DEV Community

Masui Masanori
Masui Masanori

Posted on • Edited on

2

Calling Go functions from C#

Intro

This time, I will call some Go functions from C#.
To do this, I should generate a Go dll file and call it from C#.

Calling with int values

First, I will try sending an int value as an argument of a Go funtion and receiving int value from it.

[C#] CallSample.cs

using System.Runtime.InteropServices;

namespace CallDllSample;

public class CallSample
{
    [DllImport("dllsample")]
    private static extern int CallInt(int num);

    public int CallGoInt(int num)
    {
        return CallInt(num);
    }
}
Enter fullscreen mode Exit fullscreen mode

[Go] main.go

package main

import "C"

func main() { }

// publish functions by "//export ~"
//export CallInt
func CallInt(num int) int {
    return num + 3
}
Enter fullscreen mode Exit fullscreen mode

Build a dll file

go build -buildmode=c-shared -o dllsample.dll .
Enter fullscreen mode Exit fullscreen mode

Calling with string values

Because C#'s string type and Go's string type are not compatible, these codes cause an exception.

[C#] CallSample.cs

...
    [DllImport("dllsample")]
    private static extern string CallString(string text);
...
    public string CallGoString(string text)
    {
        return CallString(text);
    }
}
Enter fullscreen mode Exit fullscreen mode

[Go] main.go

...
// DON'T DO THIS
//export CallString
func CallString(text string) string {
    return fmt.Sprintf("%s World!", text)
}
Enter fullscreen mode Exit fullscreen mode

Result

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Repeat 2 times:
--------------------------------
   at CallDllSample.CallSample.CallString(System.String)
--------------------------------
   at CallDllSample.CallSample.CallGoString(System.String)
   at Program.<Main>$(System.String[])
Enter fullscreen mode Exit fullscreen mode

To resolve that, I have to use "C.char".

[C#] CallSample.cs

...
    [DllImport("dllsample")]
    private static extern IntPtr CallString(string text);
...
    public string CallGoString(string text)
    {
        var result = CallString(text);
        Console.WriteLine(result);
        return Marshal.PtrToStringAnsi(result) ?? "";
    }
}
Enter fullscreen mode Exit fullscreen mode

[Go] main.go

...
//export CallString
func CallString(text *C.char) *C.char {
    gs := C.GoString(text)
    return C.CString(fmt.Sprintf("%s World!", gs))
}
Enter fullscreen mode Exit fullscreen mode

Calling with arrays

To send int array to the Go function, I should convert it to IntPtr.
And to receive int array from the Go function, I should convert from IntPtr.

[C#] CallSample.cs

...
    public void CallGoArray()
    {
        // Convert from C# int array to IntPtr
        var nums = new int[]{ 4, 2, 5, 8 };
        IntPtr intPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)) * nums.Length);
        Marshal.Copy(nums, 0, intPtr, nums.Length);
        var pointerResult = CallArray(intPtr, nums.Length);

        // Convert from IntPtr to C# int array
        var results = new int[nums.Length];
        Marshal.Copy(pointerResult, results, 0, results.Length);

        for(var i = 0; i < results.Length; i++)
        {
            Console.WriteLine($"From Go Index: {i} Value: {results[i]}");
        }
    }
...
Enter fullscreen mode Exit fullscreen mode

[Go] main.go

...
//export CallArray
func CallArray(values *C.int, length C.int) *C.int {
    // Convert from C int array to Go int array
    cInts := (*[1 << 30]C.int)(unsafe.Pointer(values))[:length:length]

    goResults := make([]int, int(length))
    for i, v := range cInts {
        goResults[i] = int(v)
        log.Printf("From C# Index: %d Value: %d", int(i), int(v))
    }
    // Convert from Go int array to C int array
    results := C.malloc(C.size_t(length) * C.size_t(unsafe.Sizeof(uintptr(0))))
    pointerResult := (*[1 << 30]C.int)(results)
    for i := 0; i < int(length); i++ {
        pointerResult[i] = C.int(goResults[i] + 2)  
    }
    return (*C.int)(results)
}
Enter fullscreen mode Exit fullscreen mode

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs