Server-side Asynchronous RPC

The server application responsibilities are:

Handling Asynchronous Calls

The manager routine of an asynchronous function always receives the asynchronous handle as the first parameter. The server must keep track of this handle and use it to send the reply when it becomes available. The server must also keep track of the top level pointers for the out and in, out parameters, and update them before calling RpcAsyncCompleteCall.

If the server needs to abort an asynchronous RPC, it calls RpcAsyncAbortCall. This API does the same server-side cleanup as RpcAsyncCompleteCall and propagates an exception code (provided by the server application) back to the client.

Receiving Cancellations

The server application can call RpcServerTestCancel with the binding handle of the thread in question to find out if the client has requested a cancellation of an outstanding asynchronous call.

Sending The Reply

When the asynchronous call is complete, the server sends a reply to the client by calling RpcAsyncCompleteCall on the asynchronous handle. This call is necessary even if the asynchronous call has a void return value and no out parameters. If the function has a return value, it is passed by reference to RpcAsyncCompleteCall.

When the server calls RpcAsyncCompleteCall or RpcAsyncAbortCall, or a call completed because an exception was raised in the manager routine, the server's asynchronous handle is automatically destroyed.

Note  The server must finish updating the in, out and out parameters before calling RpcAsyncCompleteCall. No changes can be made to those parameters or to the asynchronous handle after calling RpcAsyncCompleteCall.

Example

//Notice that the server-side CALL_COOKIE contains an asynchronous
//handle, whereas the client-side version contained the actual
//asynchronous state struct.

typedef struct {
  PRPC_ASYNC_STATE pAsync;
  int a ;
  int *c ;
  } CALL_COOKIE;
 
#define APP_ERROR -1
 
static unsigned long DefaultThreadStackSize = 0;
 
//This is the routine that the client calls. It can spawn off an
//asynchronous operation (in this case, a thread) to do the rest 
//of the work and send back the reply when it is done.

void MyAsyncFunc (IN PRPC_ASYNC_STATE pAsync,
                  IN RPC_BINDING_HANDLE hBinding,
                  IN int a,
                  IN int b,
                  OUT int *c)
{
unsigned long ThreadIdentifier;
HANDLE HandleToThread;
CALL_COOKIE *CallCookie;
 
CallCookie = new CALL_COOKIE;
 
CallCookie->pAsync = pAsync ;
CallCookie->a = a;
CallCookie->c = c;
 
HandleToThread = CreateThread (0,
                               DefaultThreadStackSize,
                               (LPTHREAD_START_ROUTINE) ThreadProc,
                               CallCookie,
                               0,
                               &ThreadIdentifier);
// return to the server stub. 
}
 
//This is the thread that sends the reply by
//calling RpcAsyncCompleteCall

void ThreadProc (CALL_COOKIE *Cookie)
{
int retval = 1;
// Fill-in the out params
*(Cookie->c) = 10;
RpcAsyncCompleteCall (Cookie->pAsync, &retval);
}
 

See Also

RPC_ASYNC_STATE, RpcAsyncCompleteCall, RpcAsyncAbortCall, RpcServerTestCancel