.NET ベースのコンポーネントの登録を必要としないアクティベーション: チュートリアル

 

Steve White
開発者向けの Premier サポート(Microsoft UK)

レスリー ミュラー
グローバルIT研究開発 & 、クレディスイスファーストボストン

2005 年 7 月

概要: Microsoft Platform SDK は、 分離されたアプリケーションとサイド バイ サイド アセンブリのトピックを文書化する優れた作業を行います。 ただし、すべてのユーザーがこのトピックを COM コンポーネントの登録不要のアクティブ化と同一視しているわけではありません。 登録不要の COM は、ロックダウンされたサーバーとアプリケーションが共有インフラストラクチャ上に分離されている企業にとって非常に興味深いプラットフォーム機能です。 この記事では、COM 相互運用機能を介したネイティブ クライアントによる.NET Framework ベースのコンポーネントの登録不要なアクティブ化の作業例について説明します。 (11ページ印刷)

適用対象:
   Microsoft Windows Server 2003
   Microsoft Windows XP Service Pack 2
   Microsoft .NET Framework バージョン 1.1
   Microsoft Visual Studio .NET 2003
   Microsoft Visual Basic 6.0

この記事に付属するサンプルをダウンロード します。MSDNRegFreeNet.msi

Contents

はじめに
Registration-Free COM の用語
サンプルの実行
COM サーバーとしての .NET アセンブリの構築
クライアントのビルド
Registration-Free アクティブ化
トラブルシューティング
まとめ
もっと読む

はじめに

登録不要 COM は、Microsoft Windows XP (.NET Framework ベースのコンポーネントの場合は SP2) および Microsoft Windows Server 2003 プラットフォームで使用できるメカニズムです。 名前が示すように、メカニズムを使用すると、COM コンポーネントを登録しなくても、コンピューターへの COM コンポーネントの簡単な展開 (XCOPY など) が可能になります。

ターゲット プラットフォームでは、プロセスとその依存モジュールを初期化する段階の 1 つは、関連付けられている マニフェスト ファイルアクティブ化コンテキストと呼ばれるメモリ構造に読み込みます。 対応するレジストリ エントリがない場合は、COM ランタイムに必要なバインディング情報とアクティブ化情報を提供するアクティブ化コンテキストです。 アクティブ 化コンテキスト API を使用してアクティブ化コンテキストを自分で作成してファイルの使用を無効にしない限り、COM サーバーまたはクライアントで特別なコードは必要ありません。

このチュートリアルでは、単純な .NET アセンブリをビルドし、Visual C++ と Visual Basic 6.0 で記述されたネイティブ COM クライアントから、登録と登録解除の両方で使用します。 ソース コードとサンプルをダウンロードしてすぐに動作を確認することも、チュートリアルに従ってステップ バイ ステップでビルドすることもできます。

Registration-Free COM の用語

.NET テクノロジに精通しているユーザーは、 アセンブリ という用語に慣れ、つまり、1 つのモジュールとしてデプロイされ、名前が付けられ、バージョン管理される 1 つ以上のモジュールのセットに慣れ、1 つのモジュールにはセットを定義する マニフェスト が含まれます。 登録不要の COM では、 アセンブリマニフェスト という用語は、概念的には似ていますが、.NET に対応するアイデアと同じではないアイデアに対して借用されます。

登録不要の COM では 、アセンブリ を使用して、1 つのユニットとしてデプロイ、名前付け、バージョン管理された 1 つ以上の PE モジュール (つまり、ネイティブ または マネージド) のセットを意味します。 登録不要の COM では 、マニフェスト を使用して、XML を含む .manifest 拡張子を持つテキスト ファイルを参照します。これは、 アセンブリ (アセンブリ マニフェスト) の ID とそのクラスのバインドとアクティブ化の詳細を定義するか、 アプリケーション (アプリケーション マニフェスト) の ID を 1 つ以上のアセンブリ ID 参照と共に定義します。 アセンブリ マニフェスト ファイルの名前はアセンブリに対して、アプリケーション マニフェスト ファイルの名前はアプリケーションに対して指定されます。

サイド バイ サイド (SxS) アセンブリ という用語は、マニフェスト ファイルを使用して同じ COM コンポーネントの異なるバージョンの構成を指し、登録する必要なく異なるスレッドで同時に読み込むことができます。 SxS は、 登録不要の COM を有効にし、ほぼ同義です。

サンプルの実行

サンプル コードをダウンロードして抽出すると、 \deployed という名前のフォルダーが見つかります。 ここでは、クライアント アプリケーションの Visual C++ バージョン (client.exe)、そのマニフェスト (client.exe.manifest)、および COM サーバーの C# バージョン (SideBySide.dll) をします。 先に進み 、client.exeを実行します。 予想される結果は 、client.exeSideBySideClass ( SideBySide.dllで実装) のインスタンスをアクティブ化し、 " 1.0.0-C#" のように見える Version メソッドを呼び出した結果を表示することです。

COM サーバーとしての .NET アセンブリの構築

手順 1

Visual Studio .NET 2003 で、新しい C# または Visual Basic .NET クラス ライブラリ プロジェクトを作成し、SideBySide と呼びます。 AssemblyInfo を削除します。[プロジェクトから cs/vb] ファイルを作成し、次のように クラスを実装します。

C# コード

using System;
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: Guid("[LIBID_SideBySide]")]

namespace SideBySide
{
   [Guid("[IID_ISideBySideClass]")]
   public interface ISideBySideClass
   {
      string Version();
   }

   [Guid("[CLSID_SideBySideClass]")]
   public class SideBySideClass : ISideBySideClass
   {
      public string Version()
      {
         return "1.0.0-C#";
      }
   }
}

Visual Basic .NET コード

Imports System
Imports System.Reflection
Imports System.Runtime.InteropServices

<Assembly: AssemblyVersion("1.0.0.0")> 
<Assembly: Guid("[LIBID_SideBySide]")>

<Guid("[IID_ISideBySideClass]")> _
Public Interface ISideBySideClass
    Function Version() As String
End Interface

<Guid("[CLSID_SideBySideClass]")> _
Public Class SideBySideClass
    Implements ISideBySideClass
    Function Version() As String Implements ISideBySideClass.Version
        Version = "1.0.0-VB.NET"
    End Function
End Class

プロジェクトに特有の GUID 値をプレースホルダーの形式で記述しました。 guidgen ツールを使用して一意の GUID を生成する必要があります。これは、その後プレースホルダーを使用するときに使用するそれぞれの値になります。

ステップ 2

ビルド時にタイプ ライブラリが生成されて登録されるように、プロジェクトの [ COM 相互運用機能の登録] 設定を true に設定します。

手順 3.

リリース ビルドを生成し、 SideBySide.dllを \deployed にコピーします。

クライアントのビルド

次の手順では、クライアントをビルドします。このチュートリアルでは、 Visual C++ または Visual Basic 6.0 クライアントをビルドするオプションがあります。

手順 4 (オプション A: Visual C++)

SideBySide プロジェクトのフォルダーを基準とした兄弟フォルダーに、client という名前の新しい Visual C++ Win32 コンソール プロジェクトを作成します。 Win32 アプリケーション ウィザードの [アプリケーション設定] タブで、[ATL のサポートの追加] チェックボックスをチェックします。

stdafx.h を編集し、 の直後のファイルの先頭に次の行を#pragma once追加します。

#define _WIN32_DCOM

stdafx.h でも、ファイルの下部に次の行を追加します。

import "[path]\SideBySide.tlb" no_namespace

ここで、[path] は、SideBySide アセンブリをビルドしたときに生成されたタイプ ライブラリへの相対パスである必要があります。 通常、このパスは、手順 1 で C# プロジェクトと Visual Basic .NET プロジェクトのどちらを選択したかによって異なります。

client.cpp の内容を次のコードに置き換えます。

#include "stdafx.h"
#include <iostream>
using namespace std;

void ErrorDescription(HRESULT hr)
{
    TCHAR* szErrMsg;
    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
      FORMAT_MESSAGE_FROM_SYSTEM, 
      NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
      (LPTSTR)&szErrMsg, 0, NULL) != 0)
   {
        cout << szErrMsg << endl;
        LocalFree(szErrMsg);
    }
   else
        cout << "Could not find a description for error 0x" 
           << hex << hr << dec << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
   CoInitializeEx(0, COINIT_MULTITHREADED);

   {
      ISideBySideClassPtr ptr;
      HRESULT hr = 
              ptr.CreateInstance(__uuidof(SideBySideClass));
      if (SUCCEEDED(hr))
      {
         cout << ptr->Version() << endl;
      }
      ErrorDescription(hr);

      char c;
      cin >> c;
   }

   CoUninitialize();

   return 0;
}

リリース ビルドを生成し、 \release\client.exeを \deployed にコピーします。

手順 4 (オプション B: Visual Basic 6.0)

新しい Visual Basic 6.0 Standard EXE プロジェクトを作成します。 [プロジェクト] エクスプローラー[Project1] ノードを選択し、[プロパティ] ウィンドウでその名前をクライアントに変更します。 [ファイル] を選択する |プロジェクトを名前を付けて保存し、フォーム ファイルとプロジェクト ファイルを SideBySide プロジェクトのフォルダーを基準にした兄弟フォルダーに保存します。 [プロジェクト] を選択する |[参照] で、[SideBySide] の横にあるチェック ボックスをチェックし、[OK] を選択します

フォーム デザイナーでメイン フォームをダブルクリックし、Sub Form_Load()内に次のコードを貼り付けます。

    Dim obj As New SideBySideClass
    Dim isxs As SideBySide.ISideBySideClass
    Set isxs = obj
    MsgBox isxs.Version()

[ファイル] を選択する |client.exeします...\deployed フォルダーに移動し、[OK] を選択します

手順 5.

現時点では、 \deployed フォルダーには、一部の中間ファイルとは別に、 client.exeとSideBySide.dll のみが含 まれている 必要があります。後者はビルド プロセスによって登録されます。 このような通常の状況でサーバーとクライアントが連携していることをチェックするには、\deployed\client.exeを実行し、期待される出力 "1.0.0-C#" または "1.0.0-VB.NET" をメモします。

手順 6.

このチュートリアルでは 、登録不要 の COM について説明するため、 SideBySide アセンブリの登録を解除する必要があります。 Visual Studio 2003 コマンド プロンプトで、 \deployed フォルダーに移動し、 コマンドを実行します regasm /u SideBySide.dll

手順 7.

前の手順でどのような影響があるかを確認するには、 \deployed\client.exe をもう一度実行します。"Class not registered" または "Run-time error '429': ActiveX component can't create object" というメッセージが表示されます。 この段階では、COM ランタイムがレジストリで必要な情報を見つけることに不満を感じていましたが、代替手段で情報を利用できるようにはまだありません。 これを次の手順で解決します。

Registration-Free アクティブ化

手順 8.

\deployed フォルダーで、client.exeアプリケーションのアプリケーション マニフェスト ファイル (テキスト ファイル) を作成しそれをclient.exe.manifest と呼びます。 ファイルに次のコードを貼り付けます。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" 
   manifestVersion="1.0">
<assemblyIdentity
            type = "win32"
            name = "client"
            version = "1.0.0.0" />
<dependency>
            <dependentAssembly>
                        <assemblyIdentity
                                    type="win32"
                                    name="SideBySide"
                                    version="1.0.0.0" />
            </dependentAssembly>
</dependency>
</assembly>

手順 9.

SideBySide プロジェクトのフォルダーで、プライベート アセンブリ マニフェスト ファイル (テキスト ファイル) を作成し、SideBySide.manifest と呼びます。 ファイルに次のコードを貼り付けます。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" 
  manifestVersion="1.0">
<assemblyIdentity
            type="win32"
            name=" SideBySide"
            version="1.0.0.0" />
<clrClass
            clsid="{[CLSID_SideBySideClass]}"
            progid="SideBySide.SideBySide"
            threadingModel="Both"
            name="SideBySide.SideBySideClass" >
</clrClass>
</assembly>

次のタスクは、上記のアセンブリ マニフェスト ファイルを Win32 リソースとして SideBySide アセンブリに埋め込むことです。 執筆時点では、これは Windows XP では必須ですが、Windows Server 2003 では必須ではありません。 Windows Server 2003 では アセンブリ マニフェスト ファイルをアセンブリと共に展開するだけで済みます。 ただし、今後の Windows Server 2003 Service Pack で変更される可能性があるため、この動作に依存しないようにお勧めします。 今後も両方のプラットフォームを引き続きサポートするには、次のいくつかの手順に従い、アセンブリ マニフェスト ファイルを Win32 リソースとして .NET アセンブリに埋め込みます。 これは、 の登録なしのアクティブ化にのみ必要です 。NET ベースの コンポーネントと は、 ネイティブ COM コンポーネントの登録不要なアクティブ化の要件ではありません。

手順 10.

SideBySide プロジェクトのフォルダーで、リソース定義スクリプト ファイル (テキスト ファイル) を作成し、SideBySide.rc と呼びます。 ファイルに次のコードを貼り付けます。

#include <windows.h>
#define MANIFEST_RESOURCE_ID 1
MANIFEST_RESOURCE_ID RT_MANIFEST SideBySide.manifest

Windows.h ファイルとその依存関係は、Platform SDK (Core SDK セクション) または Visual C++ をインストールするときに使用できます。 ここで必要な windows.h の部分は、次の定義です。

#define RT_MANIFEST 24

その結果、 SideBySide.rc の内容は次のように解決されます。

1 24 SideBySide.manifest

ただし、指示どおりにマクロ定義を使用する方が明確で一般的です。

手順 11.

SideBySide プロジェクトのフォルダーで、ビルド コマンド ファイル (テキスト ファイル) を作成し、build.cmd と呼びます。 ファイルに次のコードを貼り付けます。

C#をビルドするには:

rc SideBySide.rc
csc /t:library /out:..\deployed\SideBySide.dll 
/win32res:SideBySide.res Class1.cs

Visual Basic .NET をビルドするには:

rc SideBySide.rc
vbc /t:library /out:..\deployed\SideBySide.dll 
/win32resource:SideBySide.res /rootnamespace:SideBySide Class1.vb

これらのコマンドは、まずプラットフォーム SDK (rc.exe) から Microsoft Windows リソース コンパイラ ツールを呼び出して、手順 10 のリソース定義スクリプトを 、SideBySide.res という名前のコンパイル済みリソース ファイルにコンパイルすることです。次に、C# または Visual Basic .NET コンパイラを呼び出して、ソース コード ファイルをアセンブリにビルドし、コンパイルされたリソース ファイルを Win32 リソースとして埋め込みます。 コンパイル済みアセンブリは \deployed フォルダーに書き込まれますが、COM 相互運用機能に登録 されていません

手順 12.

Visual Studio 2003 コマンド プロンプトで、SideBySide プロジェクトのフォルダーに移動し、 コマンドを実行します。 build

手順 13.

マニフェスト ファイルの提供により、クライアントはもう一度 COM 相互運用機能を使用して SideBySideClass クラスをアクティブ化できることを確認し、 \deployed\client.exe を実行し、期待される出力 "1.0.0-C#" または "1.0.0-VB.NET" をメモします。

トラブルシューティング

これまで見てきたように、.NET Framework ベースのコンポーネントの登録不要なアクティブ化には、サーバーまたはクライアントで特別なコードは必要ありません。 必要なのは、一致するマニフェスト ファイルのペアです。そのうちの 1 つは、RT_MANIFEST型の Win32 リソースとして .NET アセンブリに埋め込まれます。

このチュートリアルの方法で、独自の登録不要の開発にアプローチすることをお勧めします。 具体的には、まず、登録済みサーバーでクライアントが動作していることを確認して、既知の状態に到達します。次に、サーバーの登録を解除し、エラー メッセージが予期した内容であることを確認します。最後に、マニフェスト ファイルを作成して配置することで、状況を解決します。 このように、登録なしのアクティブ化に関するトラブルシューティング作業は、マニフェスト ファイルの構造とアセンブリ マニフェストの正しい埋め込みに限定されます。

登録のない COM の問題のトラブルシューティングを行う場合、Windows Server 2003 のイベント ビューアーはフレンドです。 Windows XP または Windows Server 2003 で構成エラーが検出されると、通常、起動したアプリケーションに対してというタイトルのエラー メッセージ ボックスが表示され、「アプリケーションの構成が正しくないため、このアプリケーションを起動できませんでした。」というメッセージが表示されます。 アプリケーションを再インストールすると、この問題が解決する可能性があります。このメッセージが表示されるたびに、Windows Server 2003 で問題を再現し、システム イベント ログを参照し、 SideBySide ソースからイベントを探すようお勧めします。 私がこのような場合にXPのイベントログを見るように提案しない理由は、"[path]\[application filename]に対してアクティブ化コンテキストの生成に失敗しました"などのメッセージが必ず含まれるということです。マニフェスト。 参照エラー メッセージ: 操作が正常に完了しました"。これは問題を特定するのに役立ちません。

マニフェスト ファイルの構造に進む前に、Win32 リソースについて説明しましょう。 前述のように、 windows.h はRT_MANIFESTシンボルを値 24 として定義します。これは、オペレーティング システムが埋め込みマニフェスト ファイルとして認識する値です。 リソース定義スクリプト (.rc ファイル) に windows.h を含め忘れた場合でも、ビルドは成功し、マニフェスト ファイルはリソースとして埋め込まれますが、正しい型ではありません。 マニフェストが正しく埋め込まれたことを確認するには、Visual Studio で SideBySide.dll を開きます (ファイル |開く |ファイル...)。モジュール内のリソースを示すツリー ビューが表示されます。 ルート ノードの下には RT_MANIFEST という名前のノードが存在する必要があります。その下には、マニフェスト リソースのリソース番号を示す別のノードが必要です (チュートリアルでは 1)。 この最後のノードをダブルクリックすると、バイナリ ビューにデータが表示され、XML マニフェスト ファイルに似た簡単なサニティ チェックが表示されます。 バイナリですが、ASCII 範囲の文字は明らかです。 バイナリ データが見つからないか、正しく見つからない場合は、リソース定義スクリプト (.rc ファイル) がマニフェスト ファイルを参照していることを確認します。 RT_MANIFEST ノードのテキストが引用符で囲まれている場合は、リソース定義スクリプト (.rc ファイル) に windows.h を含め忘れた可能性があります。

前述の各エラーは、Windows Server 2003 システム イベント ログに"依存アセンブリ [名前] が見つからず、最後のエラーは参照アセンブリがシステムにインストールされていません" というメッセージで報告されます。

さまざまなマニフェスト ファイルのスキーマについては、「 マニフェスト ファイルリファレンス」という見出しの下の Platform SDK に記載されており、スキーマ検証ツール Manifestchk.vbs を使用できるため、ここではチュートリアルに関連するいくつかの点のみを説明します。 まず、アセンブリ マニフェスト ファイルを調べてみましょう。 例については、手順 9 に戻ります。

登録不要の COM の意味では、アセンブリは、アセンブリマニフェスト ファイルの内容を使用して 1 つ以上の物理ファイルを関連付ける抽象的なアイデアであることを思い出します。

assemblyIdentity 要素は、アセンブリの ID を定義します。 の場合。NET ベースのコンポーネントの name 属性は、.NET アセンブリの名前とそのファイル名と一致する必要があります。それ以外の場合は、Windows Server 2003 システム イベント ログに次のメッセージが表示されます。"依存アセンブリ [value of name attribute] が見つからず、最後のエラーが発生しました 参照アセンブリがシステムにインストールされていません。ただし、version 属性は .NET アセンブリの AssemblyVersion や AssemblyFileVersion と一致する必要はありませんが、何らかの一貫性を適用することをお勧めします。

clrClass 要素には、nameclsid の 2 つの必須属性しかありません。 name 属性は、アクティブ化される CLR クラスの名前空間とクラス名の組み合わせと一致する必要があります。 そうでない場合、CoCreateInstance は値COR_E_TYPELOAD (0x80131522) を持つ HRESULT を返します。 この結果、.NET アセンブリで要求された CLR 型が型ローダーで見つからない場合に、System.TypeLoadException がスローされます。 .NET アセンブリが Visual Basic .NET で記述されている場合にwatchする 1 つの点は、コマンド ラインの /rootnamespace スイッチを Visual Basic .NET コンパイラ (vbc.exe) に指定することです。 clsid 属性は、GuidAttribute を介してアクティブ化される CLR クラスに割り当てられている CLSID と一致する必要があります。 そうでない場合、CoCreateInstance は値 REGDB_E_CLASSNOTREG (0x80040154)、"Class not registered" のメッセージ テキストを持つ HRESULT を返します。

次に、アプリケーション マニフェスト ファイルに注目しましょう。 例については、手順 8 に戻ります。 アプリケーション マニフェストには、[application filename].manifest という形式で名前を付ける必要があります。 そのため、このチュートリアルでは 、client.exe がプロセスに読み込まれるたびに読み込む必要があることを明確にするために 、client.exe.manifest という名前が付けられました。 これが正しく行われなければ、CoCreateInstance は値 REGDB_E_CLASSNOTREG (0x80040154) を持つ HRESULT を返します。メッセージ テキストは "Class not registered" です。

アプリケーション マニフェストで最も重要な要素は、 dependentAssembly/assemblyIdentity 要素です。 この要素はアセンブリ マニフェスト内の同等の要素への参照であり、2 つは 正確に一致する必要があります。 これを確実に行う良い方法は、アセンブリ マニフェストから要素をコピーし、ここに貼り付けることです。 何らかの違いがある場合は、Windows Server 2003 システム イベント ログに"マニフェストで見つかったコンポーネント ID が、要求されたコンポーネントの ID と一致しません" というメッセージが表示されます。

まとめ

登録不要の COM は、WINDOWS レジストリへの依存関係から COM コンポーネントを解放し、その結果、それらを使用するアプリケーションが専用サーバーを必要としないようにするテクノロジです。 これにより、同じ COM コンポーネントの異なるバージョンに依存するアプリケーションがインフラストラクチャを共有し、それらのさまざまな COM コンポーネントのバージョンを .NET のバージョン管理と展開メカニズムのエコーで並列で読み込むことができます。

この記事では、Visual C++ と Visual Basic 6.0 の両方で記述されたネイティブ クライアント アプリケーションによる.NET Framework ベースのコンポーネントの登録不要なアクティブ化のデモについて説明しました。 このメカニズムのしくみの一部について説明し、考えられる構成エラーとそのトラブルシューティング方法について説明しました。

もっと読む

 

筆者について

Steve White は、Microsoft UK の Premier Support for Developers チームで働くアプリケーション開発コンサルタントです。 Visual C#、Windows フォーム、ASP.NET を使用した開発のお客様をサポートしています。 彼の ブログ には、音楽、視覚化、プログラミングに関する彼の興味に関する詳細情報があります。

レスリー・ミュラー は、クレディ・スイス・ファースト・ボストンの研究開発 & チームの技術者です。 レスリーは、金融サービス、テクノロジスタートアップ、産業オートメーション、防衛などの環境で働く開発者および技術アーキテクトとして12年の経験を持っています。 プログラミングや研究をしていないとき、彼はスキー、アイスホッケー、そして可能な限りアイスランドやロッキーのような極端な環境で電動車で少し怒っていることを楽しんでいます。