Как создать функцию Go dll, которая принимает структуру go или интерфейс в качестве аргумента

#c #go #dll

#c #Вперед #dll

Вопрос:

Я работаю с go и dll, и мне нужно создать go dll, которая экспортирует функцию, которая принимает структуру go.

 //test.go
package main

import "fmt"

//export TestFunc
func TestFunc(s TestStruct) {
  fmt.Println(s.a)
}

func main() {}
  
 //teststruct.go
package main

type TestStruct struct {
  a int
}
  

и строить с

 go build -buildmode=c-shared -o test.dll .test.go .teststruct.go
  

Я получаю идеальный DLL-файл.
Теперь, когда я использую этот код Go для его вызова

 //testcall.go
package main

import (
    "log"
    "syscall"
    "unsafe"
)

func main() {
    l, e := syscall.LoadLibrary("test.dll")

    if e != nil {
        log.Fatal(e)
    }

    p, e := syscall.GetProcAddress(l, "TestFunc")

    if e != nil {
        log.Fatal(e)
    }

    _, _, _ = syscall.Syscall(p, 1, uintptr(unsafe.Pointer(amp;TestStruct{
        a: 1002,
    })), 0, 0)
}
  

и запустить с

 go run .testcall.go .teststruct.go
  

Я получаю фатальную ошибку:

Не удалось найти указанную процедуру.

Когда я делаю то же самое на C, это работает нормально:

 //test.c

#include <stdio.h>
#include "struct.h"

__declspec(dllexport) void TestFunc(struct TestStruct s) {
    printf("%dn", s.a);
}
  
 //testcall.c

#include <windows.h>
#include "struct.h"

int main() {
    HINSTANCE l = LoadLibrary("test.dll");
    FARPROC p = GetProcAddress(l, "TestFunc");
    struct TestStruct s;
    s.a = 1002;
    p(s);
}
  
 //teststruct.h

struct TestStruct {
    int a;
};
  

и строить с:

 gcc -c test.c
gcc -shared -o test.dll test.o
gcc .testcall.c
  

Я не получаю никаких ошибок, и это дает мне

1002

Кроме того, если я использую import "C" в своем файле test.go, это даст мне

нераспознанный тип Go TestStruct

и это должно произойти, потому что C не знает, что это за тип. Итак, есть ли какой-либо способ использовать структуру go в качестве параметра и почему это выдает мне procedure not found ошибку?

Комментарии:

1. Какой оператор завершается ошибкой? Также обратите внимание, что ваша функция принимает свой аргумент по значению, но при вызове вы передаете указатель.

2. syscall.GetProcAddress сбой. (Я поставил фиктивный оператор печати для проверки)

3. Я также тестировал, принимая a *TestStruct вместо TestStruct параметра, но это также не удается.

4. Вы не импортируете «C», поэтому он не создает экспорт. Вы не можете экспортировать тип Go, потому что интерфейс — это C, а не Go.

5. Единственный способ взаимодействовать с общим объектом — через его C api, поэтому в этом контексте нет такого понятия, как «тип go».