C ++:显式DLL加载:非“extern C”函数的第一次机会异常

时间:2010-05-31 02:41:26

标签: exception visual-c++ dll

我在导入C ++函数时遇到问题。如果我将它们声明为C函数,我可以成功导入它们。当显式加载时,如果任何函数缺少extern作为C装饰,我会得到以下异常:

First-chance exception at 0x00000000 in cpp.exe: 0xC0000005: Access violation.

DLL.h:

extern "C" __declspec(dllimport) int addC(int a, int b);
__declspec(dllimport) int addCpp(int a, int b);

DLL.cpp:

#include "DLL.h"
int addC(int a, int b) {
    return a + b;
}
int addCpp(int a, int b) {
    return a + b;
}

main.cpp中:

#include "..DLL/DLL.h"
#include <stdio.h>
#include <windows.h>

int main() {
    int a = 2;
    int b = 1;
    typedef int (*PFNaddC)(int,int);
    typedef int (*PFNaddCpp)(int,int);

    HMODULE hDLL = LoadLibrary(TEXT("../Debug/DLL.dll"));

    if (hDLL != NULL)
    {
        PFNaddC pfnAddC = (PFNaddC)GetProcAddress(hDLL, "addC");
        PFNaddCpp pfnAddCpp = (PFNaddCpp)GetProcAddress(hDLL, "addCpp");
        printf("a=%d, b=%d\n", a,b);
        printf("pfnAddC: %d\n", pfnAddC(a,b));
        printf("pfnAddCpp: %d\n", pfnAddCpp(a,b)); //EXCEPTION ON THIS LINE

    }
    getchar();
    return 0;
}

如何导入动态加载的c ++函数?我发现以下代码通过引用* .lib来隐式加载,但我想了解动态加载。

提前谢谢大家。

更新 bindump / exports

1 00011109 ?addCpp@@YAHHH@Z = @ILT+260(?addCpp@@YAHHH@Z)
2 00011136 addC = @ILT+305(_addC)

解决方案

  1. 创建转化结构 找到here
  2. 看一下 文件导出和显式复制 c ++ mangle命名约定。

    PFNaddCpp pfnAddCpp =(PFNaddCpp)GetProcAddress(hDLL,“?addCpp @@ YAHHH @ Z”);

2 个答案:

答案 0 :(得分:1)

不可避免地,空指针上的访问冲突是因为GetProcAddress()在出错时返回null。

问题是编译器的C ++名称是mangled,以适应各种C ++特性(名称空间,类和重载等)。因此,您的函数addCpp()在结果库中并未真正命名为addCpp()。当您使用extern "C"声明函数时,您放弃了重载以及将函数放在命名空间中的选项,但作为回报,您将得到一个名称不受损坏的函数,您可以从C代码调用该函数(对名称损坏一无所知。)

解决此问题的一个方法是export the functions using a .def file重命名导出的函数。有一篇文章Explicitly Linking to Classes in DLLs描述了执行此操作所必需的内容。

答案 1 :(得分:0)

可以将整个头文件包装在extern "C"中,如下所示。然后,您无需担心忘记其中一个声明的extern "C"

#ifdef __cplusplus
extern "C" {
#endif

__declspec(dllimport) int addC(int a, int b);
__declspec(dllimport) int addCpp(int a, int b);

#ifdef __cplusplus
} /* extern "C" */
#endif

你仍然可以使用你在函数体中习惯的所有C ++特性 - 这些函数仍然是C ++函数 - 它们只是对原型有限制,使它们与C代码兼容。