登录
首页 >  Golang >  Go问答

如何在 DLL 导出函数中访问 std::string?

来源:stackoverflow

时间:2024-03-16 09:12:29 320浏览 收藏

如何从 Go 代码中访问 DLL 导出的 `std::string` 函数?使用 `__cdecl` 调用约定时,返回 `std::string` 会导致异常,但返回基本类型则正常。这表明问题与调用约定有关,处理 `std::string` 等对象需要额外的步骤。解决方案是使用基本类型或使用 `char **` 指针传递和修改字符串。

问题内容

我想加载一个自定义 dll(c++ dll)并调用它导出的函数? 这是我的 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
}

这是我的 dll 的 c++ 代码:

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

编辑

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。

编辑2

如果我将导出函数的返回类型更改为void,则调用将毫无异常地返回。这是否是一个额外的提示,表明它确实与调用约定有关?


解决方案


这是我从地鼠那里得到的答案:

处理对象是很棘手的。 string 是一个对象,它可能有一个 vtable在某处,它也有一个内部结构(虽然我忘记了 它是什么,我猜它类似于 COM bstring 或 go slice,也许检查相关的 c++ 源代码)。调用方法会 涉及查找调度表整体的地址并调用 那些作为函数。我建议你从 C char * 开始,然后工作 就这样。

所以我尝试使用 char ** 作为参数,我可以在 DLL 函数中修改它并在 Go 中显示修改。我还尝试返回基本类型(int)并且它也有效。

到这里,我们也就讲完了《如何在 DLL 导出函数中访问 std::string?》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>