6

使用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());
    }
}

此方法失败,因为异常没有正确传播并导致0x20474343SEH 异常。似乎有一个相关的 GCC 错误应该修复,但至少使用 MinGW-w64 g++ 4.9.2 这仍然失败(这是可用的最新版本)

4

0 回答 0