代码之家  ›  专栏  ›  技术社区  ›  YQ.Wang

在C++中加载DLL

  •  -1
  • YQ.Wang  · 技术社区  · 8 年前

    我正在尝试加载一个dll LoadLibrary 方式。这是 .h 我的dll文件:

    #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 ,其中 stroint公司 调用,并将其返回与另一个输入进行比较 int 然后 裸体 重新返回比较结果。这两个函数被导出到一个名为 callbacktestDLL.dll .

    现在我想调用这个dll 加载 方式。(The 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;
    }
    

    以下是depends显示的函数名: enter image description here

    当我生成 CallDLL 项目,没有错误,生成成功。但是,当我运行这个项目时,会弹出一个对话框说 CallDLL.exe has stopped 和A cmd 窗口显示“按任意键继续”。有人能帮我理解并解决这个问题吗?

    1 回复  |  直到 8 年前
        1
  •  1
  •   Ben Voigt    8 年前

    调用约定非常重要,因为 GetProcAddress 使用导出表时,没有类型信息,编译器无法捕获您的错误。

    VisualC++中缺省调用约定的区别 __cdecl ) __stdcall 在参数传递顺序中,谁负责还原堆栈指针。 _ CDECL公司 首先将最后一个参数推送到堆栈上,并让调用方从堆栈中移除参数。这些选择使“varargs”起作用。用 _ stdcall公司 ,首先推送第一个参数,然后调用的函数在返回时移除参数。这个选择更有效率。

    当出现不匹配时,二进制数据将被插入错误的参数中,然后堆栈指针将被错误地调整(在您的情况下,它将被调整两次,但完全不调整也是可能的)。堆栈指针的这种双重调整在调用 p1("1234") . 如果你打过电话 p2(p1, "1234", 20) 首先,对 20 因为函数指针会使程序崩溃…如果它奇迹般地幸存下来(决定不调用回调函数),那么当 p2 返回将导致崩溃。

    密切注意召集会议,你可以避免这种痛苦。