Embedding go function inside C#

Not sure this is the right place :thinking: as I am not sure this concerns Go or C#

Anyhow, I need to embed my go application inside a large C# project.
I am able to embed most of my functions, eg:

//PrintHello :
//export PrintHello
func PrintHello(s string) {
	fmt.Println(s)

}

which then in C# I would use as follow

[DllImport("main", EntryPoint = "PrintHello")]
extern static void PrintHello(string s);

PrintHello("Go rules!!!!");

This works just fine, however I am facing problems when my go function takes as input a slice and from C# an array.
As an example

//Sum :
//export Sum
func Sum(a []int) int {
	return a[0] + a[1]
}

[DllImport("main", EntryPoint = "Sum")]
extern static int Sum(int[] array);


var numlis = new List<int>();
numlis.Add(1);
numlis.Add(5);
int[] array = numlis.ToArray();

int c = Sum(array);
Console.WriteLine("Call Go func Sum, result is " + c);

I get

The program ‘[15300] InitialConnect.exe’ has exited with code 2 (0x2).

What am I doing wrong?

This might not help, but maybe try specifying the calling convention in your DllImportAttribute:

[DllImport("main", EntryPoint = "Sum", CallingConvention=CallingConvention.Cdecl)]
extern static int Sum(int[] array);

Did you generate a .h file? If so, check its signature for your Sum function? It’s unlikely C# will generate the proper struct to represent a Go slice automatically. I once made a shared lib to be called by Python, and I had to wrap my functions that worked on slices with functions that accepted pointers and lengths as one would do in C. The wrapper functions created slice headers from the pointer and length before calling the original function that accepted a slice, like this

	header := (*reflect.SliceHeader)(unsafe.Pointer(&out))
	header.Data = uintptr(unsafe.Pointer(ptr))
	header.Len = n
	header.Cap = n

Here out is the slice variable.

I just created a little test, and the .h file includes the following code:

typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
extern __declspec(dllexport) void DoubleSlice(GoSlice s);

An alternate approach could be instead of creating the slice in Go code, you could probably create the GoSlice struct in your C# code. Either way, it’s not going to be transparent/automatic.

Not related to your import issue (which is looks like you already have help on), but you can simplify this:

var numlis = new List<int>();
numlis.Add(1);
numlis.Add(5);
int[] array = numlis.ToArray();

… to a single line:

int[] array = { 1, 5 };

There’s no need to create a list (unless you want to!).

@mje thanks for hint, this helped me solving the problem.
Indeed, I had to create a C# struct to host the go slice

extern static int Sum(GoSlice vals);

		struct GoSlice
		{
			public IntPtr data;
			public Int64 len;
			public Int64 cap;
		}

After a bit of research, and help from here
I was able to accomplish the task. This allow to pass the array to the go function as a go slice

			GCHandle h = GCHandle.Alloc(array, GCHandleType.Pinned);
			GoSlice gs = new GoSlice
			{
				data = h.AddrOfPinnedObject(),
				cap = n,
				len = n
			};
2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.