IMarshal インターフェイス (objidl.h)
COM オブジェクトがインターフェイス ポインターのマーシャリングを定義および管理できるようにします。
継承
IMarshal インターフェイスは、IUnknown インターフェイスから継承されます。 IMarshal には、次の種類のメンバーもあります。
メソッド
IMarshal インターフェイスには、これらのメソッドがあります。
IMarshal::D isconnectObject IMarshal::D isconnectObject メソッド (objidl.h) は、シャットダウンする前にオブジェクトへのすべての接続を解放します。 |
IMarshal::GetMarshalSizeMax マーシャリング中に必要となるバッファーの最大サイズを取得します。 |
IMarshal::GetUnmarshalClass マーシャリング解除コードの CLSID を取得します。 |
IMarshal::MarshalInterface IMarshal::MarshalInterface メソッド (objidl.h) はインターフェイス ポインターをマーシャリングします。 |
IMarshal::ReleaseMarshalData IMarshal::ReleaseMarshalData メソッド (objidl.h) は、マーシャリングされたデータ パケットを破棄します。 |
IMarshal::UnmarshalInterface IMarshal::UnmarshalInterface メソッド (objidl.h) はインターフェイス ポインターをアンマーサルします。 |
注釈
マーシャリング とは、データをパケットにパッケージ化して、別のプロセスまたはコンピューターに送信するプロセスです。 アンマーシャリングは、受信側でそのデータを復旧するプロセスです。 任意の呼び出しでは、メソッド引数は一方向にマーシャリングされ、マーシャリングされませんが、戻り値はマーシャリングされ、もう一方の方向ではマーシャリングされません。
マーシャリングはすべてのデータ型に適用されますが、インターフェイス ポインターには特別な処理が必要です。 基本的な問題は、1 つのアドレス空間で実行されているクライアント コードが、異なるアドレス空間に存在するオブジェクト上のインターフェイスへのポインターを正しく逆参照する方法です。 COM ソリューションは、クライアント アプリケーションが代理オブジェクト (クライアントのプロセスに含まれるプロキシ) を介して元のオブジェクトと通信することです。 プロキシは、元のオブジェクトのインターフェイスへの参照を保持し、クライアント自体のインターフェイスへのポインターをクライアントに提供します。 クライアントが元のオブジェクトでインターフェイス メソッドを呼び出すと、その呼び出しは実際にはプロキシに送信されます。 したがって、クライアントの観点からは、すべての呼び出しが処理中です。
呼び出しを受信すると、プロキシはメソッド引数をマーシャリングし、RPC などのプロセス間通信のいくつかの手段を通じて、それらをサーバー プロセス内のコードに渡し、引数のマーシャリングを解除して元のオブジェクトに渡します。 この同じコードは、プロキシへの転送の戻り値をマーシャリングし、値のマーシャリングを解除してクライアント アプリケーションに渡します。
IMarshal には、クライアント プロセスでプロキシを作成、初期化、および管理するためのメソッドが用意されています。プロキシが元のオブジェクトと通信する方法は指定されません。 IMarshal の COM の既定の実装では、RPC が使用されます。 このインターフェイスを自分で実装すると、アプリケーションに適していると思われるプロセス間通信の方法 (共有メモリ、名前付きパイプ、ウィンドウ ハンドル、RPC など) を自由に選択できます。要するに、動作するものは何でもかまいません。
IMarshal の既定の実装
COM は 、IMarshal インターフェイスの独自の内部実装を使用して、独自の実装を提供しないオブジェクトをマーシャリングします。 COM は、 IMarshal のオブジェクトに対してクエリを実行することで、この決定を行います。 インターフェイスがない場合、COM は既定で内部実装に設定されます。IMarshal の COM の既定の実装では、オブジェクトごとに汎用プロキシが使用され、オブジェクトに実装されているインターフェイスごとに、必要に応じて個々のスタブとプロキシが作成されます。 特定のオブジェクトが実装できる特定のインターフェイスを COM が事前に認識できないため、このメカニズムが必要です。 COM の既定のマーシャリングを使用しない開発者は、代わりに独自のプロキシおよびマーシャリング ルーチンを記述することを選択します。コンパイル時に、オブジェクトで見つかるすべてのインターフェイスを把握し、マーシャリング コードが必要な内容を正確に理解します。 COM は、すべてのオブジェクトのマーシャリング サポートを提供する際に、実行時にこれを行う必要があります。
インターフェイス プロキシはクライアント プロセスに存在します。インターフェイス スタブはサーバーに存在します。 各ペアは、インターフェイスのすべてのマーシャリングを一緒に処理します。 各インターフェイス プロキシのジョブは、引数をマーシャリングし、そのインターフェイスへの後続の呼び出しで前後に渡される戻り値と出力パラメーターをマーシャリングすることです。 各インターフェイス スタブのジョブは、関数引数のマーシャリングを解除し、元のオブジェクトに渡してから、オブジェクトが返す戻り値と out パラメーターをマーシャリングすることです。
プロキシとスタブは、プロセス間通信にシステムの RPC インフラストラクチャを利用する RPC (リモート プロシージャ コール) チャネルによって通信します。 RPC チャネルは、インターフェイス プロキシとスタブの両方がポインターを保持する単一のインターフェイス IRpcChannelBuffer を実装します。 プロキシとスタブはインターフェイスを呼び出してマーシャリング パケットを取得し、対応するパケットにデータを送信し、完了したらパケットを破棄します。 インターフェイス スタブには、元のオブジェクトへのポインターも保持されます。
任意のインターフェイスに対して、プロキシとスタブはどちらも同じクラスのインスタンスとして実装されます。このインスタンスは、システム レジストリの各インターフェイスの ProxyStubClsid32 というラベルの下に一覧表示されます。 このエントリは、インターフェイスの IID を、そのプロキシ オブジェクトとスタブ オブジェクトの CLSID に マップします。 COM がインターフェイスをマーシャリングする必要がある場合は、システム レジストリで適切な CLSID を取得します。 この CLSID によって識別されるサーバーは、インターフェイス プロキシとインターフェイス スタブの両方を実装します。
ほとんどの場合、この CLSID が参照するクラスは、特定のインターフェイスの関数シグネチャとセマンティクスの説明を入力するツールによって自動的に生成されます。これは、いくつかのインターフェイス記述言語で記述されます。 このような言語を使用することを強くお勧めしますが、精度のために推奨されますが、そうする必要はありません。 プロキシとスタブは、RPC インフラストラクチャで使用される COM コンポーネントに過ぎず、適切な外部コントラクトが保持されている限り、任意の方法で記述できます。 新しいインターフェイスを設計するプログラマは、存在するすべてのインターフェイス プロキシとスタブが、マーシャリングされたデータの表現に確実に一致することを保証する責任があります。
作成すると、インターフェイス プロキシは常に、オブジェクト全体を表すより大きなプロキシに集約されます。 このオブジェクト プロキシは、プロキシ マネージャーと呼ばれる COM 汎用プロキシ オブジェクトも集計 します。 プロキシ マネージャーは、 IUnknown と IMarshal の 2 つのインターフェイスを実装します。 オブジェクトに実装できる他のすべてのインターフェイスは、個々のインターフェイス プロキシの集計を通じて、オブジェクト プロキシで公開されます。 オブジェクト プロキシへのポインターを保持しているクライアントは、実際のオブジェクトへのポインターを保持していると"信じています"。
オブジェクト全体を表すプロキシは、クライアントがまったく異なるオブジェクトに実装されている同じインターフェイスへの呼び出しを区別できるように、クライアント プロセスで必要です。 ただし、このような要件は、オブジェクト自体が存在するサーバー プロセスには存在しません。すべてのインターフェイス スタブは、作成されたオブジェクトとのみ通信するためです。 他の接続はできません。
インターフェイス スタブは、インターフェイス プロキシとは対照的に、一部の外部クライアントに大きな全体の一部として表示される必要がないため、集計されません。 接続すると、インターフェイス スタブには、受信したメソッド呼び出しを転送するサーバー オブジェクトへのポインターが与えられます。 スタブ マネージャーを概念的に参照すると便利です。つまり、特定のオブジェクトのリモート処理にサービスを提供するサーバー側 RPC インフラストラクチャ内のコードと状態が何であれ、コードと状態が特定の適切に指定された形式を取るという直接的な要件はありません。
クライアントが特定のオブジェクトのインターフェイスへのポインターを初めて要求すると、COM はサーバー プロセスで IClassFactory スタブを読み込み、それを使用して最初のポインターをクライアントにマーシャリングします。 クライアント プロセスでは、COM はクラス ファクトリ オブジェクトのジェネリック プロキシを読み込み、 IMarshal の実装を呼び出して最初のポインターをアンマーサルします。 その後、COM は最初のインターフェイス プロキシを作成し、RPC チャネルへのポインターを渡します。 最後に、COM はクライアントへの IClassFactory ポインターを返します。このポインターを使用して IClassFactory::CreateInstance を呼び出し、インターフェイスへの参照を渡します。
サーバー プロセスに戻ると、COM によって、要求されたインターフェイスのスタブと共に、 オブジェクトの新しいインスタンスが作成されるようになりました。 このスタブは、インターフェイス ポインターを、別のオブジェクト プロキシが作成されたクライアント プロセスにマーシャリングし、今度はオブジェクト自体にマーシャリングします。 また、要求されたインターフェイスのプロキシ (クライアントに返される へのポインター) も作成されます。 オブジェクト上の他のインターフェイスに対する後続の呼び出しにより、COM は必要に応じて適切なインターフェイス スタブとプロキシを読み込みます。
新しいインターフェイス プロキシが作成されると、COM はプロキシ マネージャーの IUnknown の実装へのポインターを提供します。このポインターは、すべての QueryInterface 呼び出しを委任します。 各インターフェイス プロキシは、それ自体の 2 つのインターフェイス (それが表すインターフェイスと IRpcProxyBuffer) を実装します。 インターフェイス プロキシは、独自のインターフェイスをクライアントに直接公開します。このインターフェイスは、プロキシ マネージャーで QueryInterface を 呼び出すことによってポインターを取得できます。 ただし、COM のみが IRpcProxyBuffer を呼び出すことができます。これは、プロキシを RPC チャネルに接続して切断するために使用されます。 クライアントはインターフェイス プロキシに対してクエリを実行して 、IRpcProxyBuffer インターフェイスへのポインターを取得できません。
サーバー側では、各インターフェイス スタブによって IRpcStubBuffer が実装されます。 スタブ マネージャーとして機能するサーバー コードは 、IRpcStubBuffer::Connect を呼び出し、インターフェイス スタブをそのオブジェクトの IUnknown ポインターに 渡します。
インターフェイス プロキシは、メソッド呼び出しを受信すると、 IRpcChannelBuffer::GetBuffer の呼び出しを介して RPC チャネルからマーシャリング パケットを取得します。 引数をマーシャリングするプロセスでは、データがバッファーにコピーされます。 マーシャリングが完了すると、インターフェイス プロキシは IRpcChannelBuffer::SendReceive を呼び出して、マーシャリングされたパケットを対応するインターフェイス スタブに送信します。 IRpcChannelBuffer::SendReceive が返されると、引数がマーシャリングされたバッファーは、インターフェイス スタブからマーシャリングされた戻り値を含む新しいバッファーに置き換えられます。 インターフェイス プロキシは戻り値をアンマーシャリングし、 IRpcChannelBuffer::FreeBuffer を呼び出してバッファーを解放し、戻り値を メソッドの元の呼び出し元に返します。
実際にサーバー プロセスに要求を送信し、そのプロセス内で要求を送信するオブジェクトを識別する IRpcChannelBuffer::SendReceive の実装です。 チャネルの実装では、そのプロセスの適切なスタブ マネージャーに要求を転送する方法も認識されます。 インターフェイス スタブは、指定されたバッファーから引数をアンマーシャリングし、サーバー オブジェクトで指定されたメソッドを呼び出し、戻り値を IRpcChannelBuffer::GetBuffer の呼び出しによって割り当てられた新しいバッファーにマーシャリングします。 その後、チャネルは、インターフェイス プロキシに戻る戻りデータ パケットを送信します。これは、インターフェイス プロキシに戻る IRpcChannelBuffer::SendReceive の途中にあります。
インターフェイス プロキシの特定のインスタンスは、次の条件が満たされている限り、複数のインターフェイスにサービスを提供するために使用できます。
- 影響を受けるインターフェイスの ID は、システム レジストリ内の適切な ProxyStubClsid にマップする必要があります。
- インターフェイス プロキシは、通常どおり、サポートされているインターフェイスから他のインターフェイスへの QueryInterface の呼び出しと、 IUnknown および IRpcProxyBuffer からの呼び出しをサポートする必要があります。
プロキシとスタブでは、さまざまな場合にメモリを割り当てるか解放する必要があります。 たとえば、インターフェイス プロキシでは、呼び出し元にパラメーターを返すメモリを割り当てる必要があります。 この点で、インターフェイス プロキシとインターフェイス スタブは、標準タスク アロケーターを使用する必要がある点で、通常の COM コンポーネントにすぎません。 ( 「CoGetMalloc」を参照)。
要件
要件 | 値 |
---|---|
サポートされている最小のクライアント | Windows 2000 Professional [デスクトップ アプリ |UWP アプリ] |
サポートされている最小のサーバー | Windows 2000 Server [デスクトップ アプリ |UWP アプリ] |
対象プラットフォーム | Windows |
ヘッダー | objidl.h (ObjIdl.h を含む) |