Click here to Skip to main content
15,886,812 members
Articles / Desktop Programming / MFC
Article

Bi-directional RPC

Rate me:
Please Sign up or sign in to vote.
4.12/5 (18 votes)
4 May 20033 min read 100.4K   3.3K   41   13
How to use RPC for doing bi-directional client/server procedure calls.

Sample Image - birpc.jpg

Introduction

RPC is frequently not used directly, so, usually you don't have to know the RPC API when you are using DCOM to communicate between systems on the www. But - as you will see later - there are times when the un-cover RPC is very useful.

For instance: In the conventional RPC programming, you have two pieces of software, each in distinguishable executable form.

app A : the client - send request to be served.
app B : the server - complies to the client request.

This is nice and satisfactory most of the time. But, for getting this goal - you don't need to use the RPC directly- the distributed COM is more than enough.

So, when do you really need the RPC?

Well, suppose that one executable plays the role of either the client or the server, alternatively. Beyond that, suppose that the client-role and the server-role use the same interface and the same functions.

Confused?

Don't be !!!

The solution

  1. Try the downloaded demo project and scan carefully the source code for further information...
  2. Read the following lines before the great trial:

Explanation

I assume you already know how to produce the RPC code by the MIDL compiler, so I'll explain just the changes needed to be done:

  1. Some variables in the RPC code have to be replaced by similar variables so there will not be duplicated variables because the client and the server code use similar names for three variables.
    __MIDL_ProcFormatString replaced by __MIDL_ProcFormatString2
    
    __MIDL_TypeFormatString replaced by  __MIDL_TypeFormatString2
    
    <interface_name>_StubDesc replaced by <interface_name>_StubDesc2
    

    The changes above should be done just in the client side of the source code.

    We can't use one instance of those variables for the client and the server side, because in each situation those variables have different values;

  2. Add all the files needed to be involved in the RPC story, in one project, rather than while the RPC is regular implemented - in two different projects.
  3. Also, change the name of the functions involved in the RPC story:
    <func-name>(<parameters>) to <func-name>2(<parameters>).
    

    This is a snippet code from the demo project. The server side interface implements the GetName function. Because both the client side and the server side implements the following function:

    void GetName(
     /* [size_is][string][out] */ unsigned char __RPC_FAR name[  ])
    {
     ....
    }
    

    ...and because we compiled together the client and the server code, we have to change the func-name in the server side to avoid duplication, as follows:

    MC++
    void GetName2(
     /* [size_is][string][out] */ unsigned char __RPC_FAR name[  ])
    {
     ....
    }
    

    This is the function generated by MIDL - the one and only change is the name of the internal function GetName (the pure implementation func - stub naked).

    MIDL
    void __RPC_STUB
    details_GetName(
        PRPC_MESSAGE _pRpcMessage )
    {
        MIDL_STUB_MESSAGE _StubMsg;
        unsigned char ( __RPC_FAR *name )[  ];
        RPC_STATUS _Status;
        
        ((void)(_Status));
        NdrServerInitializeNew(
                              _pRpcMessage,
                              &_StubMsg,
                              &details_StubDesc);
        
        name = 0;
        RpcTryFinally
            {
            RpcTryExcept
                {
                if(_StubMsg.Buffer > _StubMsg.BufferEnd)
                    {
                    RpcRaiseException(RPC_X_BAD_STUB_DATA);
                    }
                }
            RpcExcept( RPC_BAD_STUB_DATA_EXCEPTION_FILTER )
                {
                RpcRaiseException(RPC_X_BAD_STUB_DATA);
                }
            RpcEndExcept
            if(100 * 1 < 0)
                {
                RpcRaiseException(RPC_X_INVALID_BOUND);
                }
            name = (unsigned char (*)[])NdrAllocate(&_StubMsg,100 * 1);
            
            // GetName(*name) is the original source line produced
            // by midl compiler.
            GetName2(*name); 
                             
            
            _StubMsg.BufferLength = 0U;
            _StubMsg.MaxCount = 100;
            
            NdrConformantStringBufferSize( 
                 (PMIDL_STUB_MESSAGE) &_StubMsg,
                 (unsigned char __RPC_FAR *)*name,
                 (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[2] );
            
            _pRpcMessage->BufferLength = _StubMsg.BufferLength;
            
            _Status = I_RpcGetBuffer( _pRpcMessage ); 
            if ( _Status )
                RpcRaiseException( _Status );
            
            _StubMsg.Buffer = 
              (unsigned char __RPC_FAR *) _pRpcMessage->Buffer;
            
            _StubMsg.MaxCount = 100;
            
            NdrConformantStringMarshall( 
                 (PMIDL_STUB_MESSAGE)& _StubMsg,
                 (unsigned char __RPC_FAR *)*name,
                 (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[2] );
            
            }
        RpcFinally
            {
            if ( name )
                _StubMsg.pfnFree( name );
            
            }
        RpcEndFinally
        _pRpcMessage->BufferLength = 
            (unsigned int)((long)_StubMsg.Buffer - 
            (long)_pRpcMessage->Buffer);
        
    }

Practice

To test the demo-project, launch two copies of the GETNAME application. In any copy type two distinguish end points, and your name against your enemy's name (or your wife - ditto).

         end point of    end point of     your name
         remote server   local server
        ---------------  -------------    ------------

app A -   55459            55460            moshe     

app B -   55460            55459            shoshana

Click on PlayServer button on both copies. As you can see, each application points to the other application, so the communication is bi-directional. Thus each application is both the client and the server, with the same request (i.e. - get the name from the remote application).

The IP in this demo, represented by 'localhost' string, points to the local computer, represented by 'localhost'.

Click on 'get name from remote server' button - in each copy of the application, and you will get the name of the opposite application's user.

Bravo !!!

Compatibility note

The demo project works well in Windows 98 and Windows 2000.

Clarification

To make it simple and to highlight the topic of this article, I didn't use some necessary code (RPC exception, thread's status checking of activities from cradle to garden of Eden and other useful status handling).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Israel Israel
I'm just a small brain connected to an un-limited
brains network, which lead directly to the top ten
giant minds. Which lead me to the
thought : who am i?

I am just a jerry-built god !

Comments and Discussions

 
SuggestionA MIDL-only solution (no changes in generated code) Pin
Michael Videlgauz18-Jul-11 0:00
Michael Videlgauz18-Jul-11 0:00 
QuestionAbt. two-way RPC [modified] Pin
adm6-Mar-08 17:23
adm6-Mar-08 17:23 
GeneralApplication as Services Pin
Abhibt13-Jun-06 20:48
Abhibt13-Jun-06 20:48 
GeneralRPC for server implementation Pin
rdhamija2-Mar-05 0:18
rdhamija2-Mar-05 0:18 
GeneralTo get it to work with XP SP2 Pin
OmegaMan31-Aug-04 4:20
OmegaMan31-Aug-04 4:20 
GeneralRe: To get it to work with XP SP2 Pin
fgdfgdgfdg26-Jan-07 22:17
fgdfgdgfdg26-Jan-07 22:17 
GeneralRe: To get it to work with XP SP2 Pin
Codtor24-Mar-09 3:17
Codtor24-Mar-09 3:17 
Generalmultiple RPCs in one process. Pin
leonmccalla@hotmail.com31-May-04 9:04
leonmccalla@hotmail.com31-May-04 9:04 
GeneralRe: multiple RPCs in one process. Pin
Abhibt13-Jun-06 20:47
Abhibt13-Jun-06 20:47 
General/Prefix Pin
leonmccalla@hotmail.com31-May-04 8:49
leonmccalla@hotmail.com31-May-04 8:49 
GeneralMulti Agent System working (Distributed Systems) Pin
brahmos31-Jan-04 1:30
brahmos31-Jan-04 1:30 
Generalcodepage error in compiling rpc Pin
dazza00014-May-03 0:53
dazza00014-May-03 0:53 
GeneralRe: codepage error in compiling rpc Pin
moshe masas14-May-03 12:37
moshe masas14-May-03 12:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.