例えば WinTab32.dll ( ペンタブレット用ライブラリ ) のように、すべての環境に入っているとは限らない DLL を使いたいとき。
何も考えずに WinTab32.lib をリンクしてしまうと、DLL が入っていない環境では
DLL が存在しない旨のメッセージが表示されて、main(), WinMain() すら呼ばれません。
これではさすがにあんまりだし、無いならないで一部機能を無効にして起動したい場合は、
一般的には LoadLibrary(), GetProcAddress() API を用いて解決します。
typedef BOOL __stdcall SetLayeredFunc( HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags ); extern SetLayeredFunc *SetLayeredWindowAttributes; HINSTANCE hDllInst = LoadLibrary("user32.dll"); if( hDllInst == NULL ){ MessageBox( "USER32.DLLが読み込めませんでした。","Error", MB_OK|MB_ICONSTOP ); } SetLayeredWindowAttributes = (SetLayeredFunc*)GetProcAddress( hDllInst, "SetLayeredWindowAttributes" ); if( SetLayeredWindowAttributes == NULL ){ FreeLibrary(hDllInst); MessageBox( "SetLayeredWindowAttributes()関数のポインタが取得できませんでした。","Error", MB_OK ); }
例えばこんな感じ。でもこれだとグローバルで関数ポインタ型と関数ポインタを持つ必要があったり、
明示的に LoadLibrary(), FreeLibrary() する必要があって面倒です。
そこで、link.exe にある /DelayLoad スイッチを使います。
使い方はリンカオプションに「/DelayLoad:WinTab32.dll」のように書き足すだけ。
んで、実際にロードしたり読み込みエラーを検出するためにこんなコードをどこかに仕込みます。
#include <delayimp.h> struct dllload_error : public runtime_error { dllload_error() : runtime_error( "DLLLOAD_ERROR" ) { } }; // エラーフックハンドラ FARPROC WINAPI hookDLLLoad( unsigned dliNotify, PDelayLoadInfo pdli ) { throw dllload_error(); }; extern PfnDliHook __pfnDliFailureHook2 = hookDLLLoad; // 起動時にロードを仕掛けておく class CWinTab32Loader { public: CWinTab32Loader() { try { HRESULT hr = __HrLoadAllImportsForDll( "WINTAB32.dll" ); bLoadSuccess = !FAILED( hr ); if( bLoadSuccess ) { _RPTF0( _CRT_WARN, _T("DynamicLink: WinTab32.dll success.") ); } } catch( dllload_error& ) { bLoadSuccess = false; } } inline bool IsSuccess() { return bLoadSuccess; } private: bool bLoadSuccess; } WinTab32Loader;
それ以外は通常通り、#include
WinTab32.lib も一緒にリンクしたり、普通に DLL を使う場合と同じで使えます。
WinTab32.dll が存在しなくても、メイン関数が呼ばれるので
int main() { if( WinTab32Loader.IsSuccess() ) { AXIS axPressureScale; WTInfo( WTI_DEVICES, DVC_NPRESSURE, &axPressureScale ); } else { printf( "wintab32.dll not found!\n" ); } }
とこんな風に DLL 内の関数を呼び分けたり、いろいろできます。
注意点としては、__HrLoadAllImportsForDll() 関数は大文字小文字を区別することくらいでしょうか。