これを使用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 を使用すると、これはまだ失敗します (利用可能な最新バージョンです)。