最新公告
  • 欢迎您光临码农资源网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!加入我们
  • 如何将golang函数设置为.net aot的回调函数

    如何将golang函数设置为.net aot的回调函数

    问题内容

    我工作中有一个项目,主程序是用Golang编写的,还有一个用C# .Net AOT编写的共享库。

    项目中需要Golang代码和C# .Net AOT之间调用函数。

    具体内容是将一个Golang函数作为回调函数传递给C#,并在C#中调用。但当我测试时,发现该功能无法正常使用。

    这是我的测试代码:

    在 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;
            }
        }
    }

    编译命令:
    dotnet 发布 -p:NativeLib=共享 -r win-x64 -c 调试

    Go 代码:

    package main
    
    import (
        "C"
        "fmt"
        "reflect"
        "syscall"
        "unsafe"
    )
    
    func Sum(a, b int32) int32 {
        //fmt.Printf("a:%d, b:%dn", 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: %vn", 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: %vn", 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: %vn", 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)
    }

    我实现了一个简单的 Add(int a, int b) 函数进行测试。输入参数是1和2,结果应该是3,但事实并非如此。我调试的时候发现回调函数的参数列表不是1和2,而是一些奇怪的数字。我尝试了两种调用约定,Stdcall和Cdecl,但他们无法解决这个问题。

    这是什么原因以及如何解决?

    调试

    这是完整的输出日志

    <code>
    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.
    </code>

    正确答案

    需要使用cgo导出go函数

    package main
    
    /*
    extern int sum(int, int);
    //static inline void CallMyFunction(int a, int b) {
    //    sum(a, b);
    //}
    */
    import "C"
    import (
        "fmt"
        "reflect"
        "syscall"
        "unsafe"
    )
    
    //export sum
    func sum(a, b C.int) C.int {
        res := a + b
        fmt.Println(a, "+", b , "=", res )
        return res
    }
    
    func main() {
        fmt.Println("Hello go c#")
        var input string
        fmt.Scanln(&input)
        fmt.Println(input)
    
        //C.CallMyFunction(3, 4)
    
        var aValue int32 = int32(3)
        var bValue int32 = int32(4)
        var a uintptr = uintptr(aValue)
        var b uintptr = uintptr(bValue)
    
        f := C.sum
        ptrValue := reflect.ValueOf(f)
        ptr := unsafe.Pointer(ptrValue.Pointer())
        addr := uintptr(ptr)
        fmt.Printf("Func Addr: %vn", addr)
    
        maindll := syscall.NewLazyDLL("CSharp_Go.dll")
        //maindll := syscall.NewLazyDLL("Cpp_Go.dll")
        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)
    }

    输出是:

    想要了解更多内容,请持续关注码农资源网,一起探索发现编程世界的无限可能!
    本站部分资源来源于网络,仅限用于学习和研究目的,请勿用于其他用途。
    如有侵权请发送邮件至1943759704@qq.com删除

    码农资源网 » 如何将golang函数设置为.net aot的回调函数
    • 7会员总数(位)
    • 25846资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 293稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情