GetModuleHandleとLoadLibraryの違いと使いどころ
Windows API で DLL を扱う際、GetModuleHandle と LoadLibrary は頻繁に利用される関数です。どちらも HMODULE 型のハンドルを返すことから、コードを見ただけでは違いが分かりにくいかもしれません。しかし、内部動作が大きく異なるため、誤った選択がメモリリークやアプリケーションの不安定動作につながる可能性があります。
両者の本質的な違いは、DLL をメモリに「ロードするかどうか」です。LoadLibrary は必要に応じて DLL をファイルシステムから探してロードしますが、GetModuleHandle は既にロード済みのモジュールに対してハンドルを返すだけです。この違いが参照カウントや解放処理、検索パスにまで影響を及ぼします。
現実のアプリケーションでは、フック処理、ダイアログ表示、プラグイン読み込みなど、さまざまな場面でこれらの関数が使われます。たとえばキーボードフックを実装する際には、Windowsフックの基礎で解説されているように SetWindowsHookEx と組み合わせる必要があり、どちらの関数でモジュールハンドルを取得するかで挙動が変わります。
本記事では、それぞれの関数の仕様を比較し、適切な使い分けの指針を示します。
関数と用途の位置付け
GetModuleHandle は、呼び出し元プロセスのアドレス空間に既にロードされている DLL のハンドルを取得する関数です。引数に NULL を渡すと、自プロセスのインスタンスハンドルが返されます。
一方、LoadLibrary は指定されたファイルパスに基づいて DLL を検索し、必要であればメモリにロードしてハンドルを返します。既にロードされている DLL の場合は、新たなロードは行わず参照カウントをインクリメントします。
この役割分担により、用途に応じた明確な使い分けが可能になります。
仕様の比較
両者の主な違いを以下の表にまとめます。実装前に一度確認しておくと、誤った関数選択によるバグの防止に役立ちます。
| 観点 | GetModuleHandle | LoadLibrary |
|---|---|---|
| ロード処理 | 行わない | 必要に応じて行う |
| 参照カウント | 影響なし | インクリメントする |
| 解放処理 | 不要 | FreeLibrary が必要 |
| ディスク検索 | 行わない | 検索パスに従って行う |
| 失敗時の戻り値 | NULL | NULL |
| 主な利用場面 | 自プロセスの既知モジュール | 新規 DLL のロード |
GetModuleHandle はメモリ上のモジュールの存在確認にも使えますが、LoadLibrary ほど多機能ではありません。
参照カウントと解放処理
LoadLibrary を呼び出すと、対象 DLL の参照カウントが 1 増加します。参照カウントが 0 にならない限り、その DLL はプロセスのメモリ空間に残り続けます。利用後は FreeLibrary を呼び出してカウンタを減らす必要があります。
GetModuleHandle は参照カウントに影響しません。返されたハンドルを解放する必要はなく、仮に FreeLibrary を呼ぶとメモリ上の DLL がアンロードされ、アクセス違反が発生するおそれがあります。
検索パスの違い
LoadLibrary は検索パスと呼ばれるディレクトリ群を順番に探索します。実行ファイルのディレクトリやシステムディレクトリ、Windows ディレクトリなどが含まれます。
GetModuleHandle はメモリ上のモジュールだけを探索するため、ディスク検索を行いません。検索パスに依存しないため、意図しない DLL がロードされるリスクがないという利点があります。
戻り値とエラー処理
両関数ともモジュールが見つからないときに NULL を返します。LoadLibrary の場合は GetLastError でエラーコードを取得できます。
GetModuleHandle では ERROR_MOD_NOT_FOUND が設定されます。GetLastError も確認することで、エラーの原因を正確に特定でき、デバッグ時に問題を追跡しやすくなります。
実践的な使い分け
自プロセス内のシステム DLL にアクセスするには GetModuleHandle を使います。user32 のダイアログ表示や comdlg32 のファイル選択ダイアログ実装が該当します。LoadLibrary を使うと無駄に参照カウントが増えてしまいます。実装例はファイル選択ダイアログの実装が参考になります。
新しいプラグインや拡張機能を動的にロードする場合は LoadLibrary を使用します。LoadLibraryEx を併用すれば、検索パスのセキュリティリスクを軽減できます。
使い分けの指針
状況に応じて適切な関数を選ぶための基本的な指針を以下にまとめます。
- 自プロセスのリソースやシステム DLL のハンドル取得には GetModuleHandle を使う
- 新たに DLL をロードする必要があるときだけ LoadLibrary を使う
- LoadLibrary を呼んだ後は必ず対応する FreeLibrary を呼び出す
- パフォーマンスが懸念される場面では、まず GetModuleHandle で存在を確認する
- モジュール名は拡張子を含めず、ベース名だけで指定する
これらの指針を守ることで、メモリリークや DLL の不正アンロードを回避できます。チームで開発する場合は、こうした設計指針をコーディング規約として明文化しておくと効果的です。
国際的なサービス展開を視野に入れる場合は、こうした DLL 管理の堅牢性がサービスの信頼性に直結します。オーストラリア向けのサービスを展開する際の参考として、オーストラリア市場の詳細もご覧ください。GetModuleHandle と LoadLibrary の違いは一見些細に見えますが、プログラムの安定性に直結する重要なポイントです。DLL のライフサイクルを正しく管理することは、長く安心して動作する Windows アプリケーションを実現する鍵となります。