作成日: 2015/08/31

メモ: Windows 上での プロセス間通信による RPC の利用

概要

古いソースを整理していたら RPC を扱ったコードを見つけたので、自分の覚え書きにサンプルを残しておきます。

サンプルは以下の環境で作成しました
  • Windows 10 Pro
  • Visual Studio Professional 2015 (C++) (以下 VS2015)
ソース
RpcTest.zip (34.2 KB)
RpcTest.idl

IDL ファイルの uuid は guidgen.exe (VS2015 メニューの [ツール] - [GUID の作成] で起動できる) で作成しました。

guidgen ツール
[
	uuid(AD80D55D-F231-4B20-86CF-E71AC3912D2E),	// このインターフェース定義に割り当てる UUID = AD80D55D-F231-4B20-86CF-E71AC3912D2E
	...

クライアント、サーバー共に、IDL ファイルのプロパティで、[MIDL] - [コマンドライン] で ACF ファイル (RpcTest.acf) を指定しました。

ACF を指定する
RpcTest.acf

RPC のバインドハンドルをローカルで変数定義して指定したかったため、explicit_handle を指定しました。

[
	explicit_handle
]
interface testrpc
{
}
文字セットの設定

クライアント、サーバー共に、プロジェクトのプロパティで、[全般] - [文字セット] に [Unicode 文字セットを使用する] を設定しました。
※VS2015 でプロジェクトを新規作成した時のデフォルト値でした。

Unicode 文字セットを使用する (クライアント)
Unicode 文字セットを使用する (サーバー)

クライアント、サーバー共に、IDL ファイルのプロパティで、[MIDL] - [全般] - [プリプロセッサの定義] に _UNICODE および UNICODE を追加しました。

Unicode 文字セットを使用する (IDL)
スタブソースのプロジェクトへの追加

一旦、IDL ファイルのみをコンパイルし、生成された RpcTest_c.c はクライアントプロジェクトに、 RpcTest_s.c はサーバープロジェクトに追加しました。

スタブソースの追加
スタブソースのプロパティの設定

プロジェクトのプロパティで、クライアントは RpcTest_c.c に、サーバーは RpcTest_s.c に、 それぞれ、 [C/C++] - [プリコンパイル済みヘッダー] - [プリコンパイル済みヘッダー] に [プリコンパイル済みヘッダーを使用しない] を設定しました。

プリコンパイル済みヘッダーの設定 (クライアント)
プリコンパイル済みヘッダーの設定 (サーバー)
RPC 用ライブラリの設定

クライアント、サーバー共に、プロジェクトのプロパティで、[リンカー] - [入力] - [追加の依存ファイル] に rpcrt4.lib を設定しました。

rpcrt4.lib の追加 (クライアント)
rpcrt4.lib の追加 (サーバー)
メモリ確保、解放ルーチンの定義

RpcUser.h として保存し、クライアント、サーバー、それぞれのソースからインクルードして利用するようにしました。

#ifdef __DEFINE_RPC_USER_ROUTINE__

//----------------------------------------------------------------------
// メモリ確保
//----------------------------------------------------------------------

void __RPC_FAR * __RPC_API midl_user_allocate(size_t length)
{
	return new unsigned char[length];
}

//----------------------------------------------------------------------
// メモリ解放
//----------------------------------------------------------------------

void __RPC_API midl_user_free(void __RPC_FAR* ptr)
{
	delete[] ptr;
}

#else	// __DEFINE_RPC_USER_ROUTINE__

extern void __RPC_FAR * __RPC_API midl_user_allocate(size_t length);
extern void __RPC_API midl_user_free(void __RPC_FAR* ptr);

#endif	// __DEFINE_RPC_USER_ROUTINE__
その他

クライアントでの RPC 呼び出しをクラス風にしてみました。ソースをご参照下さい。