【Windows】RPC调用过程实例详解

概述:windows 创建 RPC调用过程实例详解
参考文章:Remote procedure call (RPC)(远程过程调用 (RPC)) - Win32 apps | Microsoft Learn

RPC

0x01、生成 UUID 和模版(IDL)文件

定义接口的第一步是使用 uuidgen 实用工具生成通用唯一标识符(UUID)。UUID使客户端和服务端能够相互识别。该工具包含在阿庄平台软件开发工具包中(SDK)。

一般安装路径位于:D:\Windows Kits\10\bin\10.0.22621.0\x64

以下命令生成 UUID 并创建名为 Hello.idl 的模版文件。

uuidgen /i /ohello.idl

模版内容大致如下:

[
    uuid(7a98c250-6808-11cf-b73b-00aa00b677a7),
    version(1.0)
]
interface hello
{
 
}

在模版中添加接口:

//file hello.idl
[
    uuid(7a98c250-6808-11cf-b73b-00aa00b677a7),
    version(1.0)
]
interface hello
{
    void HelloProc([in, string] unsigned char * pszString);
    void Shutdown(void);
}

0x02、添加 acf 文件

acf文件内容如下所示,导出接口需要与 idl 文件一致:

//file: hello.acf
[
    implicit_handle (handle_t hello_IfHandle)
] 
interface hello
{
}

0x03、编译 idl 文件

  1. 打开 visual studio,新建一个空项目

  2. 空项目中添加上述 idl文件 和 acf文件
    接口工程

  3. 编译项目

  4. 生成 hello_h.h、hello_c.c、hello_s.c

    • hello_h.h: 服务端和客户端共用文件
    • hello_c.c: 客户端文件
    • hello_s.c: 服务端文件

    需要补充说明的是,在 hello_h.h 头文件中有两个导出接口,导出接口即为rpc调用的接口。

    extern RPC_IF_HANDLE hello_v1_0_c_ifspec;
    extern RPC_IF_HANDLE hello_v1_0_s_ifspec;
    

0x04、客户端

新建工程文件如下所示:
客户端工程

main.cpp

//client.cpp
#include <iostream>
#include <string>
using namespace std;


#include "hello_h.h"

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


void doRpcCall();

int main(int argc, char** argv)
{
    int i = 0;
    RPC_STATUS status = 0;

    unsigned char* pszNetworkAddr = NULL;
    unsigned char* pszStringBinding = NULL;

    for (i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-ip") == 0) {
            pszNetworkAddr = (unsigned char*)argv[++i];
            break;
        }
    }

    status = RpcStringBindingCompose(NULL,
        (unsigned char*)"ncacn_np",
        pszNetworkAddr,
        (unsigned char*)"\\pipe\\hello",
        NULL,
        &pszStringBinding);
    if (status != 0) {
        cout << "RpcStringBindingCompose returns: " << status << "!" << endl;
        return -1;
    }

    cout << "pszStringBinding = " << pszStringBinding << endl;
    status = RpcBindingFromStringBinding(pszStringBinding, &hello_IfHandle);
    if (status != 0) {
        cout << "RpcBindingFromStringBinding returns: " << status << "!" << endl;
        return -1;
    }

    doRpcCall();

    status = RpcStringFree(&pszStringBinding);
    if (status != 0)
        cout << "RpcStringFree returns: " << status << "!" << endl;

    status = RpcBindingFree(&hello_IfHandle);
    if (status != 0)
        cout << "RpcBindingFree returns: " << status << "!" << endl;

    cin.get();
    return 0;
}

void doRpcCall(void)
{
    char buff[1024];
    RpcTryExcept{
     while (true) {
      cout << "Please input a string param for Rpc call:" << endl;
      cin.getline(buff, 1023);
      if (strcmp(buff, "exit") == 0 || strcmp(buff, "quit") == 0) {
       Shutdown();
      }
      else {
       HelloProc((unsigned char*)buff);
       cout << "call helloproc succeed!" << endl;
      }
     }
    }

        RpcExcept(1) {
        unsigned long ulCode = RpcExceptionCode();
        cout << "RPC exception occured! code: " << ulCode << endl;
    }
    RpcEndExcept
}

void* __RPC_USER MIDL_user_allocate(size_t len)
{
    return (malloc(len));
}

void __RPC_USER MIDL_user_free(void* ptr)
{
    free(ptr);
}

0x05、服务端

新建工程文件如下所示:
服务端工程

main.cpp

#include <iostream>
using namespace std;

#include "hello_h.h"

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

int main(void)
{
	RPC_STATUS status = 0;

	unsigned int mincall = 1;
	unsigned int maxcall = 20;

	status = RpcServerUseProtseqEp(
		(unsigned char*)"ncacn_np",
		maxcall,
		(unsigned char*)"\\pipe\\hello",
		NULL);
	if (status != 0) {
		cout << "RpcServerUseProtseqEp returns: " << status << endl;
		return -1;
	}

	status = RpcServerRegisterIf(
		hello_v1_0_s_ifspec,
		NULL,
		NULL);
	if (status != 0) {
		cout << "RpcServerRegisterIf returns: " << status << endl;
		return -1;
	}

	cout << "Rpc Server Begin Listening..." << endl;
	status = RpcServerListen(mincall, maxcall, FALSE);
	if (status != 0) {
		cout << "RpcServerListen returns: " << status << endl;
		return -1;
	}

	cin.get();
	return 0;
}

/************************************************************************/
/*                        MIDL malloc & free                            */
/************************************************************************/

void* __RPC_USER MIDL_user_allocate(size_t len)
{
	return (malloc(len));
}

void __RPC_USER MIDL_user_free(void* ptr)
{
	free(ptr);
}

/************************************************************************/
/*                       Interfaces                                     */
/************************************************************************/

void HelloProc(unsigned char* szhello)
{
	cout << szhello << endl;
}

void Shutdown(void)
{
	RPC_STATUS status = 0;

	status = RpcMgmtStopServerListening(NULL);
	if (status != 0) {
		cout << "RpcMgmtStopServerListening returns: " << status << "!" << endl;
	}

	status = RpcServerUnregisterIf(NULL, NULL, FALSE);
	if (status != 0) {
		cout << "RpcServerUnregisterIf returns: " << status << "!" << endl;
	}
}

0x06、编译并运行

分别编译客户端和服务端程序,得到 server.exe 和 client.exe

  1. 先运行 server.exe
  2. 在 client.exe 目录运行 client -ip 192.168.106.128 来启动客户端程序并与服务器端相连
  3. 在 client 的窗口输入任意字符串,回车后可看到server窗口上有显示
  4. 在 client 窗口内 输入 exit 或 quit, server 窗口关闭

0x07、运行示例

Client

Client截图

Server

Server截图

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧恩意

如有帮助,感谢打赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值