COM アプリケーションの開発

提供: RAD Studio
移動先: 案内検索

COM を使った相互運用アプリケーションの開発 への移動

Delphi は,Microsoft のコンポーネントオブジェクトモデル(COM: Component Object Model)に基づいたアプリケーションの実装を容易にするためのウィザードとクラスを提供しています。これらのウィザードを使用すれば,アプリケーション内で使用する COM ベースのクラスおよびコンポーネントを作成したり,COM オブジェクトを実装した完全に機能する COM クライアントおよびサーバー,オートメーションサーバー(Active Server オブジェクトなど),ActiveX コントロール,または ActiveForm を作成することができます。

ここでは,次の内容について説明します。

  • COM テクノロジーの概要
  • COM インターフェース
  • COM サーバー
  • COM クライアント

COM テクノロジーの概要

COM は,Windows プラットフォーム上で動作するソフトウェアコンポーネントとアプリケーションの間の対話を可能にするための,言語に依存しないソフトウェアコンポーネントモデルです。COM の最も重要な機能は,明確に定義されたインターフェースを通じて,コンポーネント間,アプリケーション間,およびクライアントとサーバー間の通信を可能にすることです。インターフェースは,クライアントが COM コンポーネントに対して実行時にどの機能をサポートするかを問い合わせるための手段を提供します。コンポーネントに機能を追加するには,追加機能用のインターフェースを追加するだけですみます。

アプリケーションは,同じコンピュータ上にある COM コンポーネントのインターフェースにアクセスするか,分散 COM(DCOM)と呼ばれるメカニズムを使ってネットワーク上の別のコンピュータ上にある COM コンポーネントのインターフェースにアクセスすることができます。

COM は,仕様であると同時に実装されたものでもあります。COM の仕様は,オブジェクトの作成とオブジェクト相互の通信がどのように行われるかを定義しています。この仕様にしたがって,COM オブジェクトをさまざまな言語で書いて,さまざまなプロセス空間およびプラットフォームで実行することができます。記述された仕様に準拠しているオブジェクトは相互に通信できます。したがって,古いコードを 1 つのコンポーネントとして,オブジェクト指向言語で書かれた新しいコンポーネントと統合することができます。

COM の実装は Win32 サブシステムに組み込まれています。Win32 サブシステムはこの仕様をサポートするための多数のコアサービスを提供します。COM ライブラリには,COM オブジェクトの基本機能を定義する標準インターフェースセットおよび COM オブジェクトの作成と管理のための API 関数が入っています。

アプリケーションの中で Delphi のウィザードと VCL オブジェクトを使用するということは,COM 仕様の Delphi の実装を使用するということです。さらに,直接実装されていない機能(ActiveX ドキュメントなど)に代わる COM サービスのためのラッパーも提供されています。ComObj ユニットで定義したラッパーや AxCtrls ユニットの API 定義を見つけることができます。

メモ:  Delphi のインターフェースと言語は,COM の仕様に対応しています。Delphi は Delphi ActiveX framework(DAX)と呼ばれるクラスのセットを使用して,COM 仕様に合ったオブジェクトを実装します。これらのクラスは AxCtrls,OleCtrlsOleServer の各ユニットにあります。また,COM API との Delphi インターフェースは,ActiveX.pasComSvcs.pas にあります。

COM インターフェース

COM クライアントは,COM インターフェースを介してオブジェクトと通信します。インターフェースは,サービスの提供者(サーバーオブジェクト)とそのクライアントとの間の通信を提供する,論理的または意味的に関連したルーチンのグループです。

たとえば,各 COM オブジェクトは,基本的なインターフェース IUnknown を実装しなければなりません。IUnknown 内の QueryInterface というルーチンによって,クライアントは,サーバーが実装するその他のインターフェースを要求できます。

オブジェクトは複数のインターフェースを持つことができ,各インターフェースがそれぞれ 1 つの機能を実装します。インターフェースは,オブジェクトがサービスをどこでどのようにして提供するかという実装の詳細を知らせずに,どのようなサービスを提供するかをクライアントに知らせる手段を提供します。

COM インターフェースの主な特徴は以下のとおりです。

  • 公開されたインターフェースは変更されません。インターフェースは,特定の機能のセットを提供することを保証します。追加の機能はインターフェースの追加によって提供されます。
  • 慣例により,COM インターフェース識別子は大文字の I(アイ)で始まり,その後にインターフェースを定義するシンボル名が続きます(例:IMallocIPersist など)。
  • インターフェースは,グローバルユニーク識別子(GUID: Globally Unique Identifier)と呼ばれるユニークな識別子を持つことが保証されています。GUID はランダムに生成される 128 ビットの数値です。インターフェースの GUID はインターフェース識別子(IID: Interface Identifier)と呼ばれます。IID によって,同一製品の異なるバージョン間や異なる製品間での名前の競合が避けられます。
  • インターフェースは言語に依存しません。COM インターフェースの実装には,ポインタの構造をサポートしていて,ポインタを通じて明示的または暗黙に関数を呼び出すことのできる言語であれば,どのような言語でも使用できます。
  • インターフェース自体はオブジェクトではなく,オブジェクトにアクセスする手段を提供するものです。したがって,クライアントはデータに直接アクセスするわけではなく,インターフェースポインタを介してデータにアクセスします。Windows 2000 にはインターセプタというもう 1 つの間接層があり,この層を通して即時アクティブ化,オブジェクトプーリングといった COM+ 機能を提供しています。
  • インターフェースは,常に基本インターフェース IUnknown から継承されます。
  • スレッド間,プロセス間,およびネットワーク化されたマシンの間でインターフェースメソッド呼び出しを行えるようにするために,プロキシを通じてインターフェースが COM によってリダイレクトされるようにすることができます(クライアントまたはサーバーオブジェクトがこのリダイレクトに気付くことはありません)。

IUnknown インターフェース

COM オブジェクトはすべて,IUnknown(基本インターフェース型 IInterface の typedef)という基本インターフェースをサポートしなければなりません。IUnknown には以下のルーチンが含まれています。

  • QueryInterface:そのオブジェクトがサポートしているほかのインターフェースにポインタを提供します。
  • AddRef および Release:オブジェクトが自分の存続期間を追跡し,そのサービスをクライアントが必要としなくなったときに自分を削除できるようにする,単純な参照カウントのためのメソッドです。

クライアントは,IUnknown メソッド QueryInterface を通じて,ほかのインターフェースへのポインタを取得します。QueryInterface は,サーバーオブジェクト内のすべてのインターフェースを知っているので,要求されたインターフェースへのポインタをクライアントに与えることができます。クライアントは,インターフェースへのポインタを受け取ると,そのインターフェースのどのメソッドでも呼び出せることが保証されます。

オブジェクトは,参照カウントのためのメソッドである IUnknownAddRef および Release メソッドを通じて,自分の存続期間を追跡します。オブジェクトは,参照カウントがゼロ以外である間メモリに残ります。参照カウントがゼロになると,インターフェースの実装は基礎となるオブジェクトを安全に破棄できます。

COM インターフェースポインタ

インターフェースポインタは,オブジェクトのインスタンスを指し示し,それによってさらにインターフェース内の各メソッドの実装を指し示すポインタです。実装へのアクセスには,これらのメソッドへのポインタの配列が使用されます。この配列は仮想テーブルと呼ばれます。仮想テーブルは,Delphi で仮想関数をサポートするために使用されているメカニズムと類似しています。この類似点があるので,コンパイラは,Delphi クラス上のメソッドの呼び出しの解決と同様に,インターフェース上のメソッドの呼び出しを解決できます。

仮想テーブルは,1 つのオブジェクトクラスのすべてのインスタンスの間で共有されるので,オブジェクトコードは各オブジェクトインスタンスについて,プライベートなデータを入れるための第 2 の構造体を割り当てます。したがって,クライアントのインターフェースポインタは,仮想テーブルへのポインタへのポインタです。

Windows 2000 以降では,オブジェクトが COM+ で動作しているとき,インターフェースポインタと vtable ポインタの間に別の間接層(インターセプタ)が提供されます。クライアントに示すインターフェースポインタはインターセプタを指し,インターセプタは vtable を指します。これにより,COM+ は即時アクティブ化などのサービスを提供し,クライアントに認識されずにサーバーを動的に起動/停止することができます。これを実現するため,COM+ は,インターセプタが通常の vtable ポインタであるかのように動作させます。

COM サーバー

COM サーバーは,クライアントのアプリケーションまたはライブラリにサービスを提供するアプリケーションまたはライブラリです。COM サーバーは 1 つまたは複数の COM オブジェクトで構成され,COM オブジェクトは一群のプロパティとメソッドで構成されます。

クライアントは,COM オブジェクトが自分のサービスをどのようにして実行するかを知りません。オブジェクトの実装は非表示のままです。前述のように,オブジェクトは自分のインターフェースを通じて自分のサービスを提供できるようにします。

クライアントは,COM オブジェクトがどこに存在するかを知る必要もありません。COM は,オブジェクトの場所に関係なく,透過的なアクセスを提供します。

クライアントは,COM オブジェクトからのサービスを要求するときに,クラス識別子(CLSID)を COM に渡します。CLSID は単に COM オブジェクトを識別する GUID です。CLSID はシステムレジストリに登録されており,COM はこの CLSID を使用して,適切なサーバーの実装を探し出します。適切なサーバーが探し出されると,COM はそのコードをメモリに読み込んで,サーバーがそのクライアントのためのオブジェクトインスタンスを作成するようにさせます。このプロセスは,要求時にオブジェクトのインスタンスを作成する(インターフェースに基づく)クラスファクトリと呼ばれる特殊なオブジェクトを介して,間接的に処理されます。

COM サーバーは,少なくとも以下のことを実行する必要があります。

  • サーバーモジュールをクラス識別子(CLSID)と関連付けるシステムレジストリにエントリを登録する。
  • 特定の CLSID の別のオブジェクトを作成するクラスファクトリオブジェクトを実装する。
  • クラスファクトリを COM に公開する。
  • クライアントにサービスを提供していないサーバーをメモリから削除するためのアンロード機構を提供する。

COM クライアント

COM クライアントとは,ほかのアプリケーションまたはライブラリが実装する COM オブジェクトを使用するアプリケーションです。最も一般的なタイプはオートメーションコントローラで,オートメーションサーバーと ActiveX コントロールをホストする ActiveX コンテナを制御します。

COM クライアントには,コントローラとコンテナの 2 種類があります。コントローラはサーバーを起動し,そのインターフェースを通じてサーバーと対話します。コントローラは COM オブジェクトにサービスを要求するか,COM オブジェクトを個別のプロセスとして駆動します。コンテナは,そのユーザーインターフェースに表示されるビジュアルコントロールまたはオブジェクトのホストになります。コンテナは,定義済みのインターフェースを使用して,表示の問題をサーバーオブジェクトとネゴシエートします。DCOM を介してコンテナ関係を持つことはできません。たとえば,コンテナのユーザーインターフェースに表示するビジュアルコントロールは,ローカルに配置しなければなりません。これは,コントロールが自分自身をペイントすると想定されるからです。コントロールが自分自身をペイントするには,ローカルの GDI リソースにアクセスできるようにする必要があります。

これら 2 種類の COM クライアントを作成する作業はきわめて似ています。なぜなら,クライアントアプリケーションがサーバーオブジェクトへのインターフェースを取得し,そのプロパティとメソッドを使用するからです。Delphi は,COM クライアントの開発を容易にするために,コンポーネントラッパーにタイプライブラリまたは ActiveX コントロールをインポートし,サーバーオブジェクトをほかの VCL コンポーネントと同じように見せることができるようにしています。Delphi では,クライアント上のコンポーネントでサーバー CoClass をラップできます。このコンポーネントをコンポーネントパレットにインストールすることもできます。このようなコンポーネントラッパーのサンプルは,コンポーネントパレットの 2 ページにわたって表示されています。ActiveX ラッパーのサンプルは[ActiveX]ページに表示され,オートメーションオブジェクトのサンプルは[Servers]ページに表示されています。

コンポーネントラッパーでサーバーオブジェクトをラップしてコンポーネントパレットにインストールするように選択しない場合でも,アプリケーションがインターフェース定義を使用できるようにしなければなりません。そのために,サーバーの型情報をインポートできます。

クライアントは,COM オブジェクトが何を提供できるかを判断するために,そのオブジェクトのインターフェースに常に問い合わせることができます。すべての COM オブジェクトでは,既知のインターフェースをクライアントが要求できます。さらに,サーバーが IDispatch インターフェースをサポートする場合に,クライアントはそのインターフェースがサポートするメソッドについての情報をサーバーに問い合わせることができます。サーバーオブジェクトは,そのオブジェクトを使用するクライアントについて,何も予想しません。同様に,クライアントはオブジェクトがどのようにしてサービスを提供するかを知る必要がなく,サーバーオブジェクトがインターフェースに記述されているサービスを提供することだけに依存します。

COM 拡張機能

COM は,進化するにつれて基本的な COM サービスをはるかに超えて拡張されました。COM は,オートメーション,ActiveX コントロール,ActiveX ドキュメント,Active ディレクトリといったほかの技術の土台として機能します。さらに,大規模な分散環境において作業する場合に,トランザクション COM オブジェクトを作成することができます。Windows 2000 以前は,トランザクションオブジェクトは COM の構造の一部ではなく,MTS(Microsoft Transaction Server)環境で動作していました。このサポートは,Windows 2000 の時点で COM+ に統合されました。Delphi は,上記の技術を Delphi 環境で使用するアプリケーションを簡単に作成するためのウィザードを提供しています。

オートメーションサーバー

オートメーションとは,たとえば一度に複数のアプリケーションを操作できるマクロのように,アプリケーションが別のアプリケーションの中のオブジェクトをプログラム的に制御する能力です。操作対象のサーバーオブジェクトをオートメーションオブジェクトといい,オートメーションオブジェクトのクライアントをオートメーションコントローラと呼びます。オートメーションは,インプロセス,ローカル,リモートのどのサーバーでも使用できます。

オートメーションは,2 つの重要な点から定義されます。

  • オートメーションオブジェクトは一連のプロパティとコマンドを定義し,型記述によってその機能を記述します。この条件を満足するには,オブジェクトのインターフェース,インターフェースメソッド,メソッドの引数の情報を提供する手段を用意しなければならなりません。通常はこの情報はタイプライブラリで入手できます。オートメーションサーバーは,IDispatch インターフェースを介して問い合わせがあったときに型情報を動的に生成することもできます。
  • オートメーションオブジェクトは,ほかのアプリケーションが自分のメソッドにアクセスして使用できるようにします。このために IDispatch インターフェースを実装します。このインターフェースを経由すれば,オブジェクトはそのすべてのメソッドとプロパティをエクスポーズできます。型情報によってオブジェクトのメソッドがわかったら,このインターフェースの一次メソッドを使用してそのメソッドを呼び出せます。

オートメーション IDispatch インターフェースはマーシャリングのプロセスを自動化するので,開発者はよくオートメーションを使用して,任意のプロセス空間で動作する非ビジュアル OLE オブジェクトを作成および使用します。ただし,オートメーションを使用すると,利用できる型が制限されます。

Active X コントロール

Delphi のウィザードを使用すると,簡単に ActiveX コントロールを作成できます。ActiveX を使用すると,COM コンポーネント,特にコントロールを,よりコンパクトで効率的にすることができます。これは,クライアントがダウンロードして使用するイントラネットアプリケーション向けのコントロールに,特に重要です。

ActiveX コントロールは,インプロセスサーバーとしてのみ実行するビジュアルコントロールであり,ActiveX コントロールコンテナアプリケーションにプラグインできます。ActiveX コントロールそのものは完全なアプリケーションではありませんが,各種のアプリケーションで再使用可能な作成済み OLE コントロールとみなせます。ActiveX コントロールは,表示されるユーザーインターフェースを持ち,定義済みのインターフェースに依存して,入出力と表示の問題をホストコンテナとネゴシエートします。

ActiveX コントロールはオートメーションを使用してそのプロパティ,メソッド,イベントをエクスポーズします。ActiveX コントロールの機能には,イベントを送出し,データソースにバインドし,ライセンス付与をサポートする機能などがあります。

ActiveX コントロールの使い方の 1 つは,Web ページ内の対話型オブジェクトとして Web サイトに使用することです。このように,ActiveX は World Wide Web 用の対話型コンテンツをターゲットとする標準であり,Web ブラウザを経由して HTML 以外のドキュメントを表示するための ActiveX ドキュメントも使用されています。ActiveX 技術の詳細は,Microsoft ActiveX Web サイトを参照してください。

ActiveX ドキュメント

ActiveX ドキュメント(以前は OLE ドキュメントと呼ばれていました)は,リンクと埋め込み,ドラッグアンドドロップ,およびビジュアル編集をサポートする COM サービスのセットです。ActiveX ドキュメントは,形式が異なるデータまたはオブジェクト(サウンドクリップ,スプレッドシート,テキスト,ビットマップなど)をシームレスに統合できます。

ActiveX コントロールとは異なり,ActiveX ドキュメントはインプロセスサーバーに限定されずクロスプロセスアプリケーションでも使用できます。

また,オートメーションオブジェクトがビジュアルな場合はほとんどありませんが,ActiveX ドキュメントオブジェクトはほかのアプリケーションでビジュアルに操作できます。したがって,ActiveX ドキュメントオブジェクトは 2 種類の型のデータと関連付けられます。ディスプレイまたは出力デバイスでオブジェクトをビジュアルに表示するために使用されるプレゼンテーションデータと,オブジェクトの編集に使用されるネイティブデータです。

ActiveX ドキュメントオブジェクトは,ドキュメントコンテナの場合もドキュメントサーバーの場合もあります。Delphi は ActiveX ドキュメントを作成するための自動ウィザードを提供していませんが,VCL クラス Vcl.OleCtnrs.TOleContainer を使用すれば,既存の ActiveX ドキュメントのリンクと埋め込みをサポートできます。

Vcl.OleCtnrs.TOleContainer を ActiveX ドキュメントコンテナの土台として使用することもできます。ActiveX ドキュメントサーバー用のオブジェクトを作成するには,COM オブジェクトウィザードを使用し,オブジェクトがサポートする必要のあるサービスに応じて適切なインターフェースを実装します。ActiveX ドキュメントサーバーの作成と使い方の詳細は,Microsoft ActiveX Web サイトを参照してください。

メモ:  ActiveX ドキュメント仕様には,クロスプロセスアプリケーションにおけるマーシャリングのサポートが組み込まれていますが,ActiveX ドキュメントはマシン上のシステムに固有の型(ウィンドウハンドル,メニューハンドルなど)を使用するので,リモートサーバー上では実行されません。

トランザクションオブジェクト

Delphi では,(Windows 2000 より前のバージョンの Windows の場合は)MTS(Microsoft Transaction Server),または(Windows 2000 以降の場合は)COM+ が提供するトランザクションサービス,セキュリティ,およびリソース管理を利用するオブジェクトに対して「"トランザクションオブジェクト"」という用語を使用します。このオブジェクトは大規模な分散環境において機能するように設計されています。

トランザクションサービスは,アクティビティが常に完了またはロールバックされるようにする堅固さを提供します。サーバーがアクティビティを部分的に完了することはありません。セキュリティサービスを使用すると,さまざまなレベルのサポートをさまざまなクラスのクライアントにエクスポーズすることができます。リソース管理を使用すると,リソースプーリングによって,または使用時のみオブジェクトをアクティブにすることにより,より多くのクライアントをオブジェクトが処理できます。システムがこれらのサービスを提供できるようにするには,オブジェクトが IObjectControl インターフェースを実装しなければなりません。 トランザクションオブジェクトはこれらのサービスにアクセスするために,MTS または COM+ によって作成される IObjectContext というインターフェースを使用します。

MTS では,サーバーオブジェクトを DLL ライブラリに組み込み,このライブラリを MTS 実行時環境にインストールしなければなりません。つまり,サーバーオブジェクトとは,MTS 実行時プロセス空間において実行されるインプロセスサーバーです。COM+ では,すべての COM 呼び出しがインターセプタ経由で送られるので,この制約が当てはまりません。クライアントから見れば,MTS と COM+ の違いはありません。

MTS または COM+ サーバーは,同じプロセス空間で実行されるトランザクションオブジェクトをグループ化します。このグループは,MTS では MTS パッケージと呼ばれ,COM+ では COM+ アプリケーションと呼ばれます。1 つのマシンが複数の MTS パッケージ(または COM+ アプリケーション)を実行し,それぞれを個別のプロセス空間において実行することができます。

クライアントには,トランザクションオブジェクトはその他の COM サーバーオブジェクトと同じように見えます。クライアントは,トランザクションそのものを起動すること以外は,トランザクション,セキュリティ,または即時アクティブ化について知っている必要はありません。

MTS および COM+ はいずれも,トランザクションオブジェクトを管理するための独立したツールを提供します。このツールを使用すると,オブジェクトをパッケージまたは COM+ アプリケーションに設定し,1 台のコンピュータにインストールされたパッケージまたは COM+ アプリケーションを表示し,含まれているオブジェクトの属性を表示または変更し,トランザクションを監視および管理し,クライアントがオブジェクトを使用できるようにするなどのことができます。MTS では,このツールは MTS エクスプローラです。COM+ ではコンポーネントサービスです。

タイプライブラリ

タイプライブラリは,オブジェクトのインターフェースから調べる場合より多くのオブジェクトの型情報を取得するための手段を提供します。タイプライブラリに入っている型情報は,オブジェクトとそのインターフェースについて必要な情報を提供します。たとえば,どのオブジェクトにどのようなインターフェースが存在するか(CLSID を指定された場合),各インターフェースにどのようなメンバー関数が存在するか,それらの関数がどのような引数を必要とするか,などの情報が提供されます。

型情報は,オブジェクトの実行中インスタンスに問い合わせるか,タイプライブラリをロードして読み出せば入手できます。どのようなメンバー関数が必要で,それらのメンバー関数に何を渡すかがわかっていれば,この型情報を使用して,目的のオブジェクトを使用するためのクライアントを実装することができます。

オートメーションサーバー,ActiveX コントロール,およびトランザクションオブジェクトのクライアントは,型情報が使用可能であるものと予想します。COM オブジェクトウィザードはタイプライブラリを任意に作成しますが,Delphi のすべてのウィザードはタイプライブラリを自動的に生成します。この型情報は,タイプライブラリエディタ を使って表示および編集することができます。

関連項目