在这个伟大的平台上阅读和学习多年后,我现在第一篇文章。
我的问题:
在C ++中我试图创建一个动态链接库(32位),它将作为AQMP通信客户端(基于SimpleAmqpClient)。然后,dll文件将在第三方应用程序(32位)中使用。
在我的测试中,我在自定义可执行文件中调用dll一切正常。但是当我尝试在第三方应用程序中使用dll时,我收到了访问冲突错误(0x00000000)。我发现问题可能是函数调用约定。
使用下面提供的少量代码行可以重现错误。如果我删除mytest.dll中的 __stdcall
表达式,它就会消失。通常我希望代码能够工作,因为它在custom_test.exe和mytest.dll中使用相同的调用约定。
(旁注:第三方应用程序需要一个__stdcall
函数,这就是我依赖它的原因)
我想了解这种行为。提前谢谢!
我的设置:
我的代码(custom_test.exe):
#include <stdio.h>
#include <windows.h>
int main(void) {
HINSTANCE hInstance;
hInstance=LoadLibrary("mytest.dll");
FARPROC lpfnGetProcessID = GetProcAddress(HMODULE(hInstance), "test");
// Function prototype
typedef void (__stdcall *myFunction)(void);
myFunction test;
test = myFunction(lpfnGetProcessID);
// Call Function
test();
FreeLibrary(hInstance);
}
我的代码(mytest.dll):
extern "C" __declspec(dllexport) void __stdcall test(void) {
printf("Inside Function \n");
}
我通过
编译代码g++ mytest.cpp -o mytest.dll -shared -std=gnu++11
g++ custom_test.cpp -o custom_test.exe -std=gnu++11
答案 0 :(得分:0)
__stdcall约定使被调用函数负责在返回时清理堆栈,而__cdecl使其成为调用者的责任。
我们无法在第三方DLL中看到实际的声明,但我最初的假设是DLL需要参数并且正在使用它认为是错误的堆栈参数,或正在清理堆栈基于它对堆栈参数的假设,并且通常会弄乱你的堆栈。
修改强> 在这种情况下,我看到在32位编译时,测试函数的输出名称为&#39; test @ 0&#39;。如果您更改GetProcAddress以使用此装饰名称,则它将起作用。
答案 1 :(得分:0)
好现在好几个小时后我又能看清了!谢谢IanM_Matrix1的建议,所谓的名字装饰确实是重点。
经过我的研究,我现在可以分享一些有用的资源,我发现: 重要的是要知道一些编译器为函数名称添加了不同的装饰,请参见此处: http://wyw.dcweb.cn/stdcall.htm
考虑到这一点,我们可以阅读关于Win32调用约定的这个页面: http://www.unixwiz.net/techtips/win32-callconv.html
使用gcc时,也可以通过标记-Wl,--kill-at
禁用装饰。