如何从DLL的导出函数获取std :: string?

I want to load a custom DLL (C++ one) and call a function that it exports ? Here is my Go code:

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
}

Here the C++ code of my DLL:

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

I tried to force the use of __stdcall (and link a .def file for this, as I thought that maybe __declspec(dllexport) could be a problem ).

However, using DUMPBIN, I can see that getHello uses __cdecl calling convention. Is it a problem?

And here is the error I get when I run my 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

The getHello function is actually well executed. I modified it to write to a file:

 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));
}

...and the file is written to. So the problem is at after the exported function returns. Which makes me think I need to change something in the Go part to "welcome" the returned std::string.

EDIT2

If I change the return type of the exported function to void then, the Call return without exception. Could it be an additional hint that it's indeed related to the calling convention ?

donkey199024
donkey199024 Go不能直接处理str::string,您应该使用C方式(缓冲区和缓冲区大小)在DLL空间和Go程序空间之间传递字符串。字符串所有者是Go程序,DLL只是将返回值复制到调用方创建的缓冲区中。
一年多之前 回复
dongzhan1948
dongzhan1948 请提供一个工作示例。
一年多之前 回复

1个回答



这是我从地鼠那里得到的答案:</ p>


对象是棘手的。 字符串是一个对象,它可能在某处有一个
vtable,它也具有一个内部结构(尽管我忘记了
它是什么,我想这可能类似于COM bstring或go
slice,也许检查一下 相关的c ++来源)。 调用方法将涉及
查找分配表整体的地址,并将其作为函数进行调用。 我建议您以C char *开头,然后按自己的方式进行操作。</ p>
</ blockquote>

所以我尝试将char **作为参数,我可以进行修改 它在DLL函数中并在Go中显示修改。 我还尝试返回一个基本类型(int),它也起作用。</ p>
</ div>

展开原文

原文

Here is the answer I got from a gopher:

working with objects is tricky. string is an object, it probably has a vtable somewhere, it also has an internal structure (although I forget what it is, my guess would be it's similar to a COM bstring or a go slice, maybe check the relevant c++ sources). Calling methods would involve finding the address of the dispatch table entires and calling those as functions. I suggest you start with a C char * and work your way to that.

So I tried by taking a char ** as argument , I could modify it in the DLL function and display the modification in Go. I also tried returning a basic type (int) and it worked also.

douchuitang0642
douchuitang0642 是的,我同意这一点,这不是我的话。 但是这里重要的是它不是相同的内部结构(在std:string和char数组之间),这是导致问题的原因。
一年多之前 回复
donglangtun1850
donglangtun1850 std :: string尽管由于大多数实现上的小字符串优化而具有有趣的内部结构(写复制时通常在C ++ 11之前被发现),但它与vtables等无关。
一年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐