In-Process拡張機能の実装に関するガイダンス
インプロセス拡張機能は、それらをトリガーするすべてのプロセスに読み込まれます。 たとえば、シェル名前空間拡張機能は、シェル名前空間に直接または間接的にアクセスする任意のプロセスに読み込むことができます。 シェル名前空間は、共通ファイル ダイアログの表示、関連するアプリケーションを介したドキュメントの起動、ファイルを表すために使用されるアイコンの取得など、多くのシェル操作で使用されます。 インプロセス拡張機能は任意のプロセスに読み込むことができるため、ホスト アプリケーションやその他のインプロセス拡張機能に悪影響を及ぼさないことを注意する必要があります。
特に注意すべきランタイムの 1 つは、マネージ コードまたは.NET Frameworkとも呼ばれる共通言語ランタイム (CLR) です。 Microsoft では、マネージド インプロセス拡張機能を Windows エクスプローラー または Windows インターネット エクスプローラーに書き込むのを推奨しており、サポートされているシナリオとは見なされません。
このトピックでは、CLR 以外のランタイムがインプロセス拡張機能による使用に適しているかどうかを判断する際に考慮すべき要素について説明します。 その他のランタイムの例としては、Java、Visual Basic、JavaScript/ECMAScript、Delphi、C/C++ ランタイム ライブラリなどがあります。 また、このトピックでは、マネージド コードがインプロセス拡張機能でサポートされていないいくつかの理由についても説明します。
バージョンの競合
バージョンの競合は、1 つのプロセス内で複数のランタイム バージョンの読み込みをサポートしていないランタイムによって発生する可能性があります。 バージョン 4.0 より前の CLR のバージョンは、このカテゴリに分類されます。 あるバージョンのランタイムを読み込むと、同じランタイムの他のバージョンの読み込みが妨げる場合、ホスト アプリケーションまたは別のインプロセス拡張機能で競合するバージョンが使用されている場合、競合が発生する可能性があります。 バージョンが別のインプロセス拡張機能と競合する場合、競合する拡張機能が正しく競合している必要があり、エラー モードは競合する拡張機能が読み込まれる順序によって異なるため、競合の再現が困難になる場合があります。
バージョン 4.0 より前のバージョンの CLR を使用して記述されたインプロセス拡張機能について考えてみましょう。 [ ファイルを開く ] ダイアログ ボックスを使用するコンピューター上のすべてのアプリケーションで、ダイアログのマネージド コードとその応答 CLR 依存関係がアプリケーションのプロセスに読み込まれる可能性があります。 最初に 4.0 より前のバージョンの CLR をアプリケーションのプロセスに読み込むアプリケーションまたは拡張機能では、そのプロセスで後で使用できる CLR のバージョンが制限されます。 [ 開く ] ダイアログ ボックスを含むマネージド アプリケーションが競合するバージョンの CLR に基づいて構築されている場合、拡張機能が正しく実行できず、アプリケーションでエラーが発生する可能性があります。 逆に、拡張機能が最初にプロセスに読み込まれて、競合するバージョンのマネージド コードがその後に起動しようとすると (マネージド アプリケーションまたは実行中のアプリケーションが必要に応じて CLR を読み込む場合)、操作は失敗します。 ユーザーには、アプリケーションの一部の機能がランダムに動作しなくなるか、アプリケーションが不思議にクラッシュしているように見えます。
バージョン 4.0 以降の CLR のバージョンは、通常、バージョン管理の問題の影響を受けにくいことに注意してください。これは、相互に共存するように設計されており、CLR のバージョンが 4.0 より前のバージョン (他のバージョンと共存できないバージョン 1.0 を除く) を使用するように設計されているためです。 ただし、このトピックの残りの部分で説明されているように、バージョンの競合以外の問題が発生する可能性があります。
パフォーマンスの問題
パフォーマンスの問題は、プロセスに読み込まれるときにパフォーマンスが大幅に低下するランタイムで発生する可能性があります。 パフォーマンスの低下は、メモリ使用量、CPU 使用率、経過時間、またはアドレス空間の消費量の形式である可能性があります。 CLR、JavaScript/ECMAScript、Java は影響の大きいランタイムであることが知られています。 インプロセス拡張機能は多くのプロセスに読み込まれ、多くの場合、パフォーマンスに依存するタイミング (ユーザーに表示されるメニューを準備する場合など) に実行されるため、影響の大きいランタイムは全体的な応答性に悪影響を及ぼす可能性があります。
重要なリソースを消費する影響の大きいランタイムは、ホスト プロセスまたは別のインプロセス拡張機能でエラーを引き起こす可能性があります。 たとえば、ヒープに数百メガバイトのアドレス空間を消費する影響の大きいランタイムでは、ホスト アプリケーションが大きなデータセットを読み込めなくなる可能性があります。 さらに、インプロセス拡張機能は複数のプロセスに読み込むことができるため、1 つの拡張機能のリソース消費量が多い場合、システム全体で高いリソース消費量にすばやく乗算できます。
ランタイムを使用する拡張機能がアンロードされた場合でも、ランタイムが読み込まれたままであるか、それ以外の場合は引き続きリソースを消費する場合、そのランタイムは拡張機能での使用には適していません。
.NET Frameworkに固有の問題
次のセクションでは、拡張機能にマネージド コードを使用する際に見つかった問題の例について説明します。 これらは、発生する可能性のあるすべての問題の完全な一覧ではありません。 ここで説明する問題は、マネージド コードが拡張機能でサポートされない理由と、他のランタイムの使用を評価するときに考慮すべき点の両方です。
再エントランシー
たとえば、Monitor.Enter、WaitHandle.WaitOne、または contended lock ステートメントが原因で CLR によってシングルスレッド アパートメント (STA) スレッドがブロックされると、CLR は標準構成で、待機中に入れ子になったメッセージ ループに入れ子になります。 多くの拡張メソッドではメッセージの処理が禁止されており、この予期しない予期しない再入により、再現と診断が困難な異常な動作が発生する可能性があります。
ザ マルチスレッド アパートメント
CLR は、コンポーネント オブジェクト モデル (COM) オブジェクトの ランタイム呼び出し可能ラッパー を作成します。 これらの同じランタイム呼び出し可能ラッパーは、後で、マルチスレッド アパートメント (MTA) の一部である CLR のファイナライザーによって破棄されます。 STA から MTA にプロキシを移動するにはマーシャリングが必要ですが、拡張機能で使用されるすべてのインターフェイスをマーシャリングできるわけではありません。
非決定論的オブジェクトの有効期間
CLR には、ネイティブ コードよりも弱いオブジェクトの有効期間の保証があります。 多くの拡張機能にはオブジェクトとインターフェイスに対する参照カウントの要件があり、CLR で使用されるガベージ コレクション モデルはこれらの要件を満たすことはできません。
- CLR オブジェクトが COM オブジェクトへの参照を取得した場合、ランタイム呼び出し可能ラッパーによって保持されている COM オブジェクト参照は、ランタイム呼び出し可能ラッパーがガベージ コレクションされるまで解放されません。 非決定的なリリース動作は、一部のインターフェイス コントラクトと競合する可能性があります。 たとえば、 IPersistPropertyBag::Load メソッドでは、 Load メソッドが返されるときに、オブジェクトがプロパティ バッグへの参照を保持する必要はありません。
- CLR オブジェクト参照がネイティブ コードに返された場合、ランタイム呼び出し可能ラッパーの Release の最後の呼び出しが行われたときに、ランタイム呼び出し可能ラッパーは CLR オブジェクトへの参照を放棄しますが、基になる CLR オブジェクトはガベージ コレクションされるまで最終処理されません。 非決定的なファイナライズは、一部のインターフェイス コントラクトと競合する可能性があります。 たとえば、参照カウントが 0 に低下したときに、すべてのリソースをすぐに解放するには、サムネイル ハンドラーが必要です。
マネージド コードとその他のランタイムの許容される用途
マネージド コードやその他のランタイムを使用して、アウトプロセス拡張機能を実装することは許容されます。 アウトプロセス シェル拡張機能の例を次に示します。
- プレビュー ハンドラー
- シェル\動詞\コマンド サブキーの下に登録されているコマンド ライン ベースのアクション。
- プロセス外のアクティブ化を許可するシェル拡張ポイント用に、ローカル サーバーに実装されている COM オブジェクト。
一部の拡張機能は、インプロセスまたはアウトプロセスの拡張機能として実装できます。 これらの拡張機能がインプロセス拡張機能のこれらの要件を満たしていない場合は、これらの拡張機能をアウトプロセス拡張機能として実装できます。 次の一覧は、インプロセス拡張機能またはアウトプロセス拡張機能として実装できる拡張機能の例を示しています。
- シェル\動詞\コマンド サブキーの下に登録された DelegateExecute エントリに関連付けられている IExecuteCommand。
- シェル\動詞\DropTarget サブキーの下に登録された CLSID に関連付けられている IDropTarget。
- シェル\動詞サブキーの下に登録された CommandStateHandler エントリに関連付けられている IExplorerCommandState。