C++第五十七篇——RPC进程间通信
第一步:新建一个空项目
第二步:新建一个IDL
第三步:生成一个GUID,编写RPCConn.idl
RPCConn.idl
import "oaidl.idl"; import "ocidl.idl"; [ uuid(1BA624D4-DC7D-484C-AF8C-0EF86C4A0555), version(1.0) ] interface RPCConn { int Add( [in] int a, [in] int b ); unsigned long long GetLastInputInfoTime(); }
第四步:右击RPCConn.idl进行编译
将RPCConn_s.c和RPCConn_h.h拷贝到RPC的服务端,将RPCConn_c.c和RPCConn_h.h拷贝到RPC的客户端。
第五步:新建一个服务端空项目RPCServer,将RPCConn_s.c和RPCConn_h.h拷贝过去,并添加现有项。
第六步:新建一个RPCServer.cpp
#include "RPCConn_h.h" #include <Windows.h> #include <iostream> #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") int main() { RPC_STATUS status = RPC_S_OK; // 注册接口 status = RpcServerRegisterIf( RPCConn_v1_0_s_ifspec, // 要注册的接口 NULL, // 指向与EPV参数关联的UUID NULL // 管理器例程的入口点向量EPV ); if (status != RPC_S_OK) { printf("注册接口失败。错误代码:0x%08X\n", status); return status; } printf("注册接口完成\n"); // 使服务器在本地可用 status = RpcServerUseProtseq( (RPC_WSTR)L"ncalrpc", RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // Protseq dependent parameter NULL // Always specify NULL here. ); if (status != RPC_S_OK) { printf("指定使用协议失败。错误代码:0x%08X\n", status); return status; } printf("指定ncalrpc协议完成\n"); // 获取绑定向量 RPC_BINDING_VECTOR* rpcBindingVector; status = RpcServerInqBindings(&rpcBindingVector); if (status != RPC_S_OK) { printf("获取绑定向量失败。错误代码:0x%08X\n", status); return status; } printf("绑定向量完成\n"); // 注册终结点 status = RpcEpRegister( RPCConn_v1_0_s_ifspec, // 注册终结点的接口 rpcBindingVector, // 指定绑定句柄的向量 NULL, // 指向服务器提供的对象UUID的向量指针 NULL // 字符串注释指针 ); if (status != RPC_S_OK) { printf("注册终结点失败。错误代码:0x%08X\n", status); return status; } printf("注册终结点完成\n"); printf("开始侦听客户端......\n"); // 侦听客户端调用 status = RpcServerListen( 1, // 服务器中创建和维护的最小线程数 RPC_C_LISTEN_MAX_CALLS_DEFAULT, // 建议的最大并发远程过程调用数 0 // 控制监听返回的标志 0:在完成所有回调前不返回 !0:完成函数处理后立即返回 ); if (status != RPC_S_OK) { printf("侦听客户端调用失败。错误代码:0x%08X\n", status); return status; } return status; } int Add( /* [in] */ handle_t IDL_handle, /* [in] */ int a, /* [in] */ int b) { printf("Calling Add:%d + %d = %d\n", a, b, a + b); return a + b; } unsigned long long GetLastInputInfoTime( /* [in] */ handle_t IDL_handle) { LASTINPUTINFO lastInputInfo; lastInputInfo.cbSize = sizeof(lastInputInfo); GetLastInputInfo(&lastInputInfo); ULONGLONG time = GetTickCount64() - lastInputInfo.dwTime; printf("Time:%llu\n", time); return time; } /******************************************************/ /* MIDL allocate and free */ /******************************************************/ void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len) { return(malloc(len)); } void __RPC_USER midl_user_free(void __RPC_FAR* ptr) { free(ptr); }
第七步:为RPCServer的链接器添加一个rpcrt4.lib文件
第八步:将RPCServer设置为启动项目并运行起来,可以在任务管理器的进程中看到。
第九步:创建一个RPC客户端空项目,将RPCConn_c.c和RPCConn_h.h拷贝进去
第十步:新建一个RPCClient.cpp
#include "RPCConn_h.h" #include <Windows.h> #include <iostream> int main() { RPC_STATUS status = RPC_S_OK; unsigned short* StringBinding; RPC_BINDING_HANDLE BindingHandle; status = RpcStringBindingCompose( NULL, // Object UUID (RPC_WSTR)L"ncalrpc", // Protocol sequence to use NULL, // Server DNS or Netbios Name NULL, NULL, &StringBinding ); if (status != RPC_S_OK) { printf("获取绑定字符串失败。错误代码:0x%08X\n", status); return status; } status = RpcBindingFromStringBinding(StringBinding, &BindingHandle); if (status != RPC_S_OK) { printf("获取绑定句柄失败。错误代码:0x%08X\n", status); return status; } RpcStringFree(&StringBinding); printf("请输入两个数字:\n"); int a = 0, b = 0; scanf_s("%d%d", &a, &b); printf("%d + %d = %d\n", a, b, Add(BindingHandle, a, b)); system("pause"); return status; } /******************************************************/ /* MIDL allocate and free */ /******************************************************/ void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len) { return(malloc(len)); } void __RPC_USER midl_user_free(void __RPC_FAR* ptr) { free(ptr); }
第十一步:为RPCClient的链接器添加一个rpcrt4.lib文件。
第十二步:将RPCClient设为一个启动项目并运行
成功通信。