Windows NT Systems Programming: Spring 1999

[ 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.

  1. Change one parameter in the client to call for a local server
  2. Add appropriate entries in the register which will use the existing DLL to be hosted by DLLHost.exe The default DLL surrogate.

Relevant points


A little diversion into RPC

 

Design Issues


Why?


Performance

Sources of significant overhead:


Cross Platform: Open Software Foundation (OSF)

Based on Unix DCE( Distributed Computing Environment)


Marshalling Parameters

Annotate function prototype with type + use information

Basic Types supported:

Limited support for Pointers:

 


Network Protocols

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

endpoint-port
Specifies a string that represents the endpoint designation for the specified protocol family. The syntax of the port string is specific to each protocol sequence.

Examples

endpoint("ncacn_np:[\\pipe\\rainier]")

endpoint("ncacn_ip_tcp:[1044]", "ncacn_np:[\\pipe\\shasta]")

Remarks

The endpoint attribute specifies a well-known port or ports (communication endpoints) on which servers of the interface listen for calls.

The endpoint specifies a transport family such as the TCP/IP connection-oriented protocol, a NetBIOS connection-oriented protocol, or the named-pipe connection-oriented protocol.

The protocol-sequence value determines the valid values for the endpoint-port. The MIDL compiler checks only general syntax for the endpoint-port entry. Port specification errors are reported by the run-time libraries. For information about the allowed values for each protocol sequence, see the topic for that protocol sequence.

The following protocol sequences specified by DCE are not supported by the MIDL compiler provided with Microsoft RPC: ncacn_osi_dna and ncadg_dds.

Make sure that you correctly quote backslash characters in endpoints. This error commonly occurs when the endpoint is a named pipe. Endpoint information specified in the IDL file is used by the RPC run-time functions RpcServerUseProtseqIf and RpcServerUseAllProtseqsIf.

Setting up the Server

Server has to register its availability to "Name Server" with the last two.


Name Server


First a Simple Example

(source here)

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);

}

RPC Client

/*

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);

}

Interface Definition Langauge file (sum.idl) MANDATORY

 

[

  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

}

Attribute Configuration File (.ACF) - optional

 

[

  auto_handle

]

interface sumup

{

}

Server Body

// 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))

  }
rainbow.gif (2243 bytes)

Manual Binding

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))

 

 
rainbow.gif (2243 bytes)

ACF

 

[

  implicit_handle(handle_t SumUpHandle)

]

interface sumup

{

}

Complicates Client Code

// 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))

  

  
rainbow.gif (2243 bytes)

Memory Allocation (MEMSTUB)

 

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?


Copyright chris wild 1999.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: April 04, 1999.