アプリケーションで共有する Side-by-Side コンポーネントの実装 (拡張)

David D'Souza、BJ Whalen、Peter Wilson
Microsoft Corporation

November 1999

要約 : Certified for Windows アプリケーション仕様書で説明しているように、MicrosoftR WindowsR 2000 および Windows 98 Second Edition での Side-by-Side 共有コンポーネントの実装について解説します。新しい Side-by-Side コンポーネントを作成したり、DLL/COM リダイレクションを活用して、異なるバージョンでの同一コンポーネントの非互換性の問題を解決する方法について述べていきます。Side-by-Side コンポーネントの記述やインストールの手順、およびアプリケーションの再パッケージやテストについての手順を含んでいます。

内容

はじめに
簡単なバックグラウンド
新しいコンポーネント共有の方針
2 つの方法の比較
新しい Side-by-Side コンポーネントを作成する
Side-by-Side コンポーネント作成の手順
Side-by-Side コンポーネントをインストールする
DLL/COM リダイレクション
DLL/COM リダイレクションを使用する

はじめに

現代のオペレーティング システムやアプリケーションは多くのコンポーネントから構成されています。コンポーネントは独立型ソフトウェアのエンティティで、さまざまなアプリケーションで幅広く使用可能な機能を提供しています。個々のコンポーネントは複数のアプリケーションで使用されるため、コンポーネントの共有は不可欠です。

問題なく汎用的にコンポーネントを共有するためには、共有するコンポーネントの機能がその旧バージョンとまったく同じ機能を持っていなければなりません。しかし実際には、共有コンポーネントを利用している設定をすべてテストすることは困難で、新旧バージョンが 100% の互換性を持つことは不可能ではありませんが、かなり難しいことです。新旧両アプリケーションは結局のところ同じコンポーネントを共有することになり、コンポーネントを修正し改善していくことは徐々に難しくなっていきます。

同様に、コンポーネントの実際の機能を簡単に定義することはできません。アプリケーションは、コンポーネントの中心機能でない思わぬ副次的作用に左右されてしまうこともあります。たとえば、アプリケーションがコンポーネントのバグに依存している(コンポーネントのバグのおかげで正常に動作している)場合、コンポーネントの開発者がそのバグを修正すると逆にアプリケーションがエラーを起こし、"DLL Hell" と呼ばれる状態になります。単純に、各コンポーネントを使用するアプリケーションが多ければ、さらに問題は複雑になります。

旧バージョンとの互換性がないと、新しいアプリケーションをインストールする場合に、既にその機能を利用しているアプリケーションを終了させる必要があるかもしれません。新しいアプリケーションは、既にインストールされているバージョンとは異なる共有コンポーネントのバージョンを必要とします。アプリケーションの安定性を向上させながら問題なく共有するために、Microsoft では Windows 2000 および Windows 98 Second Edition に対し Side-by-Side 共有を導入し、その分離を選択可能にして新旧のコンポーネントを共有できるようにしました。

簡単なバックグラウンド

Side-by-Side 共有の詳細の前に、DLL Hell の背景にある課題および問題について確認しましょう。

コンポーネントを共有する

Windows は、開発当初から共有の概念を取り入れてきました。すべてのオペレーティング システムでは、オペレーティング システムを設計したハードウェア リソースの制約に対し、耐性のある一連のサービスを提供するという必要性からバランスを取っています。最近まで、CPU の利用とディスク スペースは PC プラットフォームにおいて非常に密接なつながりのあるリソースでした。少ないスペースにオペレーティング システムとアプリケーション コードを収める方法は、可能な限りコードを共有することでした。そのほかにも多くの利点がありますが、コードの共有を行うことにより、品質保証テストを行う必要のあるモジュールの数を最小化し、ハードウェア リソースをさらに効率的に利用することができます。コードの共有は、Windows を成功へと導いた 1 つの要因でもあります。

Windows では、共有するものをコードだけに限定していません。アプリケーションおよびコンポーネントの状態は、ファイル システム内のアプリケーション固有データの記憶域である "レジストリ"、およびグローバルな名前空間を公開する Windows API を使用することによって、オペレーティング システム全体から参照することができます。共有によって、複数のソフトウェア ベンダが作成したアプリケーションを高いレベルで共用することができ、コストを削減することでソフトウェアの効率は高まります。

ただし、共有には問題が伴います。共有するということはアプリケーションが互いに依存しあうことを意味し、アプリケーションが脆弱になる原因にもなります。1 つのコンポーネントに変更を加えると、ほかのコンポーネントに思わぬ影響を与えることもあります。一般的に、アプリケーションは共有コンポーネントの特定のバージョンに依存する可能性があります。もう一方のアプリケーションがアップグレードされた (またはダウングレードされた) バージョンの共有コンポーネントと共にインストールされた場合には、最初のアプリケーションがその影響を受けます。極端な場合には、一度正常に機能していたアプリケーションが異常な動作を始めたり、エラーを起こすことがあります。こうした状態を "DLL Hell" と呼びます。

分離

システムにおいて共有の反対は分離を意味します。すべてのリソースおよびコードをアプリケーションに静的に結合することによって、アプリケーションを分離することができます。ただし、完全に分離してしまうことは、COM やその他のグローバルに格納されているシステム リソースに依存している今日のアプリケーションにとっては適していません。

選択したアプリケーションやコンポーネントのみを分離することは、アプリケーションの易損性を少なくする 1つのソリューションです。このシナリオを使用すれば、アプリケーションすべてが同じコンポーネントにアクセスできるかもしれません。ただし、現在はさまざまなバージョンのコンポーネントが存在します。コンポーネントの作者には、古いコンポーネントを改善してバグを修正し、新しいバージョンを作り出す自由があります。一方、ユーザーは特定のアプリケーションに合ったバージョンを選択することができます。これは自動車部品の販売店で、1984 年型シボレー用の燃料ポンプを選ぶのに似ています。目的のポンプを見つけると、その隣には新型の別のモデルに合うポンプが置いてあります。コンポーネントは、各アプリケーションそれぞれに適切なバージョンを提供し、異なるバージョンを互いに分離させることが重要です。さらに、リダイレクションにおいては、他のバージョンが現在何をしていて将来的に何をするのかにかかわらず、特定のアプリケーションに合ったバージョンのコンポーネントを使用するようにアプリケーションを設定することができます。

Side-by-Side 共有

このような分離を奨励するため、Microsoft Windows 2000 および Windows 98 Second Edition には新しく Side-by-Side 共有とよばれるコンポーネントの共有機能があり、ここではDLL Hell を最小限に押さえる選択可能な分離を提供しています。Side-by-Side 共有では、同じコンポーネントの複数のバージョン (COM または Win32R) を異なるプロセス内で同時に実行することができます。アプリケーションは、別のアプリケーションが同じコンポーネントの別のバージョンを要求している場合でも、そのコンポーネントの適切な特定のバージョンを使用することができます。この取り決めにより、システム上の他のアプリケーションに関係なくアプリケーションで使用するコンポーネントのバージョンを指定することができるので、開発者はより信頼性のあるアプリケーションを開発して配布することができます。

新しいコンポーネント共有の方針

Windows 2000 および Windows 98 Second Edition における Side-by-Side 共有は、次の 2 つの方針に従っています。

  • Side-by-Side コンポーネントを作成する 開発者が、コンポーネントの複数バージョンの同時実行をサポートする新しいコンポーネントを開発します。これらの新しいコンポーネントのユーザーは、コンピュータ上にどのバージョンがインストールされているかを気にすることなく、個々のアプリケーションに適合したバージョンを使用することができます。

  • DLL/COM リダイレクションを利用する 開発者および管理者は既存のアプリケーションおよびコンポーネントの再パッケージを行い、互いに並行して機能している共有コンポーネントで必要なバージョンを適切なアプリケーションに対して専有化することができます。

Side-by-Side コンポーネントは、新しく作成されたか、再構成された既存アプリケーションの一部であるかにかかわらず、どのシナリオでもサポートされるわけではありません。

  • Side-by-Side コンポーネントの作成が最も適するシナリオは、実行中のコンポーネントが処理中に他のコンテナ アプリケーション下で動作する場合に起こります。たとえば、デスクトップの Windows アプリケーションでコントロール (Microsoft Visual BasicR または Visual C++R で作成されたもの) が使用される場合、Side-by-Side の設計にこれらのコントロールを使用するのはいいアイデアです。Side-by-Side コンポーネントをサーバーで使用することはお勧めしません。

  • DLL/COM リダイレクションの利用が最も適するシナリオは、いくつかのアプリケーションをサポートしているコンピュータに新しいクライアント アプリケーションがインストールされた場合、または新しいクライアント アプリケーションが他のアプリケーションをインストールした場合に起きる共有コンポーネントの変更に対し、より柔軟性が必要な場合に起こります。DLL/COM リダイレクションをサーバーで使用することはお勧めしません。

    メモ   DLL/COM リダイレクションは、既存アプリケーションおよびコンポーネントが展開され、アプリケーションの競合が起きた場合に対処することを目的としています。新しいアプリケーションまたはコンポーネントを開発する場合の最善の方法は、最初から本質的に分離されている Side-by-Side コンポーネントを開発することです。

2 つの方法の比較

次の表では、DLL/COM リダイレクションおよび Side-by-Side (SxS) コンポーネントを作成する 2 つのアプローチについて比較し、ユーザーのシナリオに合った適切なアプローチを選択する手順を提供しています。

表 1 アプローチの比較

比較内容 SxS コンポーネント DLL/COM リダイレクション
主な目的は? 将来的なバージョンで、"旧バージョンとの互換性がない" コンポーネントの変更に左右されない耐性のある "新しいコンポーネント" を構築します。 互換性のない共有 DLL をインストールしている他のアプリケーションによって引き起こされる問題から、"既存のアプリケーション" を救出します。
コンポーネントを使用するアプリケーションと特定のバージョンのコンポーネントを分離することが可能ですか? はい。コンポーネントを使用するアプリケーションとコンポーネントを分離しておくために、SxS コンポーネントを常に展開しておく必要があります。 はい。DLL/COM リダイレクションを使用するアプリケーションは、システム上にインストールされているバージョンに関係なく、アプリケーションに直接インストールされた共有コンポーネントのすべてのバージョンを使用します。
新しいコードまたは既存コードの変更が必要ですか? はい。SxS コンポーネントを構築する (または既存のコンポーネントを SxS に変更する) ためには、少なくとも、相対パスからアクセスできるように COM 登録コードを変更する必要があります。また、SxS の実行バージョンの間で正しくグローバルな状態を操作できるように、コード変更が必要な場合もあります。 いいえ。DLL/COM リダイレクションを使用すると、アプリケーションを再構成してインストールしたり、コード変更または再コンパイルをせずに SxS を実行することができます。これにより、管理者はソース コードにアクセスせずにアプリケーションを再構成し "DLL Hell" の問題に対処することができます。
このアプローチは考えうる全ての場合で機能しますか? はい。SxS コンポーネントは、インストールして SxS を実行させるように設計されてコード化されています。そのため、適切に設計、開発、およびテストされた SxS コンポーネント (およびそれを使用するアプリケーション) は "DLL Hell" の問題に煩わされることはありません。 いいえ。DLL/COM リダイレクションでコードを変更する必要はありません。既存のアプリケーションおよびコンポーネントは、2 つ以上のバージョンが一度に実行できるようには設計されていません。これまでの経験によると、ほとんどの場合に既存のアプリケーションおよびコンポーネントは SxS を実行しますが、テストには特定のシナリオを使用する必要があります (「分離するコンポーネントを選択する」を参照してください)。

一般的な規則

  • DLL Hell の問題によって既存のアプリケーションの利用が妨げられる場合は、DLL/COM リダイレクションを使用して、競合しているコンポーネントを分離してください (詳細については、次のシナリオを参照してください)。

  • DLL Hell の問題を未然に防ぐ新しいアプリケーションを設計して開発する場合、Side-by-Side コンポーネントを構築します。

新しい Side-by-Side コンポーネントを作成する

新しいアプリケーションで Side-by-Side 共有を行う場合、開発者は Side-by-Side コンポーネントを作成する必要があります。COM または Win32 コンポーネントが、システム ディレクトリではなくアプリケーション ディレクトリ (またはそのサブ ディレクトリ) にインストールされている場合、それらは特定のアプリケーションに対して分離されているので、すべてのアプリケーションで汎用的に共有することはできません。

そのため、別のアプリケーションに直接インストールされている同じコンポーネントの別バージョンと並行して、コンポーネントを安全にインストールすることができます。システム上のもう一方のアプリケーションに別のバージョンが必要な (そのためインストールされた) 場合でも、アプリケーションに影響はありません。両アプリケーションは、コンポーネントのそれぞれのバージョンを使用して実行されます。

別のアプリケーションがシステム上に新しいコンポーネントのバージョンをインストールした場合、コンポーネントの現在使用しているバージョンはアプリケーションに直接インストールされているので影響を受けません。アプリケーションはコンポーネントの同じバージョンを使用し続け、一方で別のアプリケーションは独自のバージョンを使用し続けます。オペレーティング システムは両バージョンを同時に読み込むことができます。

同じように、Side-by-Side コンポーネントはそれをインストールしているアプリケーションに "専有化" されており、他のアプリケーションはプライベート コンポーネントに依存できないので、アンインストーラは常にこの Side-by-Side コンポーネントを安全に削除することができます。

メモ   Side-by-Side コンポーネントはオペレーティング システム (このページの後半で説明します) に適切に登録する必要があります。それにより、存在する可能性のあるコンポーネントの他のバージョンとコンポーネントの各バージョン間は競合を起こしません。

メモ   Windows 2000 および Windows 98 Second Edition は共に Side-by-Side 共有をサポートしています。以前の Windows オペレーティング システムではサポートされていませんでした。ただし、これらのシステムに Side-by-Side DLL (次の章で説明する手順に基づいて作成された DLL) をシステム ディレクトリにインストールすることは可能です。そのため、DLL は汎用的に共有する (旧バージョンとの互換性を持たせる) ことができました。アプリケーションは動的にオペレーティング システムのバージョンをチェックして、どれを適用するかを決定する必要があります。

Side-by-Side コンポーネント作成の手順

次の手順では、Side-by-Side コンポーネント (COM または Win32) を作成する上での問題点を示しています。このようなコンポーネントを作成してアプリケーション ディレクトリに置いた場合、コードはアプリケーションのコンテキストに対して専有化されます。レジストリにあるデータをアプリケーション名により作成した場合、データはそのアプリケーションに専有化されます。

Side-by-Side コンポーネントの変更は、その変更が必要ないユーザーからは遮断されます。また、既存のアプリケーションを破損せずにコンポーネントを更新することもできます。別のアプリケーションがコンポーネントの別バージョンを使用している場合でも、再起動を行わずコンポーネントをインストールすることができます。

メモ   これらの手順は、Win32 DLL をアプリケーションに直接インストールするように指示している現在の Certified for Windows アプリケーション仕様書の手順よりも厳しくなっています。

一般的な問題

  • Windows 2000 の System File Protection によって保護されているファイルは移動しないでください。これらのファイルには、ほとんどの .sys、.dll、.exe、および .ocx ファイルが含まれます。

  • 現行のオペレーティング システムでは Side-by-Side を強制していないので、特に共有が行われる領域で Side-by-Side の妥当性を確認するために、すべてのコンポーネントをテストする必要があります。

  • バージョンを特定しているすべての名前を "#define" に集めておくと、1つのバージョンから別のバージョンへ移行を行う場合に便利です。これにより、1ヶ所でバージョンを変更することができ、すべてのレジストリ キーを自動的に変更することができます。次に例を示します。

    #define MyRegistryKey "MyAppv1.0.0.0"
    

    こうすると、コンポーネントの新しいバージョンをリリースする場合、バージョンの変更が 1 ヶ所で終わります。

  • 任意に指定されたアプリケーション ディレクトリにあるため、コンポーネントをすぐに変更できない点に注意してください。コンポーネント作成者のように、コンポーネントの修正個所がすべてはわからないかもしれません。アプリケーション ベンダは修正したコンポーネントをユーザーに配布する必要があります。

  • クロス プロセスを共有しないようにしてください。コンポーネントの異なるバージョンでセクションが共有されていないために、共有メモリ セクションでエラーが発生する可能性があります。

  • すべての共有データ構造、メモリがマップされたファイル、ミューテックス、名前付きパイプ、およびハードウェア ドライバは Side-by-Side (コンポーネントのバージョンごとに異なる) に設計する必要があります。

  • 永続データでない場合は TEMP ディレクトリに格納してください。

  • ユーザー データをグローバルな場所に置かないでください。アプリケーション データとユーザー データは明確に分ける必要があります。

コンポーネントを強化する

  • コンポーネントのインストールおよびアンインストールのグローバル レジストリで、GUID のカウントを異なるベンダごとに適切に参照する必要があります。GUID キーの下に参照カウントを保持しておくのが最も信頼できる方法です。

    HKEY_CLASSES_ROOT\CLSID\{GUID}\InprocServer32 
    Default=foo.dll 
    ThreadingModel=Apartment 
    RefCount=1 
    

    メモ   GUID とは別に、DLL の参照カウントも行う必要があります。

  • COM 登録に絶対パス名を使用しないでください。コンポーネントとその独立性を確かめるためには、アプリケーション ディレクトリのディレクトリ検索が頼りになります。

  • COM GUID の下でメタデータ (たとえばスレッディング モデル) を変更すると、コンポーネントの新しいバージョンとして有効になるため、名前を変更してコンポーネントに新しい GUID を適用する必要があります (アプリケーション内のコンポーネントのプライベート バージョンとレジストリ内のデータが別のアプリケーションのコンテキストでは有効にはならなので、この作業が必要になります)。

  • 個別のファイルではなく DLL にタイプ ライブラリを実装してください。

  • "LoadRegTypeLib" 関数を使用してレジストリからタイプ ライブラリを読み込まないでください。レジストリに格納されるタイプ ライブラリはグローバルであり、専有化の規則に基づいてカウンタを実行します。代わりに "LoadType Lib" を使用します。

  • OLEAUT で新しい外部タイプ ライブラリを作成すると、破損しやすくなり、エラーが発生しやすくなります。Side-by-Side コンポーネントでは外部タイプ ライブラリを使用しないことをお勧めします。

  • 既存のコンポーネントを Side-by-Side に変更する場合、同時にコンポーネントの相対パスを使用する起動方法が変更されて、グローバルな状態が分離されることになります。コンポーネントに新しい CLSID および ProgId を与えてファイル名を変更し、今後の Side-by-Side バージョンではこの CLSID、ProgId、および新しいファイル名を使用してください。それにより、Side-by-Side バージョンの上に Side-by-Side でないバージョンのコンポーネントが登録された場合に起こる競合を避けることができます。Side-by-Side コンポーネントは、Side-by-Side でない前バージョンとの互換性を持ちません。

状態の記憶域

  • レジストリに保存されている状態 (設定) に関して、実行されるアプリケーション コンテキストの状態を専有化する必要があります。"GetModuleFileName()" 関数を使用して、仮想ルートを設定することができます。これは HKLM および HKCU の分岐に対して行います。

  • レジストリの設定は、レジストリを分離させるためにバージョン単位で行う必要があります。通常は、レジストリ キーを使用してコンポーネントの状態を保存します。別バージョンのコンポーネントがマシン上に存在する可能性があるので、再コンパイル時にはキーにできる限り単純明快なバージョンを付けてください。適切なヘッダー ファイルやヘルパ API を使用すると、この作業は簡単になります。

  • 次の名前付け規則を使用して、レジストリの状態をキーに格納します。

    
      HKCU\MyCompany\MyComponent\VersionXXXX\
    
    

    たとえば、真 (True) または 偽 (False) という値を持つ "EnableSuperCoolFeature" という名前の構成設定があるとします。従来は、この情報を次のようにレジストリに格納していました。

    HKEY_CurrentUser\Software\MyCompany\MyComponent\
            EnableSuperCoolFeature = TRUE
    
    

    Side-by-Side 共有では、次のように格納します。

    HKEY_CurrentUser\Software\MyCompany\MyComponent\Version01.01
            EnableSuperCoolFeature = TRUE
    
    
  • 別の方法として、アプリケーションごとに分離する場合は次のようにします。

    HKCU\MyCompany\MyComponent\VersionXXYY\SomeApplication\\
    
    

    "SomeApplication" は "GetModuleFileName" の戻り値です。このようにすることにより、現在コンポーネントが実行しているアプリケーションにのみ適用される設定を分離することができます。

  • 継続的に有効なモデルをサポートすることが理想的です。それにより、アプリケーションは状態を継続してレジストリを変更しません。アプリケーションが直接コンポーネントのレジストリ項目を操作するべきではありません。その代わりに、コンポーネントは Side-by-Side と互換性のある設置を保存し復元する API を持つようにします。

  • グローバルと対話を行うためには、レジストリ以外に格納されている設定を Side-by-Side の形で格納する必要があります。このような格納には次のようなものがあります。

    • 保護された記憶域 (pstore)

    • WinInet キャッシュ

    • Microsoft SQL Server? または Microsoft Jet データベース

Side-by-Side コンポーネントをインストールする

インストールする前に

Side-by-Side コンポーネントをインストールする前に、それが目的のオペレーティング システムでサポートされているかどうかを確認する必要があります。次のコードを使用して、Side-by-Side 共有が有効かどうかを確認することができます。有効でない場合は、コンポーネントをシステム ディレクトリに直接インストールしてください。


BOOL bPlatformSupportsSideBySide(void)
{
   OSVERSIONINFOEX osviex ;

   osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

   // プラットフォームが OSVERSIONINFOEX 構造をサポートしていない場合、Side-by-Side サポートは行われません。
   // カーネルでは、提携してこれらの修正を行いました...
   //
   if (!GetVersionEx((OSVERSIONINFO *)&osviex))
   {
      return FALSE ; // DLL のリダイレクションはありません。
   }

   // NT の場合、NT4 SP4 は OSVERSIONINFOEX サポートをサポートしていますが、DLL リダイレクションはサポートしていません。
   // もし、将来的に NT4 SP において DLL リダイレクションのサポートが行われる場合、このコードをアップデートする必要があります。
   //
   if ( (osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) && 
(osviex.dwMajorVersion < 5) )
   {
      return FALSE ;
   }

   // その他のプラットフォーム ID は、Side-by-Side サポートがあるこをと想定しています。
   return TRUE ;
}

インストールとアンインストール

コンポーネントの正しいインストールおよびアンインストールは重要です。アプリケーション ディレクトリにコピーしたり、またはアプリケーション ディレクトリから削除する以外はコンポーネントのインストールおよびアンインストールを行わないことが理想的です。ただし、COM 登録やコンポーネントの初期設定が必要な場合は、Side-by-Side と互換性のある方法で行ってください。

Windows 2000 には Windows Installer 1.1 が含まれており、Side-by-Side コンポーネントのインストールおよびアンインストールをサポートしています (Windows Installerは Windows 2000 がリリースされるとオンラインでも入手することができます)。Side-by-Side COM コンポーネントを登録する場合、クラス テーブルの属性列に "msidbClassAttributesRelativePath" ビットを設定する必要があります。これは相対パスを使用してコンポーネントを登録するので、同じコンポーネントの複数のコピーを作成することができます。

アプリケーション ディレクトリのコンポーネントが専有化されている一方で、他のアプリケーションがマシン上に別のバージョンをインストールする可能性があるということを忘れないでください。このコンポーネントをインストールまたはアンインストールする場合に、それが原因で他のアプリケーションに影響を与えないようにすることが必要です。このように、自己登録のエントリ ポイントである "DLLRegisterServer"、"DLLUnregisterServer (COM コンポーネント用)"、または "DllInstall (Win32 または COM コンポーネント用)" を介してコンポーネントが正しくインストールされるかどうかは、作業を行う担当者にかかっています。これらの機能の詳細については、Platform SDK の「Register Server (英語)」を参照してください。

コンポーネントをアプリケーション ディレクトリに正しくインストールするためには、通常の処理に次のステップを追加してください。

  1. 相対パス名を使用して GUID を登録します。

  2. GUID の参照カウントを行います。
    これにより、GUID が何度インストールまたはアンインストールされたかを確認することができます。

  3. GUID が存在する場合は、参照カウントを増加させます。
    または
    GUID がない場合は、GUID を追加して参照カウントを 1 にします。次に例を示します。

    
      {00000109-0000-0010-8000-00AA006D2EA4}
    \InprocServer32
    Default = "mycomponent.dll"
    ReferenceCount=1
    

    メモ   タイプ ライブラリは DLL に格納し、システム レジストリには登録しないでください。

アプリケーション ディレクトリのコンポーネントを正しくアンインストールするためには、通常の処理に次のステップを追加してください。

  • 参照カウントを減少させます。カウントが 0 になったら、他にユーザーがいないので GUID を削除することができます。カウントが 1 以上の場合は、別にアプリケーションがインストールされていてそのアプリケーションがレジストリの状態に依存していることを意味します。

DLL/COM リダイレクション

アプリケーションがインストールされた場合、DLL/COM リダイレクションには実行可能なアプリケーションが必要です。また、分離されたすべてのコンポーネントをシステム ディレクトリではなくアプリケーション ディレクトリにインストールする必要があります。さらに、Windows のバインディング処理を変更するために ".local" ファイルがアプリケーション ディレクトリにインストールされるので、アプリケーションはグローバルで共有されているバージョンではなく、分離されたコンポーネントと関連付けられます。

そのためアプリケーションは、別のアプリケーション ディレクトリやシステム ディレクトリにインストールされている同じコンポーネントの異なるバージョンと並行して安全に実行されているコンポーネントを使用することができます。システム上の別のアプリケーションが異なるバージョンを必要とする場合でも、アプリケーションに影響はありません。両アプリケーションは、コンポーネントのそれぞれのバージョンを使用して実行されます。

別のアプリケーションがシステム上に新しいコンポーネントのバージョンをインストールした場合、アプリケーションに直接インストールされているコンポーネントのバージョンは影響を受けません。アプリケーションはコンポーネントの同じバージョンを使用し続け、別のアプリケーションは独自のバージョンを使用します。オペレーティング システムは、メモリ内の両バージョンを同時に読み込むことができます。

メモ   他のコンポーネントのバージョンと競合を起こさないように、分離された COM コンポーネントをオペレーティング システムに正しく登録する必要があります。この登録では、コンポーネントの実装をバージョン間で変更することができますが、CLSID、ProgID、Type Library、およびスレッド モデルといった登録 COM メタデータをバージョン間で変更することはできません。

メモ   Windows 2000 および Windows 98 Second Edition は、共に DLL/COM リダイレクションをサポートしています。それ以前の Windows オペレーティング システムではサポートしていません。

DLL/COM リダイレクションを使用する

DLL/COM リダイレクションを使用すると、開発者または管理者は、開発および展開しているアプリケーションに対する既存のコンポーネントを選択して分離することができます。ここでは、DLL/COM リダイレクションをアクティブにする方法と、分離するコンポーネントの選択方法について説明します。

DLL/COM リダイレクションを実行する

".local" ファイルにより、DLL/COM リダイレクションはアプリケーション単位でアクティブになります。".local" ファイルは空のファイルで、アプリケーションの .exe ファイルと同じディレクトリにあります。また、アプリケーションの .exe ファイルと同じ名前で、その名前の終わりに ".local" が付きます。

たとえば、"myapp.exe" という名前のファイルに対し DLL/COM リダイレクションをアクティブにする場合、myapp.exe がインストールされている同じディレクトリに "myapp.exe.local" という名前の空のファイルを作成します。

DLL/COM リダイレクションをアクティブにすると、アプリケーションが DLL または OCX を読み込む際に、Windows はまずアプリケーションの .exe ファイルがインストールされているディレクトリ内で DLL または OCX を探します。ディレクトリ内に DLL または OCX が存在する場合は、アプリケーションやレジストリで指定されているディレクトリ パスにかかわらず、それを使用します。ディレクトリ内に DLL または OCX がない場合は、通常の検索パスまたはサーバー パスが使用されます。

分離するコンポーネントを選択する

DLL/COM リダイレクションを使用すると、コンピュータにインストールされているアプリケーションが同じコンポーネントの別のバージョンを必要としている場合に、既存のコンポーネントを分離することができます。DLL/COM リダイレクションをアクティブにすると Windows のバインディング処理が変更されるので、コンポーネントのコードを変更する必要はありません。

しかし、コンポーネントの異なるバージョンを Side-by-Side で (並行して) 実行することは、通常設計時には考慮されていませんでした。コンポーネントを並行して簡単にインストールする (共有の記憶域にインストールして複数のアプリケーションに分離する) ことは可能ですが、並行して実行できない場合もあります。これは、コンポーネントによっては、コンピュータ上にはコンポーネントのバージョンは常に 1 つしかないと判断し、グローバルな状態 (レジストリに格納されている設定など) を使用することが原因です。さらにコンポーネントは、必要なその他のリソースの位置を確認する際に、自身がインストールされている特定のディレクトリにこれらのリソースが含まれているということを想定する場合もあります。

このような理由から、単独でインストールされている分離コンポーネントや、コンポーネントの分離元であるアプリケーションのコンテキストにインストールされた分離コンポーネントを使用しているアプリケーションに対するテストは重要です。Microsoft の経験によると、ほとんどの場合は共有コンポーネントを Side-by-Side で実行できますが、前述した問題によって、アプリケーションを起動する前に、その前に実行していたアプリケーションを 1 つ終了させる必要のある場合もあります。

分離するコンポーネントを選択する場合は、次の手順に従ってください。

  • Windows 2000 の System File Protection によって保護されているファイルは分離しないでください。これらのファイルには、ほとんどの .sys、.dll、.exe、および .ocx ファイルが含まれます。

  • 現行のオペレーティング システムでは Side-by-Side を強制していないので、特に共有が行われる領域で Side-by-Side の妥当性を確認するために、すべてのアプリケーションをテストする必要があります。

  • コンポーネントは任意に指定されたアプリケーション ディレクトリにあるため、これらのコンポーネントに対して迅速に修正を加えることができなくなります。管理者は、コンポーネントの修正を行うべき場所を認識しておく必要があります。

シナリオ 1 : アプリケーションに対して ActiveXR コントロールを専有化する

このシナリオでは、管理者は新しいアプリケーションをインストールすることができません。これは、新しいアプリケーションと現在インストールされているアプリケーションでは、Visual Basic で作成された、異なるバージョンの ActiveX コントロールを使用するためです。

ActiveX コントロールに対するバグの修正や変更が行われるに従い、テストに使用した特定のバージョンを使用しないとコントロールを使用するアプリケーションが破損する問題が発見されました。管理者は、ActiveX コントロールの変更によって影響を受けるすべてのアプリケーションに対して修正およびテストを行うのではなく、ActiveX コントロールを使用する異なるアプリケーションでさまざまなバージョンの ActiveX コントロールを実行できるようにする必要があります。

メモ   現在 Visual Basic では、本質的に Side-by-Side な ActiveX コントロールを簡単に開発する方法はありません。これは、Visual Basic で作成された ActiveX コントロールを登録する際に、レジストリに OCX ファイルへの完全修飾パスが書き込まれるためです。

管理者は、新しいアプリケーションが ActiveX コントロールの適切なバージョンを使用するように設定することができます。また、新しいアプリケーションの設定を次のように変更して、既存のアプリケーションの構成が変更されないようにすることもできます。

  • アプリケーションの .exe ファイルを含むディレクトリに ActiveX コントロールの新しいバージョンをインストールします。

  • アプリケーションの .exe ファイルを含むディレクトリに .local ファイルをインストールして、このアプリケーションの実行時に、アプリケーションの .exe ファイルが存在するディレクトリから ActiveX コントロールを読み込むように指定します。

シナリオ 2 : アプリケーションに対して Win32 DLL を専有化する

このシナリオでは、新しいアプリケーションがインストールされた後に既存のアプリケーションが停止するという状況について学びます。ここで、管理者は、この問題は共有コンポーネントに対する変更により発生するもので、共有コンポーネントの新しいバージョンが、以前のバージョンとの下位互換性をサポートしないことが原因であると診断します。

管理者は、次の処置を行ってアプリケーションを修正することができます。

  • 既存のアプリケーションの .exe ファイルがあるディレクトリに、共有 DLL の以前のバージョンをインストールします。

  • 既存のアプリケーションの .exe ファイルがあるディレクトリで .local ファイルを作成します。.local ファイルでは、アプリケーションの起動時に、アプリケーションの .exe ファイルが含まれるディレクトリに存在する DLL を読み込むことを指定します。

分離された COM サーバーをインストールする際の考察

DLL/COM リダイレクションは、アプリケーションに対してプライベートな新しい場所に DLL または OCX ファイルをインストールすることによって行われます。ただし、COM サーバーの分離に関して、特別な指定を含むCOM サーバーに関連する他のシステムの状態は分離されません。

分離された COM サーバーをインストールする場合、コンピュータ上にコンポーネントの別のバージョンが既にインストールされていないかどうか (たとえば、別のアプリケーションによって)、InprocServer ファイルの場所が新しい分離コンポーネントによって上書きされていないかどうかに注意してください。分離されたCOM サーバーでは、InprocServer ファイルの場所は実行時に無視されます。ただし、既存のアプリケーションが DLL/COM リダイレクションを使用しない場合は、以前にインストールされた COM サーバーの場所を指定するために、InprocServer ファイルの場所が引き続き必要になります。これには次のような意味が含まれています。

  • COM サーバーが既にインストールされているコンピュータに分離されたCOM サーバーをインストールする場合、分離されたCOM サーバーのインストール時に登録を行わないでください。

逆に、コンピュータに分離されたCOM サーバーがインストールされていない場合は登録が必要です。ここでは、アプリケーションに対して COM サーバーが分離され、アプリケーションの .exe ファイルが存在するディレクトリにインストールされている場合に、そのコンポーネントを使用する分離されていないアプリケーションをインストールしたときに問題が発生します。この場合、分離されたアプリケーションをアンインストールする際に分離されたCOM コンポーネントが共有ファイルとして扱われ、アンインストールによって他のアプリケーションが損傷することはまずありません。これには次のような意味が含まれています。

  • 分離されたCOM サーバーをインストールする場合、COM サーバーがコンピュータにインストールされていなければ、DLL または OCX ファイルをアプリケーションの .exe ファイルが含まれているディレクトリとシステム ディレクトリ (またはその他の共有領域) の両方にコピーして、システム ディレクトリ (またはその他の共有領域) に含まれるファイルのコピーを登録します。

いくつかのアプリケーションで共有されていたり、アプリケーションに対して専有化されているバージョンがある既存のコンポーネントについては、共有する可能性のあるコンポーネントの分離バージョンを使用するアプリケーションをインストールした後に、コンポーネントの共有バージョンおよび分離バージョンがインストールされ、共有バージョンが登録されていることを確認します。これにより、アンインストール時にほかのアプリケーショを破損せずに分離バージョンを削除することができます。