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

0x20474343例外が適切に伝達されず、 SEH 例外が発生するため、このアプローチは失敗します。修正する必要がある関連する GCC バグがあるようですが、少なくとも MinGW-w64 g++ 4.9.2 を使用すると、これはまだ失敗します (利用可能な最新バージョンです)。

4

0 に答える 0