Similar to the server application we can write the client application code as below.
// File DoRPC_Client.cpp
#include <stdio.h>
#include "..\RPC1_IDL\DoRPC.h"
int main()
{
RPC_STATUS status;
unsigned char* szStringBinding = NULL;
// Creates a string binding handle.
// This function formats the passed values in a
// predefined format for use by RPC. Just like printf
// Connection is not done here.
status = RpcStringBindingCompose(
NULL, // UUID to bind to.
(unsigned char*)("ncacn_ip_tcp"),
// Use TCP/IP protocol.
(unsigned char*)("localhost"), // TCP/IP network // the same machine as server
(unsigned char*)("9191"),
// TCP/IP port to use.
NULL, // Protocol dependent network
options to use.
&szStringBinding); // String binding
output.
if (status)
exit(status);
// Validates the format of the string binding
handle and converts
// it to a binding handle.
// Connection is not done here either.
status = RpcBindingFromStringBinding(
szStringBinding, // The string binding to validate.
&hDoRPCBinding); // Put the result in the implicit binding
// handle defined in the IDL file.
if(status)
{
exit(status);
}
RpcTryExcept
{
// Calls the RPC function. The hDoRPCBinding
binding handle
// is used implicitly.
// Connection is done here.
const unsigned char szMsg[] = "Client: I Can
RPC Now!";
Show(szMsg);
}
RpcExcept(1)
{
printf("Runtime exception occured: %d\n",RpcExceptionCode());
}
RpcEndExcept
// Free the memory allocated by a string.
status = RpcStringFree(&szStringBinding);
// String to be freed.
if(status)
{
exit(status);
}
// Releases binding handle resources and
disconnects from the server.
status = RpcBindingFree(
&hDoRPCBinding); // Frees the implicit binding
handle defined in
// the IDL file.
if (status)
{
exit(status);
}
return 0;
}
// Memory allocation function for RPC.
// The runtime uses these two functions for allocating/deallocating
// enough memory to pass the string to the server.
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);
}
Now open up two command prompt consoles and execute server on one and Client on the other and you’ll see what we’ve accomplished with the help of MIDL and RPC. Wasn’t that easy?
Let’s go back and recall the steps that we performed to achieve this. First we need to compile the IDL file to get the client proxy(DoRPC_c.c), the server stub (DoRPC_s.c) and the common header file (DoRPC.h). Next the proxy and the stub are compiled, with the client and server implementations of the interface producing standalone client and server executables. If nothing goes wrong and the client and server applications can communicate, we just completed our first RPC client/server application.