オブジェクト間通信

COM は、オブジェクトが同じプロセス、同じコンピューター、または別のコンピューターのどこで実行されているかに関係なく、クライアントがオブジェクトと透過的に通信できるように設計されています。 これにより、すべてのタイプのオブジェクト、およびオブジェクト クライアントとオブジェクト サーバーの両方に単一のプログラミング モデルが提供されます。

クライアントの観点から見ると、すべてのオブジェクトはインターフェイス ポインターを介してアクセスされます。 ポインターはインプロセスである必要があります。 実際、インターフェイス関数の呼び出しは常に、最初にインプロセス コードの一部に到達します。 オブジェクトがインプロセスである場合、呼び出しはシステム インフラストラクチャ コードを介さずに直接オブジェクトに到達します。 オブジェクトがアウトプロセスである場合、呼び出しはまず、COM またはオブジェクト (実装者が希望する場合) によって提供される、いわゆる「プロキシ」オブジェクトに到達します。 プロキシ パッケージはパラメーター (インターフェイス ポインタを含む) を呼び出し、オブジェクト実装が配置されている他のプロセスまたは他のコンピューターへの適切なリモート プロシージャ コール (またはカスタム生成プロキシの場合は他の通信メカニズム) を生成します。 プロセス境界を越えて伝送するためにポインターをパッケージ化するこのプロセスは、マーシャリングと呼ばれます。

サーバーの観点から見ると、オブジェクトのインターフェイス関数への呼び出しはすべて、そのインターフェイスへのポインターを通じて行われます。 繰り返しますが、ポインターは単一プロセス内でのみコンテキストを持ち、呼び出し元は常にプロセス内コードの一部である必要があります。 オブジェクトがインプロセスである場合、呼び出し元はクライアント自体です。 それ以外の場合、呼び出し元は、COM またはオブジェクト自体によって提供される「スタブ」オブジェクトです。 スタブは、クライアント プロセスの「プロキシ」からリモート プロシージャ コール (またはカスタム生成プロキシの場合は他の通信メカニズム) を受信し、パラメーターをアンマーシャリングして、サーバー オブジェクト上の適切なインターフェイスを呼び出します。 クライアントとサーバーの両方の観点から見ると、クライアントとサーバーは常に他のインプロセス コードと直接通信します。

COM は、標準マーシャリングと呼ばれるマーシャリングの実装を提供します。 この実装はほとんどのオブジェクトで非常にうまく機能し、プログラミング要件を大幅に軽減し、マーシャリング プロセスを事実上透過的にします。

ただし、COM のプロセス透過性の実装からインターフェイスを明確に分離すると、状況によっては邪魔になる場合があります。 クライアントの観点からその機能に焦点を当てたインターフェイスの設計は、ネットワーク全体でのそのインターフェイスの効率的な実装と矛盾する設計上の決定につながる可能性があります。 このような場合、必要なのは純粋なプロセスの透明性ではなく、「注意する必要がない限り、プロセスの透明性」です。COM は、オブジェクト 実装者がカスタム マーシャリング (IMarshal マーシャリングとも呼ばれます) をサポートできるようにすることで、この機能を提供します。 実際、標準マーシャリングはカスタム マーシャリングのインスタンスです。これは、オブジェクトがカスタム マーシャリングを必要としない場合に使用される既定の実装です。

カスタム マーシャリングを実装すると、オブジェクトがネットワーク経由で使用される場合、ローカル アクセス下で実行される場合とは異なるアクションを実行できるようになり、クライアントに対して完全に透過的になります。 このアーキテクチャにより、ネットワーク パフォーマンスの問題を考慮せずにクライアント/オブジェクト インターフェイスを設計し、その後、確立された設計を中断することなくネットワーク パフォーマンスの問題に対処することが可能になります。

COM はコンポーネントがどのように構造化されるかを指定しません。それはそれらがどのように相互作用するかを指定します。 COM では、コンポーネントの内部構造に関する懸念はプログラミング言語と開発環境に委ねられます。 逆に、プログラミング環境には、直接のアプリケーションの外部にあるオブジェクトを操作するための標準が設定されていません。 たとえば、Microsoft Visual C++ は、アプリケーション内のオブジェクトの操作では非常にうまく機能しますが、アプリケーションの外部のオブジェクトの操作はサポートされていません。 一般に、この点で他のすべてのプログラミング言語は同じです。 したがって、ネットワーク全体の相互運用性を提供するために、COM は言語に依存しないインターフェイスを通じて、プログラミング言語が中断したところから再開します。

vtbl 構造の二重間接指定は、関数ポインタのテーブル内のポインターが実際のオブジェクト内の実際の実装を直接指す必要がないことを意味します。 これがプロセスの透明性の中核です。

インプロセス サーバーの場合、オブジェクトがクライアント プロセスに直接ロードされるため、テーブル内の関数ポインターは実際の実装を直接指します。 この場合、クライアントからインターフェイス メソッドへの関数呼び出しにより、実行制御がメソッドに直接転送されます。 ただし、プロセス間でメモリへのポインターを共有できないため、これはローカル オブジェクトやリモート オブジェクトに対しては機能しません。 それにもかかわらず、クライアントは実際の実装を呼び出しているかのようにインターフェイス メソッドを呼び出すことができなければなりません。 したがって、クライアントは呼び出しを行うことによって、あるオブジェクトのメソッドに制御を均一に転送します。

クライアントは常に、何らかのインプロセス オブジェクトのインターフェイス メソッドを呼び出します。 実際のオブジェクトがローカルまたはリモートの場合、呼び出しはプロキシ オブジェクトに対して行われ、プロキシ オブジェクトは実際のオブジェクトに対してリモート プロシージャ コールを行います。

では、実際に実行されるメソッドは何でしょうか。 その答えは、アウトプロセス インターフェイスへの呼び出しがあるたびに、各インターフェイス メソッドがプロキシ オブジェクトによって実装されるということです。 プロキシ オブジェクトは常に、呼び出されるオブジェクトに代わって動作するインプロセス オブジェクトです。 このプロキシ オブジェクトは、実際のオブジェクトがローカル サーバーまたはリモート サーバーで実行されていることを認識します。

プロキシ オブジェクトは、関数パラメーターをいくつかのデータ パケットにパッケージ化し、ローカルまたはリモート オブジェクトへの RPC 呼び出しを生成します。 そのパケットは、ローカルまたはリモート コンピューター上のサーバー プロセス内のスタブ オブジェクトによって取得され、パラメーターが解凍され、メソッドの実際の実装が呼び出されます。 その関数が戻ると、スタブは出力パラメーターと戻り値をパッケージ化してプロキシに送り返し、プロキシはそれらを解凍して元のクライアントに返します。

したがって、クライアントとサーバーは常に、すべてが処理中であるかのように相互に通信します。 クライアントからの呼び出しとサーバーへのすべての呼び出しは、ある時点でインプロセスとなります。 ただし、vtbl 構造では、COM などの一部のエージェントがすべての関数呼び出しと関数からの戻り値をすべてインターセプトできるため、そのエージェントは必要に応じてそれらの呼び出しを RPC 呼び出しにリダイレクトできます。 インプロセス呼び出しはアウトプロセス呼び出しよりも高速ですが、プロセスの違いはクライアントとサーバーにとって完全に透過的です。

詳細については、次のトピックを参照してください。

COM クライアントとサーバー

インターフェイス マーシャリング