I've been trying to make interop calls from C# to a function in a go lib, that returns a struct. If I understand correct you have to use CGO in go to be able to return more advanced data types.
I have successfully made calls on methods that returns a string, methods that return structs looks harder solve.
Added some sample code below. The output tells that there are some marshaling problems.
Any suggestions? Thanks!
Output:
[go] Inspect
[go] main._Ctype_struct_foobar
[go] 0 : {A main._Ctype_long 0 [0] false} , 0
[go] 1 : {B *main._Ctype_char 8 [1] false} , 8
[C#] GetStruct
System.Runtime.InteropServices.MarshalDirectiveException: Cannot marshal 'return value': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).
at pinpoint.Program.GetStruct()
at pinpoint.Program.Main(String[] args) in /home/me/examples/pinpoint/Program.cs:line 14
Build/Run:
> env GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o golib.so -buildmode=c-shared golib.go
> dotnet run
The GO code:
package main
/*
#include <stdint.h>
struct foobar {
int64_t A;
char* B;
};
*/
import "C"
import (
"fmt"
"reflect"
)
//export Inspect
func Inspect() {
fmt.Println("[go] Inspect")
var foo = C.struct_foobar{}
t := reflect.TypeOf(foo)
fmt.Println("[go] ", t)
for i := 0; i < t.NumField(); i++ {
fmt.Println("[go] ", i, ":", t.Field(i), ",", t.Field(i).Offset)
}
}
//export GetStruct
func GetStruct(id string) *C.struct_foobar {
fmt.Println("[go] GetStruct")
var A int64 = 34
var B string = "AB"
var foo = C.struct_foobar{}
foo.A = C.int64_t(A)
foo.B = C.CString(B)
return &foo
}
func main() {}
The C# code:
using System;
using System.Runtime.InteropServices;
namespace pinpoint
{
class Program
{
static void Main(string[] args)
{
try {
Inspect();
Console.WriteLine("[C#] GetStruct");
var ptr = GetStruct();
Console.WriteLine("[C#] Do marshal");
var foo = (Foo) Marshal.PtrToStructure(ptr, typeof(Foo));
Console.WriteLine($"[C#] foo = {foo}");
// FreeMem()
} catch (Exception e) {
Console.WriteLine(e);
}
}
// C type struct { int64_t A; char* B; }
[StructLayout(LayoutKind.Sequential)]
public struct Foo {
[MarshalAs(UnmanagedType.I8)]
public Int64 A;
[MarshalAs(UnmanagedType.LPTStr)]
public string B;
}
[DllImport("./golib.so", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern void Inspect();
[DllImport("./golib.so", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.LPStruct)]
public static extern IntPtr GetStruct();
}
}