进行异步调用

客户端必须先初始化异步句柄,然后才能进行异步远程调用。 客户端和服务器程序使用指向异步句柄 RPC_ASYNC_STATE 结构的指针。

每个未完成的调用都必须有其自己唯一的异步句柄。 客户端创建句柄并将其传递给 RpcAsyncInitializeHandle 函数。 为了使调用正确完成,客户端必须确保在收到服务器的异步回复之前不会释放句柄的内存。 此外,在对现有异步句柄进行另一次调用之前,客户端必须重新初始化句柄。 否则,可能导致客户端存根在调用期间引发异常。 客户端还必须确保为异步远程过程提供的 [out] 参数和 [inout] 参数的缓冲区保持分配状态,直到收到来自服务器的回复。

调用异步远程过程时,客户端必须选择 RPC 运行时库将用来通知调用完成的方法。 客户端可以通过以下任一方式接收此通知:

  • 事件。 客户端可以指定要在调用完成时触发的事件。 有关详细信息,请参阅 事件对象

  • 轮询。 客户端可以重复调用 RpcAsyncGetCallStatus。 如果返回值不是RPC_S_ASYNC_CALL_PENDING,则调用完成。 此方法使用的 CPU 时间比此处所述的其他方法多。

  • Apc。 客户端可以指定 异步过程调用 (调用 完成时调用的 APC) 。 有关 APC 函数的原型,请参阅 RPCNOTIFICATION_ROUTINE。 调用 APC 时,其 Event 参数设置为 RpcCallComplete。 若要调度 APC,客户端线程必须处于可警报等待状态。

    如果异步句柄中的 hThread 字段设置为 0,则 APC 在进行异步调用的线程上排队。 如果为非零值,则 APC 在 m 指定的线程上排队。

  • 国际 奥委会。 使用异步句柄中指定的参数通知 I/O 完成端口。 有关详细信息,请参阅 CreateIoCompletionPort

  • Windows 句柄。 消息将发布到指定的窗口句柄 (HWND) 。

以下代码片段演示初始化异步句柄并使用它进行异步远程过程调用所需的基本步骤。

RPC_ASYNC_STATE Async;
RPC_STATUS status;
 
// Initialize the handle.
status = RpcAsyncInitializeHandle(&Async, sizeof(RPC_ASYNC_STATE));
if (status)
{
    // Code to handle the error goes here.
}
 
Async.UserInfo = NULL;
Async.NotificationType = RpcNotificationTypeEvent;
 
Async.u.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (Async.u.hEvent == 0)
{
    // Code to handle the error goes here.
}
// Call an asynchronous RPC routine here
RpcTryExcept
{
    printf("\nCalling the remote procedure 'AsyncFunc'\n");
    AsyncFunc(&Async, AsyncRPC_ClientIfHandle, nAsychDelay);
}
RpcExcept(1)
{
    ulCode = RpcExceptionCode();
    printf("AsyncFunc: Run time reported exception 0x%lx = %ld\n", 
            ulCode, ulCode);
}
RpcEndExcept
 
// Call a synchronous routine while
// the asynchronous procedure is still running
RpcTryExcept
{
    printf("\nCalling the remote procedure 'NonAsyncFunc'\n");
    NonAsyncFunc(AsyncRPC_ClientIfHandle, pszMessage);
    fprintf(stderr, 
            "While 'AsyncFunc' is running asynchronously,\n"
            "we still can send message to the server in the mean "
            "time.\n\n");
}
RpcExcept(1)
{
    ulCode = RpcExceptionCode();
    printf("NonAsyncFunc: Run time reported exception 0x%lx = %ld\n", 
            ulCode, ulCode);
}
RpcEndExcept

如本示例所示,当异步过程调用仍处于挂起状态时,客户端程序可以执行同步远程过程调用。 此客户端为 RPC 运行时库创建一个事件对象,用于在异步调用完成时通知它。

注意

如果在异步调用期间引发 RPC 异常,则不会从异步 RPC 例程返回完成通知。