インターフェイスの登録
このセクションでは、RPC インターフェイスを登録するプロセスの詳細について説明します。
このセクションの情報は、次のトピックで説明します。
- インターフェイス登録関数
- エントリ ポイント ベクトル
- マネージャー EPV
- インターフェイスの単一実装の登録
- インターフェイスの複数の実装の登録
- Manager ルーチンの呼び出しに関する規則
- Server-Manager ルーチンへのリモート プロシージャ コールのディスパッチ
- 独自のObject-Inquiry関数を提供する
インターフェイス登録関数
サーバーは 、RpcServerRegisterIf 関数を呼び出してインターフェイスを登録します。 複雑なサーバー プログラムでは、多くの場合、複数のインターフェイスがサポートされます。 サーバー アプリケーションは、サポートするインターフェイスごとにこの関数を 1 回呼び出す必要があります。
また、サーバーは同じインターフェイスの複数のバージョンをサポートでき、それぞれインターフェイスの関数を独自に実装できます。 サーバー プログラムでこれを行う場合は、一連のエントリ ポイントを指定する必要があります。 エントリ ポイントは、インターフェイスのバージョンの呼び出しをディスパッチするマネージャー ルーチンです。 インターフェイスのバージョンごとに 1 つのエントリ ポイントが必要です。 エントリ ポイントのグループは、エントリ ポイント ベクトルと呼ばれます。 詳細については、「 エントリ ポイント ベクトル」を参照してください。
RPC では、標準関数 RpcServerRegisterIf に加えて、他のインターフェイス登録関数もサポートされています。 RpcServerRegisterIf2 関数は、登録フラグのセット (「インターフェイス登録フラグ」を参照)、サーバーが受け入れられる同時リモート プロシージャ 呼び出し要求の最大数、および受信データ ブロックの最大サイズ (バイト単位) を指定できるようにすることで、RpcServerRegisterIf の機能を拡張します。
RPC ライブラリには、 RpcServerRegisterIfEx という関数も含まれています。 RpcServerRegisterIf 関数と同様に、この関数はインターフェイスを登録します。 サーバー プログラムでは、この関数を使用して、登録フラグのセット ( 「インターフェイス登録フラグ」を参照)、サーバーが受け入れられる同時リモート プロシージャ 呼び出し要求の最大数、およびセキュリティ コールバック関数を指定することもできます。
RpcServerRegisterIf、RpcServerRegisterIfEx、および RpcServerRegisterIf2 関数は、内部インターフェイス レジストリ テーブルに値を設定します。 このテーブルは、インターフェイス UUID とオブジェクト UUID をマネージャー EPV にマップするために使用されます。 マネージャー EPV は、IDL ファイルで指定されたインターフェイス内の関数プロトタイプごとに 1 つの関数ポインターを含む関数ポインターの配列です。
インターフェイスの複数の実装を提供するために複数の EPV を提供する方法については、「 複数のインターフェイスの実装」を参照してください。
ランタイム ライブラリは、インターフェイス レジストリ テーブル (関数 RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 の呼び出しによって設定) とオブジェクト レジストリ テーブル (関数 RpcObjectSetType の呼び出しによって設定) を使用して、インターフェイスとオブジェクト UUID を関数ポインターにマップします。
サーバー プログラムで RPC ランタイム ライブラリ レジストリからインターフェイスを削除する場合は、 RpcServerUnregisterIf 関数を呼び出します。 インターフェイスがレジストリから削除されると、RPC ランタイム ライブラリはそのインターフェイスの新しい呼び出しを受け入れなくなります。
エントリ ポイント ベクトル
マネージャー エントリ ポイント ベクター (EPV) は、IDL ファイルで指定された関数の実装を指す関数ポインターの配列です。 配列内の要素の数は、IDL ファイルで指定された関数の数に対応します。 RPC では、インターフェイスで指定された関数の複数の実装を表す複数のエントリ ポイント ベクトルがサポートされています。
MIDL コンパイラは、マネージャー EPV の構築に使用するマネージャー EPV データ型を自動的に生成します。 データ型の名前は if-name**_SERVER_EPV**です。 ここで、if-name は IDL ファイル内のインターフェイス識別子を指定します。
MIDL コンパイラは、インターフェイス内の各プロシージャに同じ名前のマネージャー ルーチンが存在し、IDL ファイルで指定されていることを前提として、既定のマネージャー EPV を自動的に作成および初期化します。
サーバーが同じインターフェイスの複数の実装を提供する場合、サーバーは実装ごとに 1 つの追加のマネージャー EPV を作成する必要があります。 各 EPV には、IDL ファイルで定義されている各プロシージャのエントリ ポイント (関数のアドレス) を正確に 1 つ含める必要があります。 サーバー アプリケーションは、インターフェイスの追加実装ごとに 、if-name**_SERVER_EPV** 型の 1 つのマネージャー EPV 変数を宣言して初期化します。 EPV を登録するには、サポートするオブジェクトの種類ごとに RpcServerRegisterIf、 RpcServerRegisterIfEx、または RpcServerRegisterIf2 を 1 回呼び出します。
クライアントがサーバーに対してリモート プロシージャ 呼び出しを行うと、インターフェイス UUID とオブジェクトの種類に基づいて、関数ポインターを含む EPV が選択されます。 オブジェクト型は、オブジェクト照会関数または RpcObjectSetType によって制御されるテーブルドリブン マッピングによってオブジェクト UUID から派生します。
マネージャー EPV
既定では、MIDL コンパイラはインターフェイスの IDL ファイルのプロシージャ名を使用してマネージャー EPV を生成します。これは、コンパイラがサーバー スタブに直接配置します。 この既定の EPV は、インターフェイス定義で宣言されたプロシージャ名を使用して静的に初期化されます。
既定の EPV を使用してマネージャーを登録するには、RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 関数の呼び出しで、MgrEpv パラメーターの値として NULL を指定します。 マネージャーによって使用されるルーチン名がインターフェース定義のルーチン名に対応している場合は、MIDL コンパイラーによって生成されるインターフェースのデフォルト EPV を使用して、このマネージャーを登録できます。 サーバー アプリケーションが提供する EPV を使用してマネージャーを登録することもできます。
サーバーは、インターフェイスに対して null 以外のマネージャー EPV を作成して登録できます (また、必要な場合もあります)。 サーバー アプリケーションから提供される EPV を選択するには、サーバーによって値が宣言されている EPV のアドレスを MgrEpv パラメーターの値として渡します。 MgrEpv パラメーターの null 以外の値は、常にサーバー スタブの既定の EPV をオーバーライドします。
MIDL コンパイラは、マネージャー EPV の構築に使用するサーバー アプリケーション用のマネージャー EPV データ型 (RPC_MGR_EPV) を自動的に生成します。 マネージャー EPV には、IDL ファイルで定義されている各プロシージャーに対して、1 つのエントリー・ポイント (関数アドレス) を含める必要があります。
サーバーは、次の場合に null 以外の EPV を指定する必要があります。
- マネージャー ルーチンの名前がインターフェイス定義で宣言されているプロシージャ名と異なる場合
- サーバーがインターフェイスの別の実装を登録するために既定の EPV を使用する場合
サーバーは、インターフェイスの実装ごとに if-name**_SERVER_EPV** 型の変数を初期化することで、マネージャー EPV を宣言します。
インターフェイスの単一実装の登録
サーバーがインターフェイスの実装を 1 つだけ提供する場合、サーバーは RpcServerRegisterIf、 RpcServerRegisterIfEx、または RpcServerRegisterIf2 を 1 回だけ呼び出します。 標準の場合、サーバーは既定のマネージャー EPV を使用します。 (例外は、マネージャーが インターフェイスで宣言されているものとは異なるルーチン名を使用する場合です)。
標準のケースでは、RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 の呼び出しに次の値を指定します。
マネージャー EPV
既定の EPV を使用するには、MgrEpv パラメーターに null 値を指定します。
マネージャーの種類 UUID
既定の EPV を使用する場合は、パラメーター MgrTypeUuid に null 値または nil UUID を指定して、インターフェイスを nil マネージャー型 UUID に登録します。 この場合、バインド ハンドル内のオブジェクト UUID に関係なく、すべてのリモート プロシージャ呼び出しは、 RpcObjectSetType 呼び出しが行われなかったと仮定して、既定の EPV にディスパッチされます。
nil 以外のマネージャー型 UUID を指定することもできます。 この場合は、 RpcObjectSetType ルーチンも呼び出す必要があります。
インターフェイスの複数の実装の登録
IDL ファイルで指定されたリモート プロシージャの複数の実装を指定できます。 サーバー アプリケーションは RpcObjectSetType を呼び出してオブジェクト UUID を型 UUID にマップし、 RpcServerRegisterIf、 RpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出して、マネージャー EPV を UUID 型に関連付けます。 リモート プロシージャ コールがオブジェクト UUID と共に到着すると、RPC サーバーランタイム ライブラリはオブジェクト UUID を型 UUID にマップします。 その後、サーバー アプリケーションは UUID 型とインターフェイス UUID を使用して、マネージャー EPV を選択します。
独自の関数を指定して、オブジェクト UUID からマネージャー型 UUID へのマッピングを解決することもできます。 RpcObjectSetInqFn を呼び出すときにマッピング関数を指定します。
インターフェイスの複数の実装を提供するには、サーバーで RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 を個別に呼び出して、各実装を登録する必要があります。 サーバーが登録する実装ごとに、同じ IfSpec パラメーターが提供されますが、 MgrTypeUuid パラメーターと MgrEpv パラメーターのペアは異なります。
複数のマネージャーの場合は、次のように RpcServerRegisterIf、 RpcServerRegisterIfEx 、または RpcServerRegisterIf2 を使用します。
マネージャー EPV
インターフェイスの複数の実装を提供するには、サーバーで次の手順を実行する必要があります。
- 追加の実装ごとに null 以外のマネージャー EPV を作成します。
- RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 で MgrEpv パラメーターに null 以外の値を指定します。
サーバーは、既定のマネージャー EPV に登録することもできます。
マネージャーの種類 UUID
インターフェイスの各 EPV にマネージャーの種類 UUID を指定します。 MgrTypeUuid パラメーターの nil 型 UUID (または null 値) は、いずれかのマネージャー EPV に対して指定できます。 各種類の UUID は異なっている必要があります。
Manager ルーチンの呼び出しに関する規則
RPC ランタイム ライブラリは、要求された RPC インターフェイスを提供するマネージャーに着信リモート プロシージャ コールをディスパッチします。 1 つのインターフェイスに複数のマネージャーが登録されている場合、RPC ランタイム ライブラリでいずれか 1 つを選択する必要があります。 マネージャーを選択するために、RPC ランタイム ライブラリは、呼び出しのバインド ハンドルで指定されたオブジェクト UUID を使用します。
ランタイム ライブラリは、リモート プロシージャ コールのオブジェクト UUID を解釈するときに、次の規則を適用します。
Nil オブジェクト UUID
nil オブジェクト UUID には、nil 型 UUID が自動的に割り当てられます ( RpcObjectSetType ルーチンで nil オブジェクト UUID を指定することは無効です)。 したがって、バインド ハンドルに nil オブジェクト UUID が含まれるリモート プロシージャ コールは、nil 型 UUID に登録されているマネージャー (存在する場合) に自動的にディスパッチされます。
nil 以外のオブジェクト UUID
原則として、バインド ハンドルに nil 以外のオブジェクト UUID が含まれるリモート プロシージャ コールは、型 UUID がオブジェクト UUID の型と一致するマネージャーによって処理される必要があります。 ただし、正しいマネージャーを識別するには、 RpcObjectSetType ルーチンを呼び出して、サーバーがそのオブジェクト UUID の型を指定している必要があります。
サーバーが nil 以外のオブジェクト UUID に対して RpcObjectSetType ルーチンを呼び出すのに失敗した場合、そのオブジェクト UUID のリモート プロシージャ コールは、nil オブジェクト UUID (つまり nil 型 UUID) を使用してリモート プロシージャ 呼び出しを処理するマネージャー EPV に送信されます。
バインド ハンドル内の nil 以外のオブジェクト UUID を使用したリモート プロシージャ 呼び出しは、サーバーが RpcObjectSetType ルーチンを呼び出してその非 nil オブジェクト UUID に型 UUID を割り当てたが、RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出して、その型 UUID のマネージャー EPV も登録しなかった場合は実行できません。
次の表は、ランタイム ライブラリがマネージャー ルーチンを選択するために使用するアクションをまとめたものです。
呼び出しのオブジェクト UUID | オブジェクト UUID のサーバー セットの種類 | サーバー登録済み EPV の種類 | ディスパッチ アクション |
---|---|---|---|
Nil | 適用なし | はい | マネージャーを nil 型 UUID と共に使用します。 |
Nil | 利用不可 | いいえ | エラー (RPC_S_UNSUPPORTED_TYPE);はリモート プロシージャ コールを拒否します。 |
非 nil | はい | はい | 同じ種類の UUID を持つマネージャーを使用します。 |
非 nil | いいえ | 無視 | マネージャーを nil 型 UUID と共に使用します。 nil 型 UUID を持つマネージャーがない場合は、エラー (RPC_S_UNSUPPORTEDTYPE);はリモート プロシージャ コールを拒否します。 |
非 nil | はい | いいえ | エラー (RPC_S_UNSUPPORTEDTYPE);はリモート プロシージャ コールを拒否します。 |
呼び出しのオブジェクト UUID は、リモート プロシージャ 呼び出しのバインド ハンドルで見つかったオブジェクト UUID です。
サーバーは 、RpcObjectSetType を呼び出してオブジェクトの UUID 型を指定することで、オブジェクト UUID の型を設定します。
サーバーは、同じ種類の UUID を使用して RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出して、マネージャー EPV の型を登録します。
Note
nil オブジェクト UUID には、常に nil 型 UUID が自動的に割り当てられます。 RpcObjectSetType ルーチンで nil オブジェクト UUID を指定することは無効です。
サーバー マネージャー ルーチンへのリモート プロシージャ コールのディスパッチ
次の表は、RPC ランタイム ライブラリがリモート プロシージャ コールをサーバー マネージャー ルーチンにディスパッチするために実行する手順を示しています。
サーバーが既定のマネージャー EPV を登録する単純なケースを次の表に示します。
インターフェイス レジストリ テーブル
インターフェイス UUID | マネージャーの種類 UUID | エントリ ポイント ベクター |
---|---|---|
uuid1 | Nil | 既定の EPV |
オブジェクト レジストリ テーブル
オブジェクト UUID | オブジェクトの種類 |
---|---|
Nil | Nil |
(その他のオブジェクト UUID) | Nil |
バインディング ハンドルをエントリ ポイント ベクター (EPV) にマッピングする
インターフェイス UUID (クライアント バインド ハンドルから) | オブジェクト UUID (クライアント バインド ハンドルから) | オブジェクトの種類 (オブジェクト レジストリ テーブルから) | Manager EPV (インターフェイス レジストリ テーブルから) |
---|---|---|---|
uuid1 | Nil | Nil | 既定の EPV |
同上 | uuidA | Nil | 既定の EPV |
次の手順では、上記の表に示すように、RPC サーバーのランタイム ライブラリがインターフェイス UUID uuid1 を持つクライアントがそれを呼び出すときに実行するアクションについて説明します。
サーバーは RpcServerRegisterIf、 RpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出して、提供するインターフェイスを nil マネージャーの種類 UUID と MIDL によって生成された既定のマネージャー EPV に関連付けます。 この呼び出しにより、インターフェイス レジストリ テーブルにエントリが追加されます。 インターフェイス UUID は IfSpec a パラメーターに含まれています。
既定では、オブジェクト レジストリ テーブルは、すべてのオブジェクト UUID を nil 型 UUID に関連付けます。 この例では、サーバーは RpcObjectSetType を呼び出しません。
サーバー ランタイム ライブラリは、呼び出しが属しているインターフェイス UUID と、呼び出しのバインド ハンドルからオブジェクト UUID を含むリモート プロシージャ コードを受け取ります。
オブジェクト UUID をバインド ハンドルに設定する方法については、次の関数参照エントリを参照してください。
サーバーのランタイム ライブラリは、リモート プロシージャ コールのインターフェイス UUID を使用して、インターフェイス レジストリ テーブルでそのインターフェイス UUID を見つけます。
サーバーが RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 を使用してインターフェイスを登録しなかった場合、リモート プロシージャ呼び出しは、RPC_S_UNKNOWN_IF状態コードを使用して呼び出し元に戻ります。
バインド ハンドルのオブジェクト UUID を使用すると、サーバーのランタイム ライブラリによって、そのオブジェクト UUID がオブジェクト レジストリ テーブル内で検索されます。 この例では、すべてのオブジェクト UUID が nil オブジェクト型にマップされます。
サーバーのランタイム ライブラリは、インターフェイス レジストリ テーブルで nil マネージャーの種類を検索します。
インターフェイス レジストリ テーブルでインターフェイス UUID と nil 型を組み合わせると、既定の EPV に解決されます。この EPV には、リモート プロシージャ コールで見つかったインターフェイス UUID に対して実行されるサーバー マネージャー ルーチンが含まれます。
次の表で説明するように、サーバーが各インターフェイスの複数のインターフェイスと複数の実装を提供するとします。
インターフェイス レジストリ テーブル
インターフェイス UUID | マネージャーの種類の UUID | エントリ ポイント ベクター |
---|---|---|
uuid1 | Nil | epv1 |
uuid1 | uuid3 | epv4 |
uuid2 | uuid4 | epv2 |
uuid2 | uuid7 | epv3 |
オブジェクト レジストリ テーブル
オブジェクト UUID | オブジェクトの種類 |
---|---|
uuidA | uuid3 |
uuidB | uuid7 |
uuidC | uuid7 |
uuidD | uuid3 |
uuidE | uuid3 |
uuidF | uuid8 |
Nil | Nil |
(その他の UUID) | Nil |
バインディング ハンドルをエントリ ポイント ベクターにマッピングする
インターフェイス UUID (クライアント バインド ハンドルから) | オブジェクト UUID (クライアント バインド ハンドルから) | オブジェクトの種類 (オブジェクト レジストリ テーブルから) | Manager EPV (インターフェイス レジストリ テーブルから) |
---|---|---|---|
uuid1 | Nil | Nil | epv1 |
uuid1 | uuidA | uuid3 | epv4 |
uuid1 | uuidD | uuid3 | epv4 |
uuid1 | uuidE | uuid3 | epv4 |
uuid2 | uuidB | uuid7 | epv3 |
uuid2 | uuidC | uuid7 | epv3 |
次の手順では、インターフェイス UUID uuid2 とオブジェクト UUID uuidC を持つクライアントがクライアントを呼び出したときに、サーバーのランタイム ライブラリが実行するアクションについて説明します。
サーバーは RpcServerRegisterIf、 RpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出して、提供するインターフェイスを別のマネージャー EPV に関連付けます。 インターフェイス レジストリ テーブルのエントリには、RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 の 4 つの呼び出しが反映され、各インターフェイスに対して 2 つの実装 (EPV) が含まれる 2 つのインターフェイスが提供されます。
サーバーは RpcObjectSetType を呼び出して、提供する各オブジェクトの型を確立します。 nil オブジェクトと nil 型の既定の関連付けに加えて、オブジェクト レジストリ テーブルに明示的に見つからない他のすべてのオブジェクト UUID も nil 型 UUID にマップされます。
この例では、サーバーは RpcObjectSetType ルーチンを 6 回呼び出します。
サーバー ランタイム ライブラリは、呼び出しが属しているインターフェイス UUID と、呼び出しのバインド ハンドルからオブジェクト UUID を含むリモート プロシージャ コールを受け取ります。
リモート プロシージャ コールのインターフェイス UUID を使用して、サーバーのランタイム ライブラリによってインターフェイス UUID がインターフェイス レジストリ テーブル内で検索されます。
バインド ハンドルから uuidC オブジェクト UUID を使用すると、サーバーのランタイム ライブラリによってオブジェクト UUID がオブジェクト レジストリ テーブル内で検索され、 uuid7 型にマップされます。
マネージャーの種類を見つけるために、サーバーのランタイム ライブラリはインターフェイスのレジストリ テーブルにインターフェイス UUID、 uuid2、および型 uuid7 を組み合わせます。 これにより、リモート プロシージャ コール用に実行されるサーバー マネージャー ルーチンを含む epv3 に解決されます。
サーバーが uuid4 型のオブジェクトをオブジェクト レジストリ テーブルに追加するために RpcObjectSetType ルーチンを呼び出していないため、epv2 のルーチンは実行されません。
インターフェイス UUID uuid2 とオブジェクト UUID uuidF を使用したリモート プロシージャ 呼び出しは、サーバーが RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出してマネージャーの種類 uuid8 にインターフェイスを登録しなかったため、RPC_S_UNKNOWN_MGR_TYPE状態コードを使用して呼び出し元に返されます。
戻り値
この関数は、次のいずれかの値を返します。
値 | 説明 |
---|---|
RPC_S_OK | Success |
RPC_S_TYPE_ALREADY_REGISTERED | 「UUID が既に登録されている」と入力します |
独自のオブジェクト照会関数の提供
さまざまな種類の何千ものオブジェクトを管理するサーバーを考えてみましょう。 サーバーが起動するたびに、サーバー アプリケーションは、オブジェクトの一部のみを参照する (または参照に時間がかかる) 場合でも、すべてのオブジェクトに対して RpcObjectSetType 関数を呼び出す必要があります。 これらの何千ものオブジェクトがディスク上に存在する可能性が高いので、その種類を取得するには時間がかかります。 また、オブジェクト UUID をマネージャー型 UUID にマッピングする内部テーブルは、基本的にオブジェクト自体で維持されるマッピングを複製します。
便宜上、RPC 関数セットには関数 RpcObjectSetInqFn が含まれています。 この関数では、独自のオブジェクト照会関数を提供します。
たとえば、オブジェクト 100 ~ 199 を型番号 1、200 ~ 299 にマップして数値 2 などを入力する場合に、独自のオブジェクト照会関数を指定できます。 また、オブジェクト照会機能を分散ファイル・システムに拡張することもできます。サーバー・アプリケーションには、使用可能なすべてのファイル (オブジェクト UUID) のリストがない場合、またはファイル・システム内のオブジェクト UUID 名ファイルが存在し、オブジェクト UUID とタイプ UUID の間のすべてのマッピングを事前に読み込む必要がない場合があります。
関連トピック