如何在MinGW(-w64)中捕获延迟导入DLL错误(缺少dll或符号)?

时间:2015-06-08 14:31:24

标签: c++ c mingw mingw-w64 dlltool

使用dlltool -y可以为现有的.dll或.def文件创建延迟导入库。这似乎工作得很好,直到没有相应dll的系统上需要dll(正如延迟导入/加载的dll所预期的那样)。但是,我找不到有关如何捕获延迟加载期间生成的错误(缺少模块或缺少功能)的任何信息。

在MSVC上你会使用__try {} __except (...) {} SEH异常处理,但是,这在MinGW上是不可用的(我也不知道dlltool使用什么样的异常机制)。

常规try {} catch(...) {}也不起作用(应用程序崩溃的方式与没有任何异常处理的方式相同)。

GDB输出也不是特别有用:

gdb: unknown target exception 0xc06d007e at 0x7fefccfaaad

Program received signal ?, Unknown signal.
0x000007fefccfaaad in RaiseException ()
   from C:\Windows\system32\KernelBase.dll

如果我没有弄错,那么在RaiseException中发生未知异常似乎表明存在SEH异常。

因此问题是,有没有人成功处理过MinGW-W64的延迟加载以及如何?

编辑:经过一些实验,我想出了以下解决方案:

extern "C" __declspec(dllexport) void foo(int);

#include <windows.h>
#include <csetjmp>
#include <stdexcept>
#include <memory>
#include <cstdio>

thread_local auto do_handler = true;
thread_local jmp_buf env;
LONG CALLBACK handler(PEXCEPTION_POINTERS e)
{
    if(do_handler)
    {
        // this flag is necessary to prevent a recursive call to handler
        do_handler = false;
        longjmp(env, 1);
    }
    else
    {
        return EXCEPTION_CONTINUE_SEARCH;
    }
}

struct veh_remover
{
    void operator() (void * veh) const
    {
        RemoveVectoredExceptionHandler(veh);
        do_handler = true;
    }
};

int main(int, char**)
{
    #define CHECKED_DELAY(fn, ...) \
        do { \
            auto h = std::unique_ptr<void, veh_remover>(AddVectoredExceptionHandler(1, handler)); \
            if(!setjmp(env)) fn(__VA_ARGS__); \
            else throw std::runtime_error(#fn " not available"); \
        } while(0);

    try { CHECKED_DELAY(foo, 0); }
    catch(std::exception & e) { printf("%s\n", e.what()); }
}

但是,我不确定这段代码的行为是否定义得很好(毕竟我正在跳出处理程序)。它看起来也不是特别干净。

编辑2 :我尝试了另一种方法,设置__pfnDliFailureHook2

extern "C" __declspec(dllimport) void foo(int);

#include <windows.h>
#include <csetjmp>
#include <stdexcept>
#include <memory>
#include <cstdio>
#include <cassert>

#include <delayimp.h>

FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo)
{
    switch(dliNotify)
    {
        case dliFailLoadLib: throw std::runtime_error("module could not be loaded");
        case dliFailGetProc: throw std::runtime_error("could not find procedure in module");
        default: return 0;
    };
}

int main(int, char**)
{
    __pfnDliFailureHook2 = &delayHook;
    try
    {
        foo(0);
    }
    catch(std::exception & e)
    {
        printf("%s\n", e.what());
    }
}

此方法失败,因为异常未正确传播并导致0x20474343 SEH异常。似乎应该修复related GCC bug,但至少使用MinGW-w64 g ++ 4.9.2这仍然失败(这是最新的版本)

0 个答案:

没有答案