在C ++中加载DLL

时间:2018-05-31 03:38:37

标签: c++ dll

我试图以LoadLibrary方式加载DLL。这是我的DLL的.h文件:

#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)    
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif

typedef int(CALLBACK *p)(char*);  

extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);     

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); 

它有两个功能。 StrToInt将输入char*转换为int。另一个是NumCompare,其中StrToInt被调用,其返回值与另一个输入int进行比较,然后NumCompare重新比较比较结果。这两个函数将导出到名为callbacktestDLL.dll的<。}}。

现在我想以LoadLibrary方式调用此DLL。 (pragma comment(lib,"callbacktestDLL")方式已经成功测试,所以我想以另一种方式测试)。

为了调用DLL函数,这就是我在CallDLL.cpp中所做的:

#include "stdafx.h"
#include <iostream>
#include <windows.h>

typedef int (*P_to_Func1)(char*);       //pointer for StrToInt

typedef char* (*P_to_Func2)(P_to_Func1, char*, int);        //pointer for NumCompare


int main()
{
    //load DLL:
    HINSTANCE LDLL = LoadLibrary("callbacktestDLL.dll");

    if (LDLL == NULL)
    {
        printf("DLL loading failed");
        FreeLibrary(LDLL);
    }
    else
    {
        P_to_Func1 p1 = (P_to_Func1)GetProcAddress(LDLL, "_StrToInt@4");

        if (p1 = NULL)
        {
            printf("StrToInt loading failed");
        };

        P_to_Func2 p2 = (P_to_Func2)GetProcAddress(LDLL, "_NumCompare@12");
        if (p2 = NULL)
        {
            printf("NumCompare loading failed");
        };

        //Call StrToInt:
        std::cout << p1("1234") << std::endl;
        //call NumCompare:
        p2(p1, "1234", 20);
        //release:
        FreeLibrary(LDLL);
    };
    return 0;
}

这些功能&#39;显示的名称取决于: enter image description here

当我生成CallDLL项目时,没有错误并且已成功生成。但是,当我运行项目时,会跳出一个对话框并说CallDLL.exe has stoppedcmd窗口显示&#34;按任意键继续&#34;。有人能帮助我理解并解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

调用约定非常重要,因为GetProcAddress适用于导出表,所以没有类型信息,编译器也无法识别您的错误。

Visual C ++的默认调用约定(__cdecl)和__stdcall之间的区别在于参数传递顺序以及谁负责恢复堆栈指针。 __cdecl首先将最后一个参数压入堆栈,并让调用者从堆栈中删除参数。这些选择使“varargs”起作用。对于__stdcall,首先推送第一个参数,并且调用的函数在返回时删除参数。这种选择效率更高。

当你有一个不匹配时,二进制数据被插入错误的参数,然后堆栈指针调整错误(在你的情况下,它被调整两次,但根本没有调整也是可能的)。堆栈指针的这种双重调整会在从p1("1234")的调用返回时使程序崩溃。如果您首先调用了p2(p1, "1234", 20),那么将20误解为函数指针会使程序崩溃......如果它奇迹般地存活了(决定不调用回调函数),那么当p2堆栈不匹配时{1}}返回会导致崩溃。

密切关注调用约定,你可以避免这种痛苦。

相关问题