[ Home | Syllabus | Course Notes | Assignments | Search]
Separating the Component from the Client
In Process Component: Runs in address space of client, contained in DLL (see DLL start up procedure)
Separate Process Component: Need the following.
THE REAL WORK IS MINIMAL.
Relevant points
A little diversion into RPC
Sources of significant overhead:
Based on Unix DCE( Distributed Computing Environment)
Annotate function prototype with type + use information
Basic Types supported:
Limited support for Pointers:
endpoint(protocol-sequence:[endpoint-port] [ , ...] )
protocol-sequence
Specifies a character string that represents a valid combination of an RPC protocol (such
as ncacn), a transport protocol (such as tcp), and a network
protocol (such as ip). Microsoft RPC supports the following protocol
sequences:
| Protocol sequence | Description | Supporting Platforms |
| ncacn_nb_tcp | Connection-oriented NetBIOS over TCP | Client and server: Windows NTClient only: MS-DOS, Windows 3.x |
| ncacn_nb_ipx | Connection-oriented NetBIOS over IPX | Client and server: Windows NT Client : MS-DOS, Windows 3.x |
| ncacn_nb_nb | Connection-oriented NetBEUI | Client and server: Windows NT, Windows® 95 Client : MS-DOS, Windows 3.x |
| ncacn_ip_tcp | Connection-oriented TCP/IP | Client and server: Windows 95 and Windows NT Client: MS-DOS,Windows 3.x, and Apple® Macintosh® |
| ncacn_np | Connection-oriented named pipes | Client and server: Windows NT Client: MS-DOS, Windows 3.x, Windows 95 |
| ncacn_spx | Connection-oriented SPX | Client and server: Windows NT, Windows 95 Client: MS-DOS, Windows 3.x |
| ncacn_dnet_nsp | Connection-oriented DECnet | Client only: MS-DOS, Windows 3.x |
| ncacn_at_dsp | Connection-oriented AppleTalk DSP | Server: Windows NT Client: Apple Macintosh |
| ncacn_vns_spp | Connection-oriented Vines SPP | Client and server: Windows NT Client: MS-DOS, Windows 3.x |
| ncadg_ip_udp | Datagram (connectionless) UDP/IP | Client and server: Windows NT Client: MS-DOS, Windows 3.x |
| ncadg_ipx | Datagram (connectionless) IPX | Client and server: Windows NT Client: MS-DOS, Windows 3.x |
| ncalrpc | Local procedure call | Client and server: Windows NT and Windows 95 |
Server has to register its availability to "Name Server" with the last two.
Routine to Sum the integers from 1 to N, shown below:
#include <windows.h>
#include "sum.h" // generated by MIDL compiler (also generates sum_s.c)
long SumUp(short sumVal)
{
short iter;
long theSum;
theSum=0;
for (iter=1; iter<=sumVal; theSum+=iter, iter++);
return(theSum);
}
/*
This program uses an autobinding RPC call to
calculate a running sum.
*/
#include <windows.h>
#include <iostream.h>
#include <rpc.h>
#include <stdlib.h>
#include "sum.h"
#include "memstub" // used by hidden functions in sum.h to allocate/free memory
INT main(VOID)
{
CHAR sumUpToStr[10];
long theSum;
cout << "Enter a value to compute running sum: ";
cin.getline(sumUpToStr, 10);
theSum=SumUp((short)atoi(sumUpToStr));
cout << "The running sum is: " << theSum << endl;
return(0);
}
[
uuid (22449651-4321-1234-4321-987654321CBA), // generated by uuidgen -i (in VC/bin directory)
version(1.0),
endpoint ("ncacn_np:[\\pipe\\autorpc]",
"ncacn_ip_tcp:[1050]") // network connections permitted (can be multiple ones)
]
interface sumup // function names available
{
long SumUp([in] short sumVal); // annotated function prototype
}
[
auto_handle
]
interface sumup
{
}
// autoserv.cpp
#include <windows.h>
#include <iostream.h>
#include <rpc.h>
#include "sum.h"
#include "memstub"
INT main(VOID)
{
RPC_BINDING_VECTOR *bindVector;
// use the protocols specified in the
// IDL file for this interface
if (RpcServerUseAllProtseqsIf(1,
sumup_v1_0_s_ifspec, NULL))
// register the interface
if (RpcServerRegisterIf(sumup_v1_0_s_ifspec,
NULL, NULL))
// get binding handles for the interface
if (RpcServerInqBindings(&bindVector))
// add an entry in the name service
// for the interface
if (RpcNsBindingExport(RPC_C_NS_SYNTAX_DEFAULT,
(UCHAR *) "/.:/autorpc",
sumup_v1_0_s_ifspec, bindVector, NULL))
// listen for and service RPC requests
if (RpcServerListen(1, 5, FALSE))
}
Automatic is easier to code but inefficient since every RPC call
needs to query Name Server
So let's try manual binding or assisted manual.
// conserv.cpp
#include <windows.h>
#include <iostream.h>
#include <rpc.h>
#include "sum.h"
#include "memstub"
INT main(VOID)
{
// use the specified protocol and endpoint
if (RpcServerUseProtseqEp(
(UCHAR *) "ncacn_ip_tcp", 1,
(UCHAR *) "55449", NULL))
// register the interface
if (RpcServerRegisterIf(sumup_v1_0_s_ifspec,
NULL, NULL))
// listen for and service RPC requests
if (RpcServerListen(1, 5, FALSE))
[
implicit_handle(handle_t SumUpHandle)
]
interface sumup
{
}
// conclnt.cpp
/*
This program calls an RPC function
using a manual handle.
*/
#include <windows.h>
#include <iostream.h>
#include <rpc.h>
#include <stdlib.h>
#include "sum.h"
#include "memstub"
INT main(VOID)
{
CHAR sumUpToStr[10];
long theSum;
UCHAR *stringBinding;
cout << "Enter a value to compute running sum: ";
cin.getline(sumUpToStr, 10);
// put together string binding
if (RpcStringBindingCompose(NULL,
(UCHAR *) "ncacn_ip_tcp",
(UCHAR *) "localhost",
(UCHAR *) "55449", NULL, &stringBinding))
// bind to server using string binding info
if (RpcBindingFromStringBinding(stringBinding,
&SumUpHandle))
// free the string binding info
if (RpcStringFree(&stringBinding))
theSum=SumUp((short)atoi(sumUpToStr));
cout << "The running sum is: " << theSum << endl;
// release binding to server
if (RpcBindingFree(&SumUpHandle))
void __RPC_FAR * __RPC_API
midl_user_allocate(size_t len)
{
return(new(unsigned char [len]));
}
void __RPC_API midl_user_free(void __RPC_FAR * ptr)
{
delete(ptr);
}
Examining component_p.c from DLL Surrogate DCOM example
/* this ALWAYS GENERATED file contains the proxy stub code */
/* File created by MIDL compiler version 3.01.75 */
/* at Wed Mar 31 07:39:14 1999
*/
#include "rpcproxy.h"
#include "component.h"
/* Object interface: IUnknown, ver. 0.0,
GUID={0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */
/* Object interface: ISum, ver. 0.0,
GUID={0x10000001,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}} */
HRESULT STDMETHODCALLTYPE ISum_Sum_Proxy(
ISum __RPC_FAR * This,
int x,
int y,
/* [retval][out] */ int __RPC_FAR *retval)
{
HRESULT _RetVal;
RPC_MESSAGE _RpcMessage;
MIDL_STUB_MESSAGE _StubMsg;
RpcTryExcept
{
NdrProxyInitialize(
( void __RPC_FAR * )This,
( PRPC_MESSAGE )&_RpcMessage,
( PMIDL_STUB_MESSAGE )&_StubMsg,
( PMIDL_STUB_DESC )&Object_StubDesc,
3);
RpcTryFinally
{
_StubMsg.BufferLength = 4U + 4U;
NdrProxyGetBuffer(This, &_StubMsg);
*(( int __RPC_FAR * )_StubMsg.Buffer)++ = x;
*(( int __RPC_FAR * )_StubMsg.Buffer)++ = y;
NdrProxySendReceive(This, &_StubMsg);
if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION )
NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] );
*retval = *(( int __RPC_FAR * )_StubMsg.Buffer)++;
_RetVal = *(( HRESULT __RPC_FAR * )_StubMsg.Buffer)++;
}
RpcFinally
{
NdrProxyFreeBuffer(This, &_StubMsg);
}
RpcEndFinally
}
RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)
{
NdrClearOutParameters(
( PMIDL_STUB_MESSAGE )&_StubMsg,
( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[0],
( void __RPC_FAR * )retval);
_RetVal = NdrProxyErrorHandler(RpcExceptionCode());
}
RpcEndExcept
return _RetVal;
}
void __RPC_STUB ISum_Sum_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase)
{
int _M0;
HRESULT _RetVal;
MIDL_STUB_MESSAGE _StubMsg;
int __RPC_FAR *retval;
int x;
int y;
NdrStubInitialize(
_pRpcMessage,
&_StubMsg,
&Object_StubDesc,
_pRpcChannelBuffer);
retval = 0;
RpcTryFinally
{
if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION )
NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] );
x = *(( int __RPC_FAR * )_StubMsg.Buffer)++;
y = *(( int __RPC_FAR * )_StubMsg.Buffer)++;
retval = &_M0;
*_pdwStubPhase = STUB_CALL_SERVER;
_RetVal = (((ISum *) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> Sum(
(ISum *) ((CStdStubBuffer *)This)->pvServerObject,
x,
y,
retval);
*_pdwStubPhase = STUB_MARSHAL;
_StubMsg.BufferLength = 4U + 4U;
NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg);
*(( int __RPC_FAR * )_StubMsg.Buffer)++ = *retval;
*(( HRESULT __RPC_FAR * )_StubMsg.Buffer)++ = _RetVal;
}
RpcFinally
{
}
RpcEndFinally
_pRpcMessage->BufferLength =
(unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer);
}
static const MIDL_STUB_DESC Object_StubDesc =
{
0,
NdrOleAllocate,
NdrOleFree,
0,
0,
0,
0,
0,
__MIDL_TypeFormatString.Format,
0, /* -error bounds_check flag */
0x10001, /* Ndr library version */
0,
0x301004b, /* MIDL Version 3.1.75 */
0,
0,
0, /* Reserved1 */
0, /* Reserved2 */
0, /* Reserved3 */
0, /* Reserved4 */
0 /* Reserved5 */
};
const CINTERFACE_PROXY_VTABLE(4) _ISumProxyVtbl =
{
&IID_ISum,
IUnknown_QueryInterface_Proxy,
IUnknown_AddRef_Proxy,
IUnknown_Release_Proxy ,
ISum_Sum_Proxy
};
Why bother looking at output of MIDL?