インターフェイスの登録

このセクションでは、RPC インターフェイスを登録するプロセスについて詳しく説明します。

このセクションの情報は、次のトピックで説明します。

インターフェイス登録関数

サーバーは 、RpcServerRegisterIf 関数を呼び出してインターフェイスを登録します。 複雑なサーバー プログラムでは、多くの場合、複数のインターフェイスがサポートされます。 サーバー アプリケーションは、サポートするインターフェイスごとにこの関数を 1 回呼び出す必要があります。

また、サーバーは同じインターフェイスの複数のバージョンをサポートでき、それぞれがインターフェイスの関数の独自の実装を備えています。 サーバー プログラムでこれを行う場合は、エントリ ポイントのセットを提供する必要があります。 エントリ ポイントは、インターフェイスのバージョンの呼び出しをディスパッチするマネージャー ルーチンです。 インターフェイスのバージョンごとに 1 つのエントリ ポイントが必要です。 エントリ ポイントのグループは、エントリ ポイント ベクトルと呼ばれます。 詳細については、「 エントリ ポイント ベクトル」を参照してください

標準関数 RpcServerRegisterIf に加えて、RPC は他のインターフェイス登録関数もサポートしています。 RpcServerRegisterIf2 関数は、登録フラグのセット (インターフェイス登録フラグを参照)、サーバーが受け入れ可能な同時リモート プロシージャ コール要求の最大数、および受信データ ブロックの最大サイズ (バイト単位) を指定できるようにすることで、RpcServerRegisterIf の機能を拡張します。

RPC ライブラリには、 RpcServerRegisterIfEx という関数も含まれています。 RpcServerRegisterIf 関数と同様に、この関数はインターフェイスを登録します。 サーバー プログラムでは、この関数を使用して、登録フラグのセット ( インターフェイス登録フラグを参照)、サーバーが受け入れ可能な同時リモート プロシージャ コール要求の最大数、およびセキュリティ コールバック関数を指定することもできます。

RpcServerRegisterIfRpcServerRegisterIfExおよび 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 を登録するために、サポートされているオブジェクトの種類ごとに RpcServerRegisterIfRpcServerRegisterIfEx、または 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 つの実装を登録する

サーバーがインターフェイスの実装を 1 つだけ提供する場合、サーバーは RpcServerRegisterIfRpcServerRegisterIfEx、または RpcServerRegisterIf2 を 1 回だけ呼び出します。 標準の場合、サーバーは既定のマネージャー EPV を使用します。 (例外は、マネージャーがインターフェイスで宣言されているものとは異なるルーチン名を使用する場合です)。

標準の場合は、RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 の呼び出しに次の値を指定します。

  • マネージャー EPV

    既定の EPV を使用するには、パラメーター MgrEpvnull 値を指定します。

  • マネージャーの種類 UUID

    既定の EPV を使用する場合は、パラメーター MgrTypeUuidnull 値または nil UUID を指定して、インターフェイスを nil マネージャー型 UUID に登録します。 この場合、バインド ハンドル内のオブジェクト UUID に関係なく、すべてのリモート プロシージャ呼び出しは、 RpcObjectSetType 呼び出しが行われなかったと仮定して、既定の EPV にディスパッチされます。

    また、nil 以外のマネージャー型 UUID を指定することもできます。 この場合は、 RpcObjectSetType ルーチンも呼び出す必要があります。

インターフェイスの複数の実装の登録

IDL ファイルに指定されたリモート・プロシージャーの複数の実装を指定できます。 サーバー アプリケーションは RpcObjectSetType を呼び出してオブジェクト UUID を型 UUID にマップし、 RpcServerRegisterIfRpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出して、マネージャー EPV を UUID 型に関連付けます。 リモート プロシージャ コールがオブジェクト UUID と共に到着すると、RPC サーバーランタイム ライブラリはオブジェクト UUID を型 UUID にマップします。 その後、サーバー アプリケーションは UUID 型とインターフェイス UUID を使用して、マネージャー EPV を選択します。

独自の関数を指定して、オブジェクト UUID からマネージャー型 UUID へのマッピングを解決することもできます。 RpcObjectSetInqFn を呼び出すときにマッピング関数を指定します。

インターフェイスの複数の実装を提供するには、サーバーは RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 を個別に呼び出して、各実装を登録する必要があります。 サーバーが登録する実装ごとに、同じ IfSpec パラメーターが提供されますが、 MgrTypeUuid パラメーターと MgrEpv パラメーターのペアは異なります。

複数のマネージャーの場合は、次のように RpcServerRegisterIfRpcServerRegisterIfEx 、または RpcServerRegisterIf2 を使用します。

  • マネージャー EPV

    1 つのインターフェイスの複数の実装を提供するには、サーバーで次の手順を実行する必要があります。

    サーバーは既定のマネージャー 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

 

次の手順では、インターフェイス UUID uuid1 を持つクライアントがクライアントを呼び出すときに、上記の表に示すように、RPC サーバーのランタイム ライブラリが実行するアクションについて説明します。

  1. サーバーは RpcServerRegisterIfRpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出して、提供されるインターフェイスを nil manager 型 UUID と MIDL で生成された既定のマネージャー EPV に関連付けます。 この呼び出しは、インターフェイス レジストリ テーブルにエントリを追加します。 インターフェイス UUID は、 IfSpec a パラメーターに含まれています。

  2. 既定では、オブジェクト レジストリ テーブルは、すべてのオブジェクト UUID を nil 型 UUID に関連付けます。 この例では、サーバーは RpcObjectSetType を呼び出しません。

  3. サーバー ランタイム ライブラリは、呼び出しが属しているインターフェイス UUID と、呼び出しのバインド ハンドルからオブジェクト UUID を含むリモート プロシージャ コードを受け取ります。

    オブジェクト UUID をバインド ハンドルに設定する方法については、次の関数参照エントリを参照してください。

  4. リモート プロシージャ コールのインターフェイス UUID を使用して、サーバーのランタイム ライブラリはインターフェイス レジストリ テーブルでそのインターフェイス UUID を見つけます。

    サーバーが RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2使用してインターフェイスを登録しなかった場合、リモート プロシージャ コールは、RPC_S_UNKNOWN_IF状態コードを使用して呼び出し元に戻ります。

  5. バインド ハンドルのオブジェクト UUID を使用して、サーバーのランタイム ライブラリはオブジェクト レジストリ テーブルでそのオブジェクト UUID を検索します。 この例では、すべてのオブジェクト UUID が nil オブジェクト型にマップされます。

  6. サーバーのランタイム ライブラリは、インターフェイス レジストリ テーブルで nil マネージャーの種類を検索します。

  7. インターフェイス レジストリ テーブルのインターフェイス 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 を持つクライアントがクライアントを呼び出すときに、サーバーのランタイム ライブラリが実行するアクションについて説明します。

  1. サーバーは 、RpcServerRegisterIfRpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出して、提供するインターフェイスをさまざまなマネージャー EPV に関連付けます。 インターフェイス レジストリ テーブルのエントリには、 RpcServerRegisterIf、RpcServerRegisterIfEx、または RpcServerRegisterIf2 の 4 つの呼び出しが反映され、インターフェイスごとに 2 つの実装 (EPV) が含まれる 2 つのインターフェイスが提供されます。

  2. サーバーは RpcObjectSetType を呼び出して、提供する各オブジェクトの型を確立します。 nil オブジェクトと nil 型の既定の関連付けに加えて、オブジェクト レジストリ テーブルに明示的に見つからない他のすべてのオブジェクト UUID も、nil 型 UUID にマップされます。

    この例では、サーバーは RpcObjectSetType ルーチンを 6 回呼び出します。

  3. サーバー ランタイム ライブラリは、呼び出しが属しているインターフェイス UUID と、呼び出しのバインド ハンドルからオブジェクト UUID を含むリモート プロシージャ 呼び出しを受信します。

  4. サーバーのランタイム ライブラリは、リモート プロシージャ コールのインターフェイス UUID を使用して、インターフェイス レジストリ テーブル内のインターフェイス UUID を検索します。

  5. バインド ハンドルから uuidC オブジェクト UUID を使用すると、サーバーのランタイム ライブラリはオブジェクト レジストリ テーブル内のオブジェクト UUID を検索し、 uuid7 型にマップされることを検出します。

  6. マネージャーの種類を見つけるために、サーバーのランタイム ライブラリは、インターフェイス レジストリ テーブルにインターフェイス UUID、 uuid2、および型 uuid7 を組み合わせます。 これにより、リモート プロシージャ コール用に実行されるサーバー マネージャー ルーチンが含まれる epv3 に解決されます。

サーバーが uuid4 型のオブジェクトをオブジェクト レジストリ テーブルに追加するために RpcObjectSetType ルーチンを呼び出していないため、epv2 のルーチンは実行されません。

サーバーが RpcServerRegisterIfRpcServerRegisterIfEx、または RpcServerRegisterIf2 を呼び出してマネージャーの種類の uuid8 にインターフェイスを登録しなかったため、インターフェイス UUID uuid2 とオブジェクト UUID uuidF を持つリモート プロシージャ呼び出しは、RPC_S_UNKNOWN_MGR_TYPE状態コードで呼び出し元に返されます。

戻り値

この関数は、次のいずれかの値を返します。

意味
RPC_S_OK Success
RPC_S_TYPE_ALREADY_REGISTERED 型 UUID が既に登録されている

 

独自のオブジェクト照会関数の指定

さまざまな種類の何千ものオブジェクトを管理するサーバーを考えてみましょう。 サーバーが起動するたびに、サーバー アプリケーションはオブジェクトの 1 つごとに RpcObjectSetType 関数を呼び出す必要があります。ただし、クライアントが参照するオブジェクトの数が少ない (または参照に時間がかかる場合もあります)。 この数千のオブジェクトはディスク上に存在する可能性が高いので、その種類を取得するには時間がかかります。 また、オブジェクト UUID をマネージャー型 UUID にマッピングする内部テーブルは、基本的にオブジェクト自体で保持されているマッピングを複製します。

便宜上、RPC 関数セットには RpcObjectSetInqFn 関数が含まれています。 この関数では、独自のオブジェクト照会機能を提供します。

たとえば、オブジェクト 100 ~ 199 を型番号 1、200~ 299 にマップして数値 2 などを入力するときに、独自のオブジェクト照会関数を指定できます。 また、オブジェクト照会機能を分散ファイル・システムに拡張することもできます。サーバー・アプリケーションが使用可能なすべてのファイル (オブジェクト UUID) のリストを持っていない場合、またはファイル・システム内のオブジェクト UUID 名ファイルがオブジェクト UUID とタイプ UUID の間のすべてのマッピングを事前に読み込む必要がない場合にも使用できます。

RpcBindingFromStringBinding

RpcBindingSetObject

RpcNsBindingExport

RpcNsBindingImportBegin

RpcNsBindingLookupBegin

RpcObjectSetType

RpcServerRegisterIf

RpcServerRegisterIf2

RpcServerRegisterIfEx

RpcServerUnregisterIf

RpcServerUnregisterIfEx