I have a project at work, the main program is written in Golang, and there is a shared library written in C# .Net AOT.
In the project, functions need to be called between Golang code and C# .Net AOT.
The specific content is to pass a Golang function to C# as a callback function and call it in C#. But when I tested, I found that the function didn't work properly.
Here is my test code:
in c#:
using System.Runtime.InteropServices;
namespace CSharp_Go
{
public unsafe class Export
{
private static delegate* unmanaged[Stdcall]<int, int, int> _addDel;
[UnmanagedCallersOnly(EntryPoint = "SetAddFunc")]
public static void SetAddFunc(delegate* unmanaged[Stdcall]<int, int, int> addDel)
{
_addDel = addDel;
}
private static delegate* unmanaged<int> _testFun;
[UnmanagedCallersOnly(EntryPoint = "SetTestFunc")]
public static void SetTestFunc(delegate* unmanaged<int> testFun)
{
_testFun = testFun;
}
[UnmanagedCallersOnly(EntryPoint = "Test")]
public static int Test()
{
int res = _testFun();
Console.WriteLine($"in c# Test res:{res}");
return res;
}
[UnmanagedCallersOnly(EntryPoint = "Add")]
public static int Add(int a, int b)
{
Console.WriteLine($"in c# Add a:{a}, b:{b}");
int res = 0;
if (null != _addDel)
{
res = _addDel(a, b);
Console.WriteLine($"in c# Add res:{res}, a:{a}, b:{b}");
}
return res;
}
}
}
Compilation command:
dotnet publish -p:NativeLib=Shared -r win-x64 -c Debug
the Go code:
package main
import (
"C"
"fmt"
"reflect"
"syscall"
"unsafe"
)
func Sum(a, b int32) int32 {
//fmt.Printf("a:%d, b:%d\n", a, b)
res := a + b
return res
}
func main() {
f := Sum
ptrValue := reflect.ValueOf(f)
ptr := unsafe.Pointer(ptrValue.Pointer())
addr := uintptr(ptr)
fmt.Printf("Func Addr: %v\n", addr)
var input string
fmt.Scanln(&input)
fmt.Println(input)
var aValue int32 = int32(1)
var bValue int32 = int32(2)
var a uintptr = uintptr(aValue)
var b uintptr = uintptr(bValue)
ptrVa := &aValue
ptrA := &a
fmt.Printf("va:%v, a: %v\n", ptrVa, ptrA)
t := func() int32 {
//fmt.Println(aValue, bValue)
//pa := (*int32)(unsafe.Pointer(uintptr(aValue)))
//a := *pa
return aValue + bValue
}
ptrT := uintptr(unsafe.Pointer(reflect.ValueOf(t).Pointer()))
fmt.Printf("Func Addr: %v\n", ptrT)
fmt.Println("Hello go c#")
maindll := syscall.NewLazyDLL("CSharp_Go.dll")
setTestFunc := maindll.NewProc("SetTestFunc")
test := maindll.NewProc("Test")
//cb := syscall.NewCallback(t)
r1, r2, err := setTestFunc.Call(ptrT)
fmt.Println(r1, r2, err)
r1, r2, err = test.Call()
fmt.Println(r1, r2, err)
setAddFunc := maindll.NewProc("SetAddFunc")
add := maindll.NewProc("Add")
r1, r2, err = setAddFunc.Call(addr)
fmt.Println(r1, r2, err)
r1, r2, err = add.Call(a, b)
fmt.Println(r1, r2, err)
fmt.Scanln(&input)
fmt.Println(input)
}
I implemented a simple Add(int a, int b) function for testing. The input parameters were 1 and 2, the result should be 3 but it was not. When I was debugging, I found that the parameter list of the callback function was not 1 and 2, but some strange numbers. And I tried two calling conventions, Stdcall and Cdecl, but they couldn't solve this problem.
What is the reason for this and how to solve it?
Here is the full output log
Func Addr: 15405888
6
6
va:0xc00000e128, a: 0xc00000e130
Func Addr: 15410016
Hello go c#
2259596893072 2260255909544 The operation completed successfully.
in c# Test res:12144
12144 0 The operation completed successfully.
2259596893072 15405888 The operation completed successfully.
in c# Add a:1, b:2
in c# Add res:31533024, a:1, b:2
31533024 0 The operation completed successfully.
It needs to use cgo to export the go function
the output is: