Share via


非同期呼び出しの作成

非同期リモート呼び出しを行う前に、クライアントは非同期ハンドルを初期化する必要があります。 クライアント プログラムとサーバー プログラムは、非同期ハンドルに RPC_ASYNC_STATE 構造体へのポインターを使用します。

未処理のすべての呼び出しには、独自の一意の非同期ハンドルが必要です。 クライアントはハンドルを作成し、 RpcAsyncInitializeHandle 関数に渡します。 呼び出しが正しく完了するには、クライアントがサーバーの非同期応答を受信するまでハンドルのメモリが解放されないようにする必要があります。 また、既存の非同期ハンドルに対して別の呼び出しを行う前に、クライアントはハンドルを再初期化する必要があります。 これを行わないと、クライアント スタブが呼び出し中に例外を発生させる可能性があります。 また、クライアントは、非同期リモート プロシージャに対して [out] パラメーターと [in, out] パラメーターに提供するバッファーが、サーバーから応答を受信するまで割り当てられたままになります。

非同期リモート プロシージャを呼び出すとき、クライアントは、RPC ランタイム ライブラリが呼び出しの完了を通知するために使用するメソッドを選択する必要があります。 クライアントは、次のいずれかの方法でこの通知を受信できます。

  • イベント。 クライアントは、呼び出しが完了したときに発生するイベントを指定できます。 詳細については、「 イベント オブジェクト」を参照してください。

  • ポーリング。 クライアントは 、RpcAsyncGetCallStatus を繰り返し呼び出すことができます。 戻り値がRPC_S_ASYNC_CALL_PENDING以外の値である場合、呼び出しは完了です。 この方法では、ここで説明する他の方法よりも多くの CPU 時間が使用されます。

  • Apc。 クライアントは、 呼び出しが完了したときに呼び出される非同期プロシージャ 呼び出し (APC) を指定できます。 APC 関数のプロトタイプについては、「 RPCNOTIFICATION_ROUTINE」を参照してください。 APC は、Event パラメーターを RpcCallComplete に設定して呼び出されます。 APC がディスパッチされるには、クライアント スレッドがアラート可能な待機状態である必要があります。

    非同期ハンドルの hThread フィールドが 0 に設定されている場合、APC は非同期呼び出しを行ったスレッドでキューに入れられます。 0 以外の場合、APC は m で指定されたスレッドでキューに入れられます。

  • Ioc。 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 ランタイム ライブラリのイベント オブジェクトを作成します。

Note

非同期呼び出し中に RPC 例外が発生した場合、非同期 RPC ルーチンから完了の通知は返されません。