2016-11-16 63 views
0

在这个伟大的平台上阅读和学习多年后,现在是我的第一篇文章。DLL调用约定和访问冲突

我的问题:

在C++中,我试图创建一个动态链接库(32位),将作为一个AQMP通信客户端(基于SimpleAmqpClient)。该dll文件将在第三方应用程序(32位)中使用。

在我的测试中,我在自定义可执行文件中调用dll时,一切正常。但是,当我尝试在第三方应用程序中使用DLL时,出现访问冲突错误(0x00000000)。我发现问题可能是函数调用约定。

下面介绍的几行代码可以重现错误。如果我删除mytest.dll中的__stdcall表达式,它会消失。通常我会希望代码工作,因为它在custom_test.exe和mytest.dll中使用相同的调用约定。 (旁注:第三方应用程序预计__stdcall函数,这就是为什么我依靠它)

我想了解这种行为。提前致谢!

我的设定:

  • 操作系统:Windows 7
  • 32位编译器:GCC 5.3(Cygwin的)

我的代码(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"); 
} 

我通过编译代码

  • DLL:g++ mytest.cpp -o mytest.dll -shared -std=gnu++11
  • EXE:g++ custom_test.cpp -o custom_test.exe -std=gnu++11

回答

0

的__stdcall约定也使得它的责任被调用的函数在返回时清理堆栈,而__cdecl使其成为调用者的责任。

我们无法看到第三方DLL中的实际声明,但我最初的假设是,DLL需要参数并且要么使用它认为是错误的堆栈参数,要么正在清理堆栈基于它的堆栈参数的假设,并通常与您的堆栈搞乱。

编辑 在这个例子中,我看到在32位编译时,测试函数被导出的名字是'test @ 0'。如果您将GetProcAddress更改为使用此装饰名称,它将起作用。

+0

Thx为您的答复!在我的第一篇文章中,我只想展示我的任务的全貌。错误可以通过给定的代码进行再现,而不需要任何进一步的依赖(第三方库或应用程序)。 – wolfspex

+0

更新了答案 - 请参阅编辑 –

0

现在好几个小时后,我可以再次看到清晰! Thx IanM_Matrix1的建议,所谓的名字装饰确实是重点。

我的研究后,我现在可以分享一些有用的ressources我发现: 知道一些编译器的功能名称添加不同的装饰是很重要的,在这里看到: http://wyw.dcweb.cn/stdcall.htm

考虑到这一点可以看这个页面关于Win32调用约定一般如下: http://www.unixwiz.net/techtips/win32-callconv.html

当使用gcc时,也可以通过标志-Wl,--kill-at禁用装饰。