COM コンポーネントからの .NET コンポーネントの呼び出し

 

Mike Gunderloy
ラークグループ株式会社

2002 年 1 月

概要: COM クライアントから Microsoft .NET サーバーを呼び出す方法の詳細について説明します。 (12ページ印刷)

目標

  • COM 呼び出し可能ラッパーの概念を理解する
  • Microsoft® Visual Basic® 6.0 から呼び出すことができる .NET サーバーを作成する
  • sn、regasm、gacutil ユーティリティを使用する
  • .NET クラスを使用する Visual Basic 6.0 コードを記述する

前提条件

このドキュメントを最大限に活用するには、次のことが当てはまります。

  • Visual Basic プログラミングに精通している
  • COM の概念に精通している
  • Visual Basic .NET にアクセスできます
  • .NET アーキテクチャ全体を理解している
  • Visual Basic .NET でパブリック クラスを作成する方法について説明します

内容

相互運用性の喜び
COM アプリケーションで使用する .NET クラスの作成
COM から .NET コンポーネントを呼び出す練習
Visual Basic 6.0 以降の新機能
まとめ

相互運用性の喜び

プログラミングの革命によって、前に来たすべてを放棄することが強制される場合があります。 極端な例を見ると、何年も前から Visual Basic アプリケーションを作成してきたとします。 多くの開発者に似ている場合は、その時点でコードのかなりのインベントリを構築することになります。 また、さまざまな言語教師からの推奨事項に従っている場合、そのコードは コンポーネント化されます。 つまり、COM (コンポーネント オブジェクト モデル) (以前の Microsoft® ActiveX®) サーバーを使用すると、アプリケーションが呼び出し可能な機能のチャンクに分割されました。 もちろん、他の開発者や他の企業から、ActiveX コントロールなどのコンポーネントに多額の投資を行う可能性もあります。

しかし、開発を別のオペレーティングシステムに完全に切り替えるという根本的な動きを決めたらどうでしょうか? その時点で、COM への投資全体が無価値になります。 既存のコードを使用することはできません。また、新しいプラットフォームですべてを実行する方法を学習する必要があります。 これは間違いなくあなたの生産性に深刻な打撃になります。

幸いなことに、COM から .NET に切り替えると、このような生産性が大幅に低下する必要はありません。 コード ベースや生産性を損なうことなく、COM 開発から .NET 開発への移行を大幅に容易にする 2 つの主要な概念があります。

  • .NET コンポーネントは COM コンポーネントを呼び出すことができます。
  • COM コンポーネントは.NET コンポーネントを呼び出すことができます。

この双方向の相互運用性は、COM から .NET への移行の鍵となります。 .NET の複雑さを学習すると、引き続き COM コンポーネントを使用できます。 この相互運用性が役立つ状況は多数あります。

  • .NET への切り替えがすぐには行われません。 .NET プログラミングの概念と実装を学ぶのに時間がかかるため、自分、同僚、サプライヤーがスピードを上げる間に、COM コードを引き続き使用する必要がある場合があります。
  • .NET に移行できるコードは、一度にすべて移行することはできません。 移行された各コンポーネントを個別に移行してからテストする必要があります。
  • .NET に変換できないサードパーティの COM コンポーネントを使用していて、サプライヤーがまだ .NET バージョンをリリースしていない場合があります。
  • Visual Basic 6.0 コードは .NET に移行されますが、移行は完全ではありません。 実装や言語の違いにより、.NET に移動できないコンポーネントがある場合があります。

このドキュメントでは、COM クライアントから .NET サーバーを呼び出す方法の詳細について説明します。 このシリーズの別のドキュメント「 .NET クライアントからの COM コンポーネントの呼び出し」では、.NET クライアントから COM サーバーへの他の方向での呼び出しについて説明します。

COM アプリケーションで使用する .NET クラスの作成

COM クライアントは、.NET サーバーによってパブリック クラスで公開されているコードを呼び出すことができますが、COM クライアントから .NET コードに直接アクセスすることはできません。 COM クライアントから .NET コードを使用するには、COM 呼び出し可能ラッパー (CCW) と呼ばれるプロキシを作成する必要があります。 このセクションでは、CCW アーキテクチャと、COM クライアントで使用される .NET クラスを作成および展開するために必要な手順について説明します。

COM 呼び出し可能ラッパー

.NET 共通言語ランタイム (CLR) 内で動作するコードは、 マネージド コードと呼ばれます。 このコードは、言語間統合、セキュリティとバージョン管理のサポート、ガベージ コレクションなど、CLR がテーブルに提供するすべてのサービスにアクセスできます。 CLR 内で動作しないコードは、 アンマネージド コードと呼ばれます。 COM は CLR が存在する前に設計されており、COM コードは CLR によって提供されるインフラストラクチャ内で動作しないため、どの CLR サービスも使用できません。 すべての COM コンポーネントは、定義上、アンマネージド コードです。

マネージド コード コンポーネントは CLR に依存するだけでなく、CLR に依存するために対話するコンポーネントを必要とします。 COM コンポーネントは CLR 内では動作しないため、マネージド コード コンポーネントを直接呼び出すことはできません。 アンマネージ コードは、マネージド コンポーネントを直接呼び出すために CLR に到達することはできません。

このジレンマから抜け出す方法は、 プロキシを使用することです。 一般に、プロキシとは、コンポーネントからコマンドを受け入れ、変更し、別のコンポーネントに転送するソフトウェアの一部です。 アンマネージ コードからマネージド コードを呼び出す際に使用されるプロキシの特定の種類は、COM 呼び出し可能ラッパー (CCW) と呼ばれます。 図 1 は、CCW がマネージド コードとアンマネージド コードの境界をまたぐ方法を概略的に示しています。 この図には、ComUI.exeという名前の COM プログラム、NETService.dll と Utility.dll という名前の 2 つの .NET コンポーネント、およびそれらを接続するための必要なテクノロジが含まれます。

図 1. CCW を使用したマネージド コードの呼び出し

COM 呼び出し可能クラスの前提条件

COM クライアントで使用される .NET クラスを作成する場合は、2 つの前提条件に留意する必要があります。

まず、Visual Basic .NET コードでインターフェイスを明示的に定義し、 クラスに インターフェイスを実装させます。 たとえば、次のコード スニペットでは、iFile という名前のインターフェイスと、 インターフェイスを実装するクラスを定義します。

Public Interface iFile
    Property Length() As Integer
End Interface

Public Class TextFile
    Implements iFile
    ' details omitted
End Class

インターフェイスを使用して機能を実装すると、COM クライアントにとって大きな利点があります。 .NET では、CCW の生成時にインターフェイスが以前のバージョンと一貫性を保ちます。 これにより、.NET サーバーに対する変更が COM クライアントを壊すのを防ぐことができます。

第 2 に、COM クライアントに表示されるクラスは、パブリックとして宣言する必要があります。 CCW を作成するツールは、パブリック クラスに基づいて型のみを定義します。 COM クライアントで使用されるメソッド、プロパティ、イベントにも同じ規則が適用されます。

また、暗号化キー ペアを使用して COM によって使用されるクラスを含む .NET アセンブリに署名することも検討する必要があります。 Microsoft はこれを、 厳密な名前でアセンブリに署名することを指します。 厳密な名前でアセンブリに署名すると、アセンブリが発行されてからアセンブリ内のコードが変更されていないことを .NET で確認できます。 これは、すべての グローバル アセンブリ (複数のクライアントで共有されるアセンブリ) の要件ですが、署名されていないアセンブリは COM クライアントから呼び出すこともできます。

メモ アセンブリをプライベート アセンブリとして COM クライアントのディレクトリに直接展開することで、COM クライアントから署名されていない アセンブリを使用できます。 グローバル アセンブリは、ほとんどの COM アプリケーションのアーキテクチャを持つプライベート アセンブリよりも互換性があるため、このドキュメントではプライベート アセンブリのアプローチについては説明しません。

プライベート アセンブリであっても、すべてのアセンブリに署名することをお勧めします。 これにより、マネージド クラスに対して優れた CLSID を生成し、異なるアセンブリ内のクラス間の競合を回避できます。

厳密な名前を作成するには、sn ツールを使用します。 このコマンド ライン ツールには多くのオプションがあり、コマンド プロンプトで 「sn /?」と 入力してすべてを表示できます。 アセンブリに署名するために必要なオプションは 、キー ファイルを作成する -k です。 既定では、キー ファイルでは拡張子 .snk が使用されます。 たとえば、NETServer.snk という名前のキー ファイルを作成するには、次のコマンド ラインを使用できます。

sn -k NETServer.snk

COM アクセスに対するアプリケーションの配置

COM クライアントによって呼び出されるクラスを含む .NET アセンブリを作成したら、COM でクラスを使用できるようにする 3 つの手順があります。

最初に、アセンブリのタイプ ライブラリを作成する必要があります。 タイプ ライブラリは、.NET アセンブリに含まれるメタデータと同等の COM です。 タイプ ライブラリは、通常、拡張子が .tlb のファイルに含まれています。 タイプ ライブラリには、COM クライアントが特定のサーバーに配置されているクラス、およびそれらのクラスでサポートされているメソッド、プロパティ、およびイベントを決定するために必要な情報が含まれています。 .NET Framework SDK には、アセンブリからタイプ ライブラリを作成できる tlbexp (タイプ ライブラリ エクスポーター) という名前のツールが含まれています。 Tlbexp にはいくつかのオプションが含まれており、コマンド プロンプトで 「tlbexp /? 」と 入力して、すべてのオプションを表示できます。 これらのオプションの 1 つは /out オプションで、生成されたタイプ ライブラリの名前を指定できます。 (独自の名前を作成しない場合は、自動的に作成されます)。たとえば、NETServer.dll という名前のアセンブリから NETServer.tlb という名前のタイプ ライブラリにメタデータを抽出するには、次のコマンド ラインを使用できます。

tlbexp NETServer.dll /out:NETServer.tlb

次に、.NET Framework SDK のアセンブリ登録ツール (regasm) を使用して、タイプ ライブラリを作成し、1 つの操作で登録する必要があります。 これは、1 台のコンピューターで .NET と COM の両方の開発を行う場合に使用する最も簡単なツールです。 tlbexp と同様に、regasm には多くのオプションがあります。コマンド プロンプトで regasm /? を入力して、すべてを表示します。 regasm を使用してタイプ ライブラリを作成して登録するには、次のようなコマンド ラインを使用します。

regasm /tlb:NETServer.tlb NETServer.dll

第 3 に、共有アセンブリとして使用できるように、.NET アセンブリをグローバル アセンブリ キャッシュ (GAC) にインストールする必要があります。 アセンブリを GAC にインストールするには、gacutil ツールを使用します。

gacutil /i NETServer.dll

ここでも、「 gacutil /? 」と入力すると、gacutil のすべてのオプションの一覧を取得できます。 at a command prompt.

COM から .NET コンポーネントを呼び出す練習

次の例では、COM コードの .NET コンポーネントでプロパティとメソッドを使用します。 regasm を使用して.NET アセンブリからタイプ ライブラリを作成し、アセンブリを登録し、gacutil を使用してアセンブリをグローバルに使用できるようにします。 その後、Visual Basic 6.0 COM コード内からこの .NET アセンブリを使用する方法を確認します。

.NET アセンブリを作成する

パブリック クラスを含む .NET アセンブリを作成するには、次の手順に従います。

  1. Microsoft® Visual Studio® .NET を開き、スタート ページで [新しいプロジェクト ] をクリックします。

  2. 画面の左側にあるツリー ビューから [ Visual Basic プロジェクト ] を選択します。

  3. プロジェクト テンプレートとして [ クラス ライブラリ ] を選択します。

  4. アプリケーションの名前を PhysServer2 に設定し、[ OK] をクリックして プロジェクトを作成します。

  5. ソリューション エクスプローラー ウィンドウで Class1.vb というクラスを強調表示し、名前を NETTemperature.vb に変更します。

  6. NETTemperature.vb の Class1 のコードを選択し (これは空のクラス定義になります)、次のコードに置き換えます。

    Public Interface iTemperature
        Property Celsius() As Double
        Property Fahrenheit() As Double
        Function GetCelsius() As Double
        Function GetFahrenheit() As Double
    End Interface
    
    Public Class NET_Temperature
        Implements iTemperature
    
        Private mdblCelsius As Double
        Private mdblFahrenheit As Double
    
        Public Property Celsius() As Double _
         Implements iTemperature.Celsius
            Get
                Celsius = mdblCelsius
            End Get
            Set(ByVal Value As Double)
                mdblCelsius = Value
                mdblFahrenheit = ((Value * 9) / 5) + 32
            End Set
        End Property
    
        Public Property Fahrenheit() As Double _
         Implements iTemperature.Fahrenheit
            Get
                Fahrenheit = mdblFahrenheit
            End Get
            Set(ByVal Value As Double)
                mdblFahrenheit = Value
                mdblCelsius = ((Value - 32) * 5) / 9
            End Set
        End Property
    
        Public Function GetCelsius() As Double _
         Implements iTemperature.GetCelsius
            GetCelsius = mdblCelsius
        End Function
    
        Public Function GetFahrenheit() As Double _
         Implements iTemperature.GetFahrenheit
            GetFahrenheit = mdblFahrenheit
        End Function
    End Class
    

このコードは、 まず iTemperature という名前のインターフェイスを定義することから始めます。 インターフェイスはパブリック キーワード (keyword)で定義されているため、このアセンブリから作成するタイプ ライブラリにエクスポートされます。 インターフェイス定義は、クラス定義のすべてまたは一部のスケルトンと考えることができます。 インターフェイス定義には、クラスと同様にメンバー (プロパティ、メソッド (関数またはサブ) とイベント) を含めることができます。 ただし、クラスとは異なり、インターフェイス定義には、これらのメンバーのコードは含まれていない。 クラスは、(この例のように) 1 つのインターフェイスまたは複数のインターフェイスを実装できます。

このコードでは、インターフェイス iTemperature を使用するNET_Temperature クラスを定義します。 特に、クラス定義のこの行は、 クラスとインターフェイスの間にコントラクトを設定します。

Implements iTemperature

コントラクトは、 クラスが インターフェイスのすべてのメンバーを実装することを示します。 また、インターフェイスの一部ではない追加のメンバーが含まれている場合もありますが、インターフェイスを完全に実装していないクラスをビルドしようとするとエラーが発生します。

メモ クラスは、2 つのパブリック プロパティと 2 つのパブリック メソッドを公開します。 (クラス、メソッド、およびプロパティの作成の基本については、「 Visual Basic .NET でのクラスの作成」を参照してください)。

クラス内のメンバーを、クラスが実装するインターフェイスのメンバーに関連付けるために使用される構文に注目してください。 たとえば、NET_Temperature クラスの摂氏プロパティは次のように定義されます。

Public Property Celsius() As Double _
 Implements iTemperature.Celsius

このコード行は、Double を返すプロパティを定義し、このプロパティが iTemperature インターフェイス内の摂氏プロパティの実装であることをコンパイラに伝えます。

キー ペアを作成してアセンブリに署名する

アセンブリをグローバルに使用できるようにするには、キー ペアを作成し、それを使用してアセンブリに署名する必要があります。 さらに、タイトルと説明を追加することで、アセンブリを簡単に操作できます。

アセンブリに署名するには、sn ユーティリティを実行し、キー ファイルの名前を手動で追加するか、Visual Studio .NET ユーザー インターフェイスを使用して厳密な名前を生成します。 後者のメソッドを使用します。 これを行うには、次のステップに従います。

  1. Visual Studio .NET のソリューション エクスプローラーで、AssemblyInfo.vb ファイルをダブルクリックして編集ウィンドウで開きます。

  2. このファイルの上部にある [アセンブリ属性] セクションで、読み取る AssemblyTitle 行と AssemblyDescription 行を変更します。

    <Assembly: AssemblyTitle("PhysServer2")> 
    <Assembly: AssemblyDescription(".NET Version of PhysServer")> 
    

    **ヒント!   **Visual Basic .NET のアセンブリ属性は、Visual Basic 6.0 のプロジェクト プロパティと同等です。

  3. ソリューション エクスプローラーで、プロジェクト ノードを右クリックし、[プロパティ] を選択します。 [ 共通プロパティ ] フォルダーをクリックし、[ 厳密な名前 ] プロパティ ページをクリックします。 [Generate Strong Name Using]\(厳密な名前の生成の使用\) というラベルの付いたボックスを選択します。 [ キーの生成 ] をクリックしてキー ファイルを生成し、プロジェクトに追加します。 [ OK] を クリックしてプロパティ ダイアログ ボックスを閉じます。

これで、アセンブリを作成する準備ができました。 [ ビルド ] をクリックするか、 Ctrl + Shift + B キーを押してアセンブリをビルドします。

アセンブリを登録してタイプ ライブラリを作成する

この時点で、別の .NET アプリケーションから新しいアセンブリと NET_Temperature クラスを使用できます。 ただし、クラスとそのメンバーを COM アプリケーションで使用できるようにする必要があります。 Visual Studio .NET コマンド プロンプトを開き ([スタート]、[プログラム]、[Microsoft Visual Studio .NET 7.0]、[Visual Studio .NET Tools]、[Visual Studio .NET コマンド プロンプト] の順にクリック)、PhysServer2 のプロジェクト ディレクトリに変更し、次のように入力します。

regasm /tlb:PhysServer2.tlb PhysServer2.dll

regasm ユーティリティはタイプ ライブラリを作成し、それを Windows レジストリに登録して、PhysServer2.dllのクラスを COM クライアントで使用できるようにします。

アセンブリをグローバル アセンブリ キャッシュに追加する

最後に、新しく登録されたアセンブリをハード ドライブ上にあるすべての COM クライアントでグローバルに使用できるようにするには、Visual Studio .NET コマンド プロンプトに戻り、次のように入力します。

gacutil /I PhysServer2.dll

gacutil ユーティリティは、アセンブリを GAC に追加し、ステータス メッセージを出力して、それが完了したことを通知します。

.NET クラスを呼び出す Visual Basic 6.0 コードを記述する

これで、 NET_Temperature クラスを使用する COM クライアントを作成する準備ができました。 次の手順のようにします。

  1. Visual Basic 6.0 を開き、[新しいプロジェクト] ダイアログ ボックスで [ 新規] タブをクリックします。

  2. [ Standard EXE ] を選択し、[ 開く] をクリックします。

  3. [Project エクスプローラー] ウィンドウで Form1 という名前のフォームを強調表示し、名前を frmTemperature に変更します。

  4. 表 1 に示すように、適切なコントロールを追加し、それらのコントロールのプロパティを設定して、図 2 に示すフォームを作成します。

    表 1 frmTemperature のコントロール

    コントロール型 プロパティ
    Label 名前 lblFahrenheit
      Caption ファラハイト
    TextBox 名前 txtFahrenheit
      Text (空白)
    ボタン 名前 cmdConvertToC
      Caption C に変換する
    Label 名前 lblCelsius
      Caption 摂氏
    TextBox 名前 txtCelsius
      Text (空白)
    ボタン 名前 cmdConvertToF
      Caption F に変換

    図 2. テスト フォームの設計

  5. CCW から PhysServer2 のクラスを使用するには、[ プロジェクト] をクリックし、[参照] をクリックして [ 参照 ] ダイアログ ボックスを開きます。 図 3 に示すように、PhysServer の .NET バージョンのリファレンスを選択します。 [OK] をクリックしてダイアログ ボックスを閉じます。

    図 3: .NET コンポーネントへの参照の設定

これで、 NET_Temperature クラスのメソッドとプロパティを使用するコードを記述する準備ができました。 [ 表示 ] メニューの [ コード] をクリックし、frmTemperature のフォーム モジュールに次のコードを入力します。

Private moTempClass As PhysServer2.NET_Temperature
Private moTemp As PhysServer2.iTemperature

Private Sub cmdConvertToC_Click()
    With moTemp
        .Fahrenheit = txtFahrenheit.Text
         txtCelsius.Text = .GetCelsius
    End With
End Sub

Private Sub cmdConvertToF_Click()
    With moTemp
        .Celsius = txtCelsius.Text
        txtFahrenheit.Text = .GetFahrenheit
    End With
End Sub

Private Sub Form_Load()
    Set moTempClass = New PhysServer2.NET_Temperature
    Set moTemp = moTempClass
End Sub

.NET プロジェクトでは、iTemperature インターフェイスを使用して Net_Temperature クラスを定義しました。 このコードでは、インターフェイス ( moTemp という名前のオブジェクトとして表されます) を オブジェクトから取得する方法を示します。 これは余分なコードのように見えるかもしれませんが、Visual Basic で実験すると、 オブジェクトよりもインターフェイスを操作する方がはるかに便利であることがわかります。 これは、インターフェイスが Microsoft® IntelliSense® コマンド入力候補をサポートしているためです。

試してみる

NET_Temperature クラスの動作を確認するには、次の手順に従います。

  1. F5 キーを押してプロジェクトを開始します。
  2. [華氏] ボックスに 「95 」と入力し、[ C に変換] をクリックします。[摂氏] ボックスに値 35 を入力する必要があります。
  3. [摂氏] ボックスに 「-14 」と入力し、[ F に変換] をクリックします。[華氏] ボックスに値 6.8 を入力する必要があります。
  4. フォームを閉じてプロジェクトを停止します。

Visual Basic 6.0 以降の新機能

もちろん、Visual Basic 6.0 から .NET コンポーネントを呼び出すプロセス全体は、Visual Basic 6.0 のリリース時に .NET が存在しなかったため、新しいプロセスです。 Visual Basic 6.0 には、COM 呼び出しによって接続された複数のコンポーネントを作成する機能があり、.NET CCW は COM 呼び出しと同様に .NET 呼び出し関数を行います。 プロセス全体の良い点は、COM コードから使用するために .NET コンポーネントの安全性と安定性を危険にさらす必要がないということです。 CLR を介して を呼び出すことで、.NET コンポーネントを使用する場所に関係なく、CCW はマネージド コードのすべての利点を .NET コンポーネントに提供します。

まとめ

.NET はまったく新しい開発環境ですが、デザイナーは既存のコードとの互換性の問題を無視しませんでした。 .NET コンポーネントを適切に構築し、sn、tlbexp、regasm、gacutil などのツールを使用することで、.NET アセンブリから COM クライアントにクラスを公開できます。

COM コンポーネントから .NET コンポーネントを呼び出すことは簡単な演習ではありません。 このドキュメントで説明したように、このシナリオを有効にするには、.NET コンポーネントに明示的なコード変更を行う必要があります。 ただし、変更は軽微であり、COM クライアントで .NET サーバーを呼び出す利点は確かにあります。 複雑なアプリケーションを COM から .NET コンポーネントに一度に 1 つずつ移行する場合は、このドキュメントで説明されている手法が不可欠です。

著者について

マイク・ガンダーロイは ソフトウェアについて書き、ワシントン州東部でニワトリを育てる。 Access 2002 Developer's Handbook の共同執筆者であり、Sybex 社の analysis Services を使用したSQL Server Developerの OLAP ガイドの著者です。 彼は、先史時代から Microsoft 製品のコードを作成しており、すぐに停止するつもりはありません。

情報伝達グループについて

インフォーマント・コミュニケーションズ・グループ(www.informant.com)は、情報技術分野に重点を置いた多様なメディア企業です。 ソフトウェア開発出版物、カンファレンス、カタログ発行、Webサイトを専門とするICGは、1990年に設立されました。 ICGは、米国および英国にオフィスを構え、質の高い技術情報に対する IT プロフェッショナルの高い意欲を満たす、メディアおよびマーケティング コンテンツ インテグレーターとして高い評価を受けています。

Copyright © 2002 Informant Communications Group and Microsoft Corporation

技術編集: PDSA, Inc. および KNG コンサルティング