解説インサイド .NET Framework [改訂版]第3回 アセンブリのロード
吉松 史彰 |
アセンブリへの参照の解決
user.exeが実行されると、CLRによってMainメソッドが実行される*1。Mainメソッドではまず、Utilクラスのインスタンスを作成している。
Util u = new Util();
ここでUtilというクラスの定義情報が必要になるので、CLRはそれを持っているアセンブリのロードを開始する。
*1 Mainメソッドが実行される手順は次回以降に解説する。 |
− アセンブリのロード 第1段階 −
Utilが実装されているアセンブリの識別
アセンブリをロードするためには、どのアセンブリがUtilを実装しているのかを知らなければならない。CLRはコードが現在実行されているアセンブリ(この場合はuser.exeを含むアセンブリ)のモジュールに含まれるメタデータから、そのアセンブリが参照している型の情報を探し出す。
ildasm.exeを次のように起動してuser.exeモジュールを開き、[表示]メニューから[MetaInfo]-[表示!]を選択する。
% ildasm /adv user.exe
すると、user.exeのメタデータを表示することができる。メタデータの中に、Util型に関する情報が次のように書かれている。
user.exeのメタデータにあるUtil型に関する情報(メタデータの型参照) |
これはメタデータの型参照(Type Reference)テーブルのエントリを表している。Utilという名前が確認できるので、このアセンブリは正しくUtil型を参照していることが分かる。そこで、次にCLRは、この型がどこに実装されているのかを調べる。上記のTypeRefエントリには「ResolutionScope」という属性がある。ここに書いてあるのはメタデータ・テーブルのエントリを表すトークンである。つまり、この場合はUtil型への参照を解決してくれるものが、このメタデータのどこかに“0x23000002”というトークンで収められているということである。そこで再びメタデータを探すと、次のようなエントリが見つかるだろう。
user.exeのメタデータにある、Util型が実装されているアセンブリへの参照(AssemblyRef) |
ずばり、0x23000002というトークンは、Util型が実装されているアセンブリへの参照(AssemblyRef)を指していたことが分かった。これでCLRは、Util型のインスタンスを作成するためには、次のような表示名(前回参照)のアセンブリをロードしなければならないことが分かったことになる。要するに、先ほどal.exeを使って作成したあのアセンブリだ。
util, version=1.0.0.0, culture=neutral, publickeytoken=52aa3cb48fd943e1
ちなみにこの手順は、従来のCOMではコード中にCOMの型名(IID)とコンポーネント名(CLSID)が記述されていたため、まったく不要な手順だった。同様に、Win32のDLLからエクスポートされている関数を呼び出す場合も、この手順はまったく必要なかった。
− アセンブリのロード 第2段階 −
アセンブリのプライマリ・モジュールの探索
ロードすべきアセンブリが分かったので、CLRはアセンブリの探索を開始する。この時点でCLRがターゲットにしているのは、アセンブリのプライマリ・モジュール(マニフェストが含まれるモジュール)である。
従来のCOMでは、この手順はレジストリでCLSIDをキーにして検索を行い、inprocserver32サブキーを探し出して、中に書いてある実装ファイル(DLL)のパスを取得するという方法で行われていた。Win32のDLLの場合は、ソース・コード中にファイル・パスが書いてあったので、そこから直接ファイルをロードすることができた。
だが、CLRではアセンブリの名前にはファイル名やパスが一切含まれていない。COMではレジストリにファイル・パスが書かれていたのでそこを見ればよかったが、CLRではレジストリは使わないことになっている。それではCLRはどうやってファイルへのパスを手に入れるのだろうか。
この問題を解決するに当たって、CLRは過去にさかのぼることにした。Win32のDLLのフルパスが分からなかったときは、Windowsのローダーは次の順番でディレクトリを検索し、指定されたファイル名を持つDLLを探索していた。
- アプリケーション(DLLの呼び出し元)がロードされたディレクトリ
- カレント・ディレクトリ
- システム・ディレクトリ(%Systemroot%\System32)
- 16bit・システム・ディレクトリ(%Systemroot%\System)
- Windowsディレクトリ(%Systemroot%)
- PATH環境変数に列挙されているディレクトリ
CLRはこの当時に戻ることにした。つまり探索場所を決め打ちして、それ以外の場所にはモジュールを配置できないようにしたのだ。.NET Frameworkではレジストリを使わなくてよくなった、などと宣伝されているが何のことはない、単に探す場所を決めてしまうという昔のやり方に戻っただけなのだ。
アセンブリの名前をプライマリ・モジュールのパスに解決するために、CLRは次の場所を検索する。
- DEVPATH環境変数に列挙されているディレクトリ
- グローバル・アセンブリ・キャッシュ
- アセンブリのコードベース
このうち、DEVPATH環境変数に設定されているディレクトリの検索は通常は行われない。アプリケーションの開発時に開発者が構成ファイルで検索する指定を行ったときにのみ、このディレクトリが検索対象になる。本稿ではこの設定は特に解説しないので、興味のある読者は.NET Framework SDKのドキュメントを参照してほしい。
次ページではまず、グローバル・アセンブリ・キャッシュとアセンブリのコードペースについて解説する。
INDEX | ||
解説 インサイド .NET Framework [改訂版] | ||
第3回 アセンブリのロード | ||
1.はじめにサンプル・アプリケーション | ||
2.アセンブリのロード 1〜2段階 | ||
3.GACとコードベース | ||
4.アセンブリのロード 3〜5段階 | ||
5.アセンブリの配置に関する補足とまとめ | ||
「解説:インサイド .NET Framework [改訂版]」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|