EternalWindows
RPC / エンドポイントマッパー
対応するクライアントはこちら

これまで開発してきたサーバーは、最初にプロトコルシーケンスとエンドポイントの設定を行っていましたが、 このエンドポイントの設定はRPC側に任せることができます。 この場合、クライアントはサーバーのエンドポイントが分からないため、 バインディングすることができないように思えますが、 サーバーは代わりとして他の情報をエンドポイントマッパーに登録します。 エンドポイントマッパーとは、"Remote Procedure Call (RPC)"という名前のサービスであり、 内部にエンドポイントマッパーデータベースを持っています。 クライアントは、このデータベースを照会することで、 バインディングできるようになります。

サーバーがエンドポイントを指定しない場合に呼び出す関数は、 RpcServerUseProtseqになります。

RPC_STATUS RPC_ENTRY RpcServerUseProtseq(
    unsigned char *ProtSeq,
    unsigned int MaxCalls,
    void *SecurityDescriptor
);

ProtSeqは、プロトコルシーケンスを指定します。 MaxCallsは、ncacn_ip_tcpにおいて、キューに格納できる接続要求の最大数を指定します。 SecurityDescriptorは、セキュリティ記述子を指定します。

サーバーは、クライアントがバインディングできるように、 エンドポイントマッパーに情報を登録する必要があります。 登録できる情報は、RpcEpRegisterの引数から分かります。

RPC_STATUS RPC_ENTRY RpcEpRegister(
    RPC_IF_HANDLE IfSpec,
    RPC_BINDING_VECTOR *BindingVector,
    UUID_VECTOR *UuidVector,
    unsigned char *Annotation
);

IfSpecは、登録済みのインターフェースハンドルを指定します。 BindingVectorは、バインディングベクタのアドレスを指定します。 UuidVectorは、オブジェクトUUIDベクタを指定します。 このオブジェクトが何を意味するのかはよく分かりませんが、 おそらく、データベースに登録する情報をオブジェクトとして扱い、 それにUUIDを備えるということではないでしょうか。 Annotationは、登録した情報を表す最大64文字のコメントを指定します。

RpcEpRegisterに指定するバインディングベクタとは、 バインディングハンドルの配列のようなものです。 サーバーが既にRpcServerUseProtseqEpやRpcServerUseProtseqを呼び出している場合は、 RpcServerInqBindingsを呼び出すことによって、 バインディングベクタを取得することができます。

RPC_STATUS RPC_ENTRY RpcServerInqBindings(
    RPC_BINDING_VECTOR **BindingVector
);

BindingVectorは、バインディングベクタを受け取る変数のアドレスを指定します。

サーバーが終了する場合は、RpcEpUnregisterを呼び出すことによって登録した情報を削除します。

RPC_STATUS RPC_ENTRY RpcEpUnregister(
    RPC_IF_HANDLE IfSpec,
    RPC_BINDING_VECTOR *BindingVector,
    UUID_VECTOR *UuidVector
);

IfSpecは、登録済みのインターフェースハンドルを指定します。 BindingVectorは、バインディングベクタを指定します。 オブジェクトUUIDベクタを指定します。

不要になったバインディングベクタは、RpcBindingVectorFreeで開放することになります。

RPC_STATUS RPC_ENTRY RpcBindingVectorFree(
    RPC_BINDING_VECTOR **BindingVector
);

BindingVectorは、開放したいバインディングベクタを指定します。

次に、今回のIDLファイルを示します。

[
	uuid (6b1e63f3-83a3-486d-8c3e-a38d36401e41),
	version (1.0)
]
interface sample
{
	int ServerFunction(void);
	void Shutdown(void);
}

次に、今回のACFファイルを示します。

[
	implicit_handle(handle_t hBinding)
]
interface sample
{
}

次に、今回のプログラムを示します。

#include <windows.h>
#include <rpc.h>
#include "sample_h.h"

#pragma comment (lib, "rpcrt4.lib")

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	RPC_BINDING_VECTOR *pBindingVector;
	
	if (RpcServerUseProtseqW((USHORT *)L"ncacn_np", 0, NULL) != RPC_S_OK) {
		MessageBox(NULL, TEXT("プロトコルの指定に失敗しました。"), NULL, MB_ICONWARNING);
		return 0;
	}
	
	if (RpcServerRegisterIf(sample_v1_0_s_ifspec, NULL, NULL) != RPC_S_OK) {
		MessageBox(NULL, TEXT("インターフェースの登録に失敗しました。"), NULL, MB_ICONWARNING);
		return 0;
	}
	
	if (RpcServerInqBindings(&pBindingVector) != RPC_S_OK) {
		MessageBox(NULL, TEXT("バインディングの問い合わせに失敗しました。"), NULL, MB_ICONWARNING);
		RpcServerUnregisterIf(NULL, NULL, FALSE);
		return 0;
	}
	
	if (RpcEpRegister(sample_v1_0_s_ifspec, pBindingVector, NULL, 0) != RPC_S_OK) {
		MessageBox(NULL, TEXT("アドレス情報の登録に失敗しました。"), NULL, MB_ICONWARNING);
		RpcBindingVectorFree(&pBindingVector);
		RpcServerUnregisterIf(NULL, NULL, FALSE);
		return 0;
	}

	if (RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE) != RPC_S_OK) {
		MessageBox(NULL, TEXT("リッスンに失敗しました。"), NULL, MB_ICONWARNING);
		RpcEpUnregister(sample_v1_0_s_ifspec, pBindingVector, NULL);
		RpcBindingVectorFree(&pBindingVector);
		RpcServerUnregisterIf(NULL, NULL, FALSE);
		return 0;
	}
	
	MessageBox(NULL, TEXT("終了します。"), TEXT("OK"), MB_OK);

	RpcEpUnregister(sample_v1_0_s_ifspec, pBindingVector, NULL);
	RpcBindingVectorFree(&pBindingVector);
	RpcServerUnregisterIf(NULL, NULL, FALSE);

	return 0;
}

int ServerFunction(void)
{
	return 1;
}

void Shutdown(void)
{
	RpcMgmtStopServerListening(NULL);
}

void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)
{
	return(malloc(len));
}

void __RPC_API midl_user_free(void __RPC_FAR * ptr)
{
	free(ptr);
}

RpcEpRegisterの呼び出しにはバインディングベクタが必要になるため、 事前にRpcServerInqBindingsを呼び出しておく必要があります。 第3引数に指定できるオブジェクトUUIDベクタはNULLに指定することができ、 第4引数のコメント文字列もNULLを指定することができます。 RpcEpUnregisterの呼び出しでは、RpcEpRegisterと同じ引数を指定します。

エンドポイントマッパーデータベースはローカルコンピュータを対象としています。 よって、リモートからエンドポイントマッパーデータベースの情報を追加する事や参照することはできないと思われます。 エンドポイントマッパーデータベースに登録した情報は、サーバーが終了すると同時に削除されることになっています。 このため、明示的に情報を削除するRpcEpUnregisterを呼び出さなくても特に問題はありません。 ネームサービスはこれらと正反対に、リモートからの参照が可能で、登録した情報も永続的です。


戻る