Как получить в Go std :: string из экспортируемой функции DLL? - PullRequest
0 голосов
/ 08 января 2019

Я хочу загрузить пользовательскую DLL (C ++ one) и вызвать функцию, которую она экспортирует? Вот мой код Go:

func main() {
    dllForGo := syscall.MustLoadDLL("dllForGo.dll")
    defer dllForGo.Release()
    getHello:= dllForGo.MustFindProc("getHello")
    r1, _, err := getHello.Call(0) // also tried with .Call() and still got the same error
}

Вот код C ++ моей DLL:

 std::string __stdcall getHello(void) {
     int a = 1;
     double b = 10;
     return ("Hello-World !!"+std::to_string(a) + std::to_string(b));
}

Я пытался принудительно использовать __stdcall (и связал для этого файл .def, так как думал, что, возможно, __declspec (dllexport) может быть проблемой).

Однако, используя DUMPBIN, я вижу, что getHello использует соглашение о вызовах __cdecl. Это проблема?

А вот ошибка, которую я получаю при запуске Go:

Exception 0xc0000005 0x1 0x10 0x7fef0591327
PC=0x7fef0591327

syscall.Syscall(0x7fef05910d0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    D:/Go/src/runtime/syscall_windows.go:172 +0xf9
syscall.(*Proc).Call(0xc00004e420, 0xc000058090, 0x1, 0x1, 0x565520, 0x21, 0x2e06a0, 0x0)
    D:/Go/src/syscall/dll_windows.go:146 +0x140
main.main()
    D:/GoLand_Projects/dllLoad/main.go:58 +0x335
rax     0x22fdb8
rbx     0x9
rcx     0x30
rdi     0x9
rsi     0x0
rbp     0x22fdd9
rsp     0x22fd60
r8      0x30303030302e3031
r9      0x7fef1220000
r10     0x22fd90
r11     0x771a1f
r12     0xa
r13     0x9
r14     0x0
r15     0x0
rip     0x7fef0591327
rflags  0x10202
cs      0x33
fs      0x53
gs      0x2b

EDIT

Функция getHello действительно хорошо выполнена. Я изменил его, чтобы записать в файл:

 std::string __stdcall  getHello(void) {
     std::ofstream outfile("D:\\test123.txt");
     outfile << "getHello working!" << std::endl;
     outfile.close();
     int a = 1;
     double b = 10;
    return ("Hello-World !!"+std::to_string(a) + std::to_string(b));
}

... и файл записывается в. Таким образом, проблема в после возврата экспортированной функции. Это заставляет меня думать, что мне нужно что-то изменить в части Go, чтобы "приветствовать" возвращенный std :: string.

EDIT2

Если я изменю тип возврата экспортируемой функции на void , то Call вернется без исключения. Может ли быть дополнительным намеком на то, что это действительно связано с соглашением о вызовах?

1 Ответ

0 голосов
/ 08 января 2019

Вот ответ, который я получил от суслика:

работать с объектами сложно. Строка является объектом, она, вероятно, имеет Vtable где-то, он также имеет внутреннюю структуру (хотя я забыл что это такое, я думаю, что это похоже на COM BSTRING или Go кусок, может быть, проверьте соответствующие источники C ++). Вызов методов вовлекать нахождение адреса таблицы отправки и вызова те, как функции. Я предлагаю вам начать с символа C * и работать над путь к этому.

Итак, я попытался взять символ ** в качестве аргумента, я мог изменить его в функции DLL и отобразить изменение в Go. Я также попытался вернуть базовый тип (int), и он также работал.

...