戻る ホーム 上へ 進む

MainInstance と HInstance の違いは?

Tip

Tip 独自に作成したカーソルを使いたい で説明しましたように、カーソルリソースやアイコンリソースなどを実行ファイルに $R 指令でリンクした場合、リソースを読み込むにはインスタンスハンドルなるものが必要になります。

VCL には2種類のインスタンスハンドルを保持するグローバル変数があります。MainInstanceHInstance です。どちらを使うべきなのでしょうか?

たいていは MainInstance でよいのですが、DLL やパッケージを使う場合はちょっと話が違ってきます。

実行ファイル(EXE) の中で実行ファイル(EXE)にリンクされたリソースを使う場合は、MainInstance を使います。
DLLやパッケージの中で、DLLやパッケージにリンクされたリソースを使う場合は HInstance を使います。
DLLやパッケージの中で、実行ファイル(EXE)にリンクされたリソースを使うときはMainInstance を使います。但し、EXEがパッケージを使っていない場合や、使っていてもDLLがパッケージを使っていない場合は、DLLの中で MainInstance は使えません。実行ファイル(EXE)からDLLへMainInstance を通知してもらう必要があります。

解説

アプリケーションは一般に、実行ファイル(EXE)、DLL、パッケージから構成されますが、これらはモジュールと呼ばれます。インスタンスハンドルはモジュール固有のもので、モジュール毎に異なる値になります。

パッケージは DLL の一種ですが、ここでは区別することにします。ここでいう DLL とはパッケージではない、DLL のことです

つまり EXE, DLL, パッケージはそれぞれ異なるインスタンスハンドルを持つわけです。リソースはモジュールにリンクされるので、リソースをロードするには正しいインスタンスハンドルを指定する必要があります。

MainInstance は System ユニットに、HInstance は SysInit ユニットで宣言されているグローバル変数です。これはともにインスタンスハンドルを保持していますが、

MainInstance: 実行ファイル(EXE)のインスタンスハンドル
HInstance: モジュールのインスタンスハンドル

になっています。つまり HInstanceりソースをロードしようとしているコードが属するモジュールのインスタンスハンドルを保持しているわけです。

VCLのSystemユニットとSysInitユニットはともにUses節で指定しなくとも自動的に使われるユニットですが、その性質はパッケージを使うと大きな違ってきます。

System ユニットはパッケージ VCL50.bpl(Delphi 5), VCL60.bpl(Delphi6)に含まれ、パッケージを使う全てのモジュールは Systemユニット内のコードとデータを共有します。一方 SysInit ユニット は必ず各モジュールに個別にリンクされ共有されません

パッケージを使うと MainInstance はパッケージ VCL50.bpl/VCL60.bpl の中に有り、実行ファイル(EXE)は MainInstance を自分のインスタンスハンドルで初期化します。一方 HInstance は各モジュールが自分のインスタンスハンドルをセットします。従って

DLL がパッケージを使わない場合は MainInstance は0になる。
EXEがパッケージを使わない場合は、DLL やパッケージのMainInstance は0になりる。

ということになります。注意してください

MainInstance は Delphi 3 で導入されましたが、その理由はパッケージです。パッケージは DLL の一種で、アプリケーションを構成する一部のユニットを DLL 化するためのものです。

ユニットをEXEからパッケージに移す際、ユニットのコードに書き換えが必要になるのは好ましいことでは有りません。このため、EXEにリンクされているリソースを EXE内からでも、パッケージからでも同じようにアクセスできるように導入されたのが MainInstance なのです。

何がパッケージによって共有され、何がされないかを把握しておくことは大切です。最後にSysInit ユニットのいくつかの変数を紹介しておきましょう。

ModuleIsLib: Boolean;        : モジュールが DLL かパッケージであることを表します。ちなみに Systemユニットを IsLibrary 変数はパッケージを使うと正常に動作しません。DLL、パッケージ、EXEで共有されるのですから当然でしょう。
ModuleIsPackage: Boolean; : モジュールがパッケージであることを表します。
ModuleIsCpp: Boolean;   : モジュールが C++Builder でリンクされたことを示す。
HInstance: LongWord;       : モジュールのインスタンスハンドル
DLLProc: Pointer;            : DLLエントリポイント(これが共有されたら困ります)。

戻る ホーム 上へ 進む

inserted by FC2 system