在Windows DLL

时间:2017-02-10 12:36:38

标签: c++ windows dll exception-handling

我正在用C ++编写Windows DLL。该库只有C接口,只使用标准的Windows库,它们也有C接口。因此,将所有C ++库静态链接到库中似乎是安全的,因为我在使用C接口时不依赖于C ++ ABI版本。

不幸的是,当我用-static-stdc++ -static-libgcc编译我的库时,我的库停止处理异常,当抛出一些异常时,DLL会调用其静态链接的_Unwind_RaiseException函数来中止整个应用程序。

我认为它可能是一个损坏的libgtcc.a所以我试图更新我的编译器。但结果与MinGW 4.8和MinGW 6.3相同。

请有人能够解释一下这里到底发生了什么吗?

Klasyc

2 个答案:

答案 0 :(得分:0)

您是否正在处理DLL中的所有异常?如果任何异常在具有C调用约定的函数外部“泄漏”,则会使应用程序崩溃。

我在使用静态libstdc ++的 MinGW x86_64-5.3.0-win32-seh-rt_v4-rev0 mingw32 4.8.1 dwarf2 下的C ++异常没有问题/ libgcc中。

DLL源(dll.cpp):

#include <windows.h>
#include <exception>
#include <iostream>

extern "C" {
__declspec(dllexport) int __stdcall test() {
    try {
        new int[-1];
        return 123;
    } catch (const std::exception& ex) {
        std::cerr << "Exception:" << ex.what() << std::endl;
        return 456;
    }
}
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD     fdwReason, LPVOID    lpvReserved)
{
    return TRUE;
}

申请来源(app.c):

#include <stdio.h>

#ifdef __cplusplus
extern "C"
#endif
__declspec(dllimport) int __stdcall test();

int main() {
  printf("result: %d\n", test());
  return 0;
}

编译:

g++ -O2 -static-libgcc -static-libstdc++ -shared -Wl,--out-implib=dtest.lib -s -o dtest.dll dll.cpp

g++ -O2 -static-libgcc -static-libstdc++ -L. -s -o app app.c -ldtest

输出:

Exception:std::bad_alloc
result: 456

回答您的评论“为什么我需要支持SEH的编译器?我认为SEH允许我捕获Windows异常” - 在Windows上,SEH是所有的事实上的标准异常,包括C ++异常(使用Visual C ++编译时)。 MinGW有不同的C ++异常实现(SEH,SJLJ和DWARF),但是SEH是唯一没有开销的机制,所以如果它可用,你真的应该优先于SJLJ和DWARF。

答案 1 :(得分:0)

感谢RastyX在他的回答中提供了这个简单的例子。经过一些研究后,我发现当我使用-static-libgcc编译DLL部分时应用程序崩溃,而没有这个开关的应用程序部分(两个部分都使用相同的g ++编译)。

还要感谢Ripi2提出的TDM-GCC建议。我尝试了SJLJ和DWARF-2异常处理,两者都有效。

总而言之,似乎MinGW的libgcc不喜欢每个进程多次实例化它。在我的情况下,我在DLL(静态链接)中使用一个副本,在应用程序中使用一个副本,这可能会破坏异常处理。

另一方面,TDM-GCC专注于基本库的静态链接,因为它的网页显示,因此即使没有-static-stdc++ -static-libgcc命令行开关,也会产生仅依赖于Windows库的二进制文件(这就是我想要的) 。此外,异常处理也适用于此,因此更改工具链对我来说是正确的方法。