Как установить функцию Go в качестве функции обратного вызова для .NET AOTC#

Место общения программистов C#
Ответить
Anonymous
 Как установить функцию Go в качестве функции обратного вызова для .NET AOT

Сообщение Anonymous »

У меня есть проект на работе. Основная программа написана на Go, имеется общая библиотека, написанная на C# .NET AOT.
В проекте необходимо вызывать функции между кодом Go и C# .NET AOT. .
Конкретное содержание — передать функцию Go в C# в качестве функции обратного вызова и вызвать ее в C#. Но когда я проверил, я обнаружил, что функция работает неправильно.
Вот мой тестовый код:
На C#:

Код: Выделить всё

using System.Runtime.InteropServices;

namespace CSharp_Go
{
public unsafe class Export
{
private static delegate* unmanaged[Stdcall] _addDel;
[UnmanagedCallersOnly(EntryPoint = "SetAddFunc")]
public static void SetAddFunc(delegate* unmanaged[Stdcall] addDel)
{
_addDel = addDel;
}

private static delegate* unmanaged _testFun;
[UnmanagedCallersOnly(EntryPoint = "SetTestFunc")]
public static void SetTestFunc(delegate* unmanaged 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 publish -p:NativeLib=Shared -r win-x64 -c Debug
Код Go:

Код: Выделить всё

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)
}
Для тестирования я реализовал простую функцию Add(int a, int b). Входные параметры были 1 и 2; результат должен был быть 3, но этого не произошло. Когда я занимался отладкой, я обнаружил, что в списке параметров функции обратного вызова были не 1 и 2, а какие-то странные числа. И я попробовал два соглашения о вызовах, Stdcall и Cdecl, но они не смогли решить эту проблему.
В чем причина этого и как ее решить?
Отладка
Вот полный журнал вывода:

Адрес функции: 154058886
6
va: 0xc00000e128, a: 0xc00000e130
Адрес функции: 15410016
Здравствуйте, c#
2259596893072 2260255909544 Операция завершена успешно.
в C# Test res:12144
12144 0 Операция завершена успешно.
2259596893072 15405888 Операция завершена успешно.
в C# Добавьте a:1, b:2
В C# Добавить res:31533024, a:1, b:2
31533024 0 Операция завершена успешно.


Подробнее здесь: https://stackoverflow.com/questions/774 ... to-net-aot
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»