idl文件ildTest1.idl:
import "oaidl.idl";
import "ocidl.idl";
[
uuid(A112A4B2-3CA5-475c-B9C0-8684DBEBED52),
version(1.0)
]
interface hw // The interface is named hw
{
// A function that takes a zero-terminated string.
void Hello(
[in, string] const char* szOutput);
}
服务器端:
#include"stdafx.h"
#include
#include
#include"ildTest1_h.h"
#pragma comment(lib,"rpcrt4")
#pragma comment(lib,"ole32")
/*extern "C"{*/
void Hello(handle_t IDL_handle,const unsigned char*psz){
printf("server:%s\n",psz);
}
void Shutdown(handle_t IDL_handle){
RpcMgmtStopServerListening(NULL);
RpcServerUnregisterIf(NULL,NULL,FALSE);
}
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);
}
/*}*/
int main()
{
RPC_STATUS status;
status = RpcServerUseProtseqEp(
(RPC_CSTR)("ncacn_ip_tcp"), // Use TCP/IP protocol.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // Backlog queue length for TCP/IP.
(RPC_CSTR)("13521"), // TCP/IP port to use.
NULL); // No security.
if (status){
printf("ServerUse failed\n");
exit(status);}
else printf("UseProtseqEq ok\n");
// status = RpcServerRegisterIf(
// hw_v1_0_s_ifspec, // Interface to register.
//
// NULL, // Use the MIDL generated entry-point vector.
//
// NULL);// Use the MIDL generated entry-point vector.
// 注意:从Windows XP SP2 开始,增强了安全性的要求,如果用 RpcServerRegisterIf() 注册
// 接口,客户端调用时会出现 RpcExceptionCode() == 5,即Access Denied 的错误. 因此,必
// 须用 RpcServerRegisterIfEx 带 RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH 标志允许客户端直
// 接调用。
// RpcServerRegisterIf(HelloWorld_v1_0_s_ifspec, NULL, NULL);
RpcServerRegisterIfEx(
hw_v1_0_s_ifspec, // Interface to register.
NULL,
NULL, // Use the MIDL generated entry-point vector.
RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
NULL);
if (status){
printf("Register failed\n");
exit(status);}
else printf("Register if ok\n");
// This call will not return until
// RpcMgmtStopServerListening is called.
status = RpcServerListen(
1, // Recommended minimum number of threads.
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Recommended maximum number of threads.
FALSE); // Start listening now.
if (status){
printf("Server listen failed\n");
exit(status);}
else printf("listen ok\n");
return 0;
}
客户端:
#include "stdafx.h"
#include
#include
#include"ildTest1_h.h"
#pragma comment(lib,"rpcrt4")
#pragma comment(lib,"ole32")
int main(void){
RPC_STATUS status;
RPC_BINDING_HANDLE hwBinding;
unsigned char* szStringBinding=NULL;
status=RpcStringBindingCompose(//建立一个String Binding句柄,并不连接
NULL,
(RPC_CSTR)("ncacn_ip_tcp"),
(RPC_CSTR)("localhost"),
(RPC_CSTR)("13521"),
NULL,
(RPC_CSTR*)&szStringBinding);
if(status){
printf("StringBinding failed\n");
exit(status);}
printf("szString=%s\n",szStringBinding);
status=RpcBindingFromStringBinding(
szStringBinding,
&hwBinding);
if(status){
printf("Bind from String failed:%d\n",GetLastError());
exit(status);}
RpcTryExcept{
Hello(hwBinding,(RPC_CSTR)("Hello RPC World!"));
}
RpcExcept(1){
printf("Runtime reported exception:%d,except=%d\n",GetLastError(),RpcExceptionCode()/*RPC_S_ACCESS_DENIED==5L*/);//这里返回了5
}
RpcEndExcept
status = RpcBindingFree(&hwBinding); // Frees the binding handle.
RpcStringFree(&szStringBinding);
if (status){
printf("Bind free failed\n");
exit(status);}
return 0;
}
void* __RPC_USER midl_user_allocate(size_t size){
return malloc(size);
}
// Memory deallocation function for RPC.
void __RPC_USER midl_user_free(void* p){
free(p);
}
总结以及遇到的问题:
1)idl文件单独建立一个工程进行编译,不要在客户端或者服务器工程中编译,因为每次编译都会有所改变,而比如在客户端上包含了idl则会每次重新编译idl文件导致客户端和服务端对应文件不统一。(idlTest1_h.h 和 idlTest1_c.c在客户端中使用,ildTest1_h.h 和 ildTest1_s.c在服务器端使用)
以下段落为转载:
这节我们来谈谈 Windows NT 下 RPC 的高性能模式 - LPC。
很多 Windows 编程入门的书里面讲 Windows 的进程间通信,都会讲 WM_COPYDATA,讲匿名管道,讲命名管道,讲共享内存等等,
但是很少有讲 RPC 的,为什么呢?因为 RPC 看名字,就叫“Remote Procedure Call”,一看就是给分布式系统通信用的,虽然
也可以作为本机进程间通信用,但是性能上总是让人怀疑。所以很多人设计的进程间通信模型,都是用 WM_COPYDATA,或者管道,
或者干脆共享内存,相当于自己造轮子,一切从头做起。但 RPC 确实好用啊,调用起来就像调用库函数一样,通信的细节全给你
封装起来了。那 RPC 有没有性能好一点的模式呢?这就是下面要讲的 LPC 模式了。
LPC(Local Procedure Call)是 Windows NT 内部的高性能的通信模式。它是在内核中实现的,主要用于 Win32 子系统内部的
通信,比如 csrss, lsass 都大量的用到了 LPC。在前面演示的代码中,只需要改一行代码,我们就可使用 LPC 了,其实 RPC 就
是内部使用 LPC 来进行通信,性能大大提高。
服务端代码:
server.c
--------------
// 用LPC 方式通信
RpcServerUseProtseqEp(
(unsigned char *)"ncalrpc",
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
(unsigned char *)"AppName",
NULL);
客户端代码:
client.c
--------------
// 用LPC 方式通信
// 第3 个参数NetworkAddr 只能取NULL
RpcStringBindingCompose(
NULL,
(unsigned char*)"ncalrpc",
NULL, (unsigned char*)"AppName",
NULL,
&pszStringBinding );