Saya ada projek di tempat kerja Program utama ditulis dalam Golang, dan terdapat juga perpustakaan kongsi yang ditulis dalam C# .Net AOT.
Projek ini memerlukan fungsi panggilan antara kod Golang dan C# .Net AOT.
Kandungan khusus adalah untuk menghantar fungsi Golang sebagai fungsi panggil balik kepada C# dan memanggilnya dalam C#. Tetapi apabila saya mengujinya, saya mendapati bahawa ciri itu tidak berfungsi dengan betul.
Ini kod ujian saya:
Dalam 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; } } }
Arahan kompilasi:
dotnet 发布 -p:NativeLib=共享 -r win-x64 -c 调试
Kod pergi:
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) }
Saya melaksanakan fungsi Tambah(int a, int b) mudah untuk ujian. Parameter input adalah 1 dan 2, hasilnya harus 3, tetapi tidak. Apabila saya menyahpepijat, saya mendapati bahawa senarai parameter fungsi panggil balik bukanlah 1 dan 2, tetapi beberapa nombor pelik. Saya mencuba kedua-dua konvensyen panggilan, Stdcall dan Cdecl, tetapi mereka tidak dapat menyelesaikan masalah itu.
Apakah punca dan cara mengatasinya?
Nyahpepijat
Ini ialah log keluaran lengkap
<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>
Anda perlu menggunakan cgo untuk mengeksport fungsi 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: %v\n", 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) }
Keluaran ialah:
Atas ialah kandungan terperinci Bagaimana untuk menetapkan fungsi golang sebagai fungsi panggil balik .net aot. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!