次の方法で共有


コンテキスト ハンドルを使用したサーバー開発

サーバー プログラム開発の観点からは、コンテキスト ハンドルは型指定されていないポインターです。 サーバー プログラムは、メモリ内のデータまたは他の形式のストレージ (ディスク上のファイルなど) を指すことによってコンテキスト ハンドルを初期化します。

たとえば、クライアントがコンテキスト ハンドルを使用して、データベース内のレコードに対する一連の更新を要求するとします。 クライアントはサーバー上でリモート プロシージャを呼び出し、検索キーを渡します。 サーバー プログラムは、データベースで検索キーを検索し、一致するレコードの整数レコード番号を取得します。 その後、サーバーは、レコード番号を含むメモリの場所で void へのポインターをポイントできます。 が返されるときに、リモート プロシージャは、戻り値またはそのパラメーター リストを介してコンテキスト ハンドルとしてポインターを返す必要があります。 クライアントは、レコードを更新するためにリモート プロシージャを呼び出すたびに、ポインターをサーバーに渡す必要があります。 これらの更新操作のたびに、サーバーは void ポインターを整数へのポインターとしてキャストします。

サーバー プログラムがコンテキスト データでコンテキスト ハンドルをポイントすると、ハンドルは開いていると見なされます。 NULL 値を含むハンドルは閉じられます。 サーバーは、クライアントがそれを閉じるリモート プロシージャを呼び出すまで、開かれたコンテキスト ハンドルを保持します。 ハンドルが開いている間にクライアント セッションが終了した場合、RPC ランタイムはサーバーのランダウン ルーチンを呼び出してハンドルを解放します。

次のコード フラグメントは、サーバーがコンテキスト ハンドルを実装する方法を示しています。 この例では、サーバーは、リモート プロシージャを使用してクライアントが書き込むデータ ファイルを保持します。 コンテキスト情報は、サーバーがデータを書き込むファイル内の現在の場所を追跡するファイル ハンドルです。 ファイル ハンドルは、リモート プロシージャ呼び出しのパラメーター リストのコンテキスト ハンドルとしてパッケージ化されます。 構造体には、ファイル名とファイル ハンドルが含まれています。 この例のインターフェイス定義は、「 コンテキスト ハンドルを使用したインターフェイス開発」に示されています。

/* cxhndlp.c (fragment of file containing remote procedures) */
typedef struct 
{
     FILE* hFile;
     char   achFile[256];
} FILE_CONTEXT_TYPE;

RemoteOpen 関数は、サーバー上のファイルを開きます。

short RemoteOpen(
    PPCONTEXT_HANDLE_TYPE pphContext,
    unsigned char *pszFileName)
{
    FILE               *hFile;
    FILE_CONTEXT_TYPE  *pFileContext;
 
    if ((hFile = fopen(pszFileName, "r")) == NULL) 
    {
        *pphContext = (PCONTEXT_HANDLE_TYPE) NULL;
        return(-1);
    }
    else 
    {
        pFileContext = (FILE_CONTEXT_TYPE *) 
                       MIDL_user_allocate(sizeof(FILE_CONTEXT_TYPE));
        pFileContext->hFile = hFile;
        // check if pszFileName is longer than 256 and if yes, return
        // an error
        strcpy_s(pFileContext->achFile, srlen(pszFileName), pszFileName);
        *pphContext = (PCONTEXT_HANDLE_TYPE) pFileContext;
        return(0);
    }
}

RemoteRead 関数は、サーバー上のファイルを読み取ります。

short RemoteRead(
    PCONTEXT_HANDLE_TYPE phContext, 
    unsigned char *pbBuf, 
    short *pcbBuf) 
{ 
    FILE_CONTEXT_TYPE *pFileContext; 
    printf("in RemoteRead\n"); 
    pFileContext = (FILE_CONTEXT_TYPE *) phContext; 
    *pcbBuf = (short) fread(pbBuf, sizeof(char), 
                            BUFSIZE, 
                            pFileContext->hFile); 
    return(*pcbBuf); 
}

RemoteClose 関数は、サーバー上のファイルを閉じます。 サーバー アプリケーションは、close 関数の一部としてコンテキスト ハンドルに NULL を 割り当てる必要があることに注意してください。 これにより、コンテキスト ハンドルが削除されたことをサーバー スタブと RPC ランタイム ライブラリに伝えます。 それ以外の場合、接続は開いたままになり、最終的にはコンテキストランダウンが発生します。

void RemoteClose(PPCONTEXT_HANDLE_TYPE pphContext)
{
    FILE_CONTEXT_TYPE *pFileContext;
 
    if (*pphContext == NULL)
    {
        //Log error, client tried to close a NULL handle.
        return;
    }
    pFileContext = (FILE_CONTEXT_TYPE *)*pphContext;
    printf("File %s closed.\n", pFileContext->achFile);
    fclose(pFileConext->hFile);
    MIDL_user_free(pFileContext);
 
    // This tells the run-time, when it is marshalling the out 
    // parameters, that the context handle has been closed normally.
    *pphContext = NULL;
}

注意

クライアントが [in, out] 方向属性を持つ呼び出しに有効なコンテキスト ハンドルを渡すと予想されますが、RPC では、この方向属性の組み合わせに対して NULL コンテキスト ハンドルは拒否されません。 NULL コンテキスト ハンドルは、NULL ポインターとしてサーバーに渡されます。 NULL ポインターを受け取ったときにアクセス違反を回避するために、[in, out] コンテキスト ハンドルを含む呼び出しのサーバー コードを記述する必要があります。