トランザクション管理 (Data Exchange)
サーバーとの会話を確立した後、クライアントはトランザクションを送信して、サーバーからデータとサービスを取得できます。
次のトピックでは、クライアントがサーバーとの対話に使用できるトランザクションの種類について説明します。
- 要求トランザクション
- トランザクションをポーク
- トランザクションのアドバイス
- トランザクションを実行します
- 同期トランザクションと非同期トランザクション
- トランザクション コントロール
- トランザクション クラス
- トランザクションの種類
要求トランザクション
クライアント アプリケーションは、 XTYP_REQUEST トランザクションを使用して、サーバー アプリケーションにデータ項目を要求できます。 クライアントは DdeClientTransaction 関数を呼び出し、トランザクションの種類として XTYP_REQUEST を指定し、アプリケーションに必要なデータ項目を指定します。
動的データ交換管理ライブラリ (DDEML) は、クライアントによって要求されたトピック名、アイテム名、およびデータ形式を指定して、 XTYP_REQUEST トランザクションをサーバーに渡します。 サーバーが要求されたトピック、項目、および形式をサポートしている場合、サーバーはアイテムの現在の値を識別するデータ ハンドルを返す必要があります。 DDEML は、このハンドルを DdeClientTransaction からの 戻り値としてクライアントに渡します。 要求されたトピック、項目、または形式がサポートされていない場合、サーバーは NULL を返す必要があります。
DdeClientTransaction は lpdwResult パラメーターを使用して、トランザクション状態フラグをクライアントに返します。 サーバーが XTYP_REQUEST トランザクションを処理しない場合、 DdeClientTransaction は NULL を返し、 lpdwResult は DDE_FNOTPROCESStandard Edition D または DDE_FBUSY フラグを指します。 DDE_FNOTPROCESStandard Edition D フラグが返された場合、クライアントはサーバーがトランザクションを処理しなかった理由を判断できません。
サーバーが XTYP_REQUEST トランザクションをサポートしていない場合は、 DdeInitialize 関数で CBF_FAIL_REQUESTS フィルター フラグを指定する必要があります。 このフラグにより、DDEML はトランザクションをサーバーに送信できなくなります。
トランザクションをポーク
クライアントは、 DdeClientTransaction を使用してサーバーのコールバック関数に XTYP_POKE トランザクションを送信することで、要求されていないデータをサーバーに送信できます。
クライアント アプリケーションは、まず、サーバーに送信するデータを含むバッファーを作成し、そのバッファーへのポインターをパラメーターとして DdeClientTransaction に渡します。 または、クライアントは DdeCreateDataHandle 関数を使用して、データを識別するデータ ハンドルを取得し、そのハンドルを DdeClientTransaction に渡すことができます。 どちらの場合も、クライアントは DdeClientTransaction を呼び出すときにトピック名、項目名、およびデータ形式も指定します。
DDEML は、クライアントが要求した トピック名、項目名、およびデータ形式を指定して、 XTYP_POKE トランザクションをサーバーに渡します。 データ項目と形式を受け入れるために、サーバーはDDE_FACKを返す必要があります。 データを拒否するには、サーバーは DDE_FNOTPROCESStandard Edition D を返す必要があります。 サーバーがビジー状態でデータを受け入れられない場合、サーバーはDDE_FBUSY を返す必要があります。
DdeClientTransaction が返されると、クライアントは lpdwResult パラメーターを使用してトランザクション状態フラグにアクセスできます。 フラグがDDE_FBUSYの場合、クライアントは後でトランザクションをもう一度送信する必要があります。
サーバーが XTYP_POKE トランザクションをサポートしていない場合は、 DdeInitialize で CBF_FAIL_POKES フィルター フラグを指定する必要があります。 このフラグにより、DDEML は、このトランザクションをサーバーに送信できなくなります。
トランザクションのアドバイス
クライアント アプリケーションは、DDEML を使用して、サーバー アプリケーション内の項目への 1 つ以上のリンクを確立できます。 このようなリンクが確立されると、サーバーはリンクされたアイテムに関する定期的な更新をクライアントに送信します (通常、サーバー アプリケーションに関連付けられている項目の値が変更されるたびに)。 リンクにより、クライアントが終了するまでメインする 2 つのアプリケーション間にアドバイズ ループが確立されます。
アドバイズ ループには、"hot" と "warm" の 2 種類があります。ホット アドバイズ ループでは、サーバーは変更された値を識別するデータ ハンドルをすぐに送信します。 ウォーム アドバイズ ループでは、サーバーはアイテムの値が変更されたことをクライアントに通知しますが、クライアントが要求するまでデータ ハンドルを送信しません。
クライアントは、 DdeClientTransaction の呼び出しで XTYP_ADVSTART トランザクションの種類を指定することで、サーバーとのホット アドバイズ ループを要求できます。 ウォーム アドバイズ ループを要求するには、クライアントは XTYPF_NODATAXTYP_ADVSTART フラグと トランザクションの種類を組み合わせる必要があります。 いずれの場合も、DDEML は XTYP_ADVSTART トランザクションをサーバーの Dynamic Data Exchange (DDE) コールバック関数に渡します。 サーバーの DDE コールバック関数は、 XTYP_ADVSTART トランザクションに付随するパラメーター (要求された形式、トピック名、項目名を含む) を調べ、 TRUE を返して、アドバイズ ループまたは FALSE が拒否できるようにする必要があります。
アドバイズ ループが確立されると、要求された項目名に関連付けられている項目の値が変更されるたびに、サーバー アプリケーションは DdePostAdvise 関数を呼び出す必要があります。 この呼び出しにより、 XTYP_ADVREQ トランザクションがサーバー独自の DDE コールバック関数に送信されます。 サーバーの DDE コールバック関数は、データ項目の新しい値を識別するデータ ハンドルを返す必要があります。 次に、DDEML は、 XTYP_ADVDATA トランザクションをクライアントの DDE コールバック関数に送信することによって、指定された項目が変更されたことをクライアントに通知します。
クライアントがホット アドバイズ ループを要求した場合、DDEML は、 XTYP_ADVDATA トランザクション中に変更された項目にデータ ハンドルをクライアントに渡します。 それ以外の場合、クライアントは XTYP_REQUEST トランザクションを送信してデータ ハンドルを取得できます。
サーバーは、クライアントが新しいデータを処理するよりも速く更新プログラムを送信できます。 更新の速度は、データに対して長い処理操作を実行する必要があるクライアントにとって問題になる可能性があります。 この場合、クライアントは、アドバイズ ループを要求するときに、XTYPF_ACKREQ フラグを指定する必要があります。 このフラグは、サーバーが次のデータ項目を送信する前に、クライアントがデータ項目を受信して処理したことをクライアントが確認するのを待機させます。 XTYPF_ACKREQ フラグを使用して確立されたアドバイズ ループは、高速サーバーの方が堅牢ですが、更新を見逃す場合があります。 XTYPF_ACKREQ フラグなしで確立されたアドバイズ ループは、クライアントがサーバーに対応している限り、更新を見逃さないことを保証します。
クライアントは、 DdeClientTransaction の呼び出しで XTYP_ADVSTOP トランザクションの種類を指定することで、アドバイズ ループを終了できます。
サーバーがアドバイズ ループをサポートしていない場合は、 DdeInitialize 関数で CBF_FAIL_ADVIStandard Edition S フィルター フラグを指定する必要があります。 このフラグにより、DDEML は XTYP_ADVSTART および XTYP_ADVSTOP トランザクションをサーバーに送信できなくなります。
トランザクションを実行します
クライアントは、 XTYP_EXECUTE トランザクションを使用して、サーバーにコマンドまたは一連のコマンドを実行させることができます。
サーバー コマンドを実行するために、クライアントは最初にサーバーが実行するコマンド文字列を含むバッファーを作成し、 DdeClientTransaction を呼び出すときにバッファーを識別するバッファーまたはデータ ハンドルへのポインターを渡します。 その他の必須パラメーターには、会話ハンドル、項目名文字列ハンドル、書式指定、および XTYP_EXECUTE トランザクションの種類が含まれます。 実行データを渡すデータ ハンドルを作成するアプリケーションでは、 DdeCreateDataHandle 関数の hszItem パラメーターに NULL を指定し、 uFmt パラメーターにゼロを指定する必要があります。
DDEML は、 XTYP_EXECUTE トランザクションをサーバーの DDE コールバック関数に渡し、コマンド文字列を識別する形式名、会話ハンドル、トピック名、およびデータ ハンドルを指定します。 サーバーでコマンドがサポートされている場合は、 DdeAccessData 関数を使用してコマンド文字列へのポインターを取得し、コマンドを実行してから、DDE_FACK を返す必要があります。 サーバーがコマンドをサポートしていない場合、またはトランザクションを完了できない場合は、DDE_FNOTPROCESStandard Edition D を返す必要があります。 トランザクションを完了するにはビジー状態が多すぎる場合、サーバーはDDE_FBUSYを返す必要があります。
一般に、サーバーのコールバック関数は、次の例外を 除いて戻る前に、 XTYP_EXECUTE トランザクションを処理する必要があります。
- XTYP_EXECUTE トランザクションで渡されたコマンドがサーバーに終了を要求した場合、コールバック関数が XTYP_EXECUTE の処理から戻るまで、サーバーは終了しないでください。
- DDEML 再帰の問題を引き起こす可能性があるダイアログ ボックスや DDE トランザクションの処理などの操作をサーバーが実行する必要がある場合、サーバーは、実行トランザクションをブロックし、操作を実行して実行トランザクションの処理を再開するCBR_BLOCKリターン コードを返す必要があります。
DdeClientTransaction が返されると、クライアントは lpdwResult パラメーターを使用してトランザクション状態フラグにアクセスできます。 フラグがDDE_FBUSYの場合、クライアントは後でトランザクションをもう一度送信する必要があります。
サーバーが XTYP_EXECUTE トランザクションをサポートしていない場合は、 DdeInitialize 関数で CBF_FAIL_EXEUTES フィルター フラグを指定する必要があります。 これにより、DDEML はトランザクションをサーバーに送信できなくなります。
同期トランザクションと非同期トランザクション
クライアントは、同期トランザクションまたは非同期トランザクションを送信できます。 同期トランザクションでは、クライアントは、サーバーがトランザクションを処理するのを待機する最大時間を示すタイムアウト値を指定します。 DdeClientTransaction は、サーバーがトランザクションを処理するか、トランザクションが失敗するか、タイムアウト値が期限切れになるまで戻りません。 クライアントは、 DdeClientTransaction を呼び出 すときにタイムアウト値を指定します。
同期トランザクション中、クライアントはトランザクションが処理されるのを待っている間にモーダル ループに入ります。 クライアントは引き続きユーザー入力を処理できますが、 DdeClientTransaction が戻るまで別の同期トランザクションを送信することはできません。
クライアントは、 DdeClientTransaction で TIMEOUT_ASYNC フラグを指定して非同期トランザクションを送信します。 この関数は、トランザクションが開始された後に戻り、トランザクション識別子をクライアントに渡します。 サーバーが非同期トランザクションの処理を完了すると、DDEML は XTYP_XACT_COMPLETE トランザクションをクライアントに送信します。 XTYP_XACT_COMPLETE トランザクション中 に DDEML がクライアントに渡すパラメーターの 1 つがトランザクション識別子です。 このトランザクション識別子と DdeClientTransaction によって返される識別子を比較することで、クライアントはサーバーが処理を完了した非同期トランザクションを識別します。
クライアントは、非同期トランザクションの処理の 補助として DdeSetUserHandle 関数を使用できます。 この関数を使用すると、クライアントはアプリケーション定義の値を会話ハンドルとトランザクション識別子に関連付けることができます。 クライアントは、 XTYP_XACT_COMPLETE トランザクション中に DdeQueryConvInfo 関数を使用して、アプリケーション定義の値を取得できます。 この関数により、アプリケーションにアクティブなトランザクション識別子の一覧をメイン含める必要はありません。
クライアントが同期トランザクションを使用してデータの要求を正常に完了すると、DDEML は、クライアントが受信したデータの使用を完了したタイミングを確認する方法はありません。 クライアント アプリケーションは、受信したデータ ハンドルを DdeFreeDataHandle 関数に渡し、ハンドルが使用されなくなることを DDEML に通知する必要があります。 同期トランザクションによって返されるデータ ハンドルは、クライアントによって実質的に所有されます。
サーバーが非同期トランザクションをタイムリーに処理しない場合、クライアントは DdeAbandonTransaction 関数を呼び出すことによってトランザクションを破棄できます。 DDEML は、トランザクションに関連付けられているすべてのリソースを解放しカードサーバーがトランザクションの処理を完了したときにトランザクションの結果を破棄します。 同期トランザクション中のタイムアウトは、トランザクションを実質的に取り消します。
非同期トランザクションメソッドは、大量の DDE トランザクションを送信しながら、計算などの大量の処理を同時に実行する必要があるアプリケーションに対して提供されます。 非同期メソッドは、DDE トランザクションを中断せずに他のタスクを完了できるように、DDE トランザクションの処理を一時的に停止する必要があるアプリケーションでも役立ちます。 他のほとんどの状況では、アプリケーションで同期メソッドを使用する必要があります。
同期トランザクションは保持が簡単で、非同期トランザクションよりも高速です。 ただし、一度に実行できる同期トランザクションは 1 つだけですが、多くの非同期トランザクションを同時に実行できます。 同期トランザクションを使用すると、サーバーが遅いと、クライアントが応答を待機している間にアイドル状態に保持する可能性があります。 また、同期トランザクションにより、クライアントはモーダル ループに入り、アプリケーション独自のメッセージ ループでメッセージ フィルター処理をバイパスできます。
クライアントがメッセージをフィルター処理するフック プロシージャをインストールしている場合 (つまり、 SetWindowsHookEx 関数の呼び出しでWH_MSGFILTERフックの種類を指定した場合)、同期トランザクションによってシステムはフック プロシージャをバイパスしません。 クライアントが同期トランザクションの終了を待機している間に入力イベントが発生すると、フック プロシージャはMSGF_DDEMGRフック コードを受け取ります。 同期トランザクション モーダル ループを使用するメインの危険性は、ダイアログ ボックスによって作成されたモーダル ループがその操作を妨げる可能性があるということです。 DDEML が DLL によって使用されている場合は、非同期トランザクションを常に使用する必要があります。
トランザクション コントロール
アプリケーションは、特定の会話ハンドルに関連付けられているトランザクション、または会話ハンドルに関係なくすべてのトランザクションのいずれかによって、DDE コールバック関数へのトランザクションを中断できます。 この機能は、長い処理を必要とするトランザクションをアプリケーションが受信する場合に便利です。 このような場合、アプリケーションはCBR_BLOCKリターン コードを返して、トランザクションの会話ハンドルに関連付けられている将来のトランザクションを中断して、アプリケーションが他の会話を自由に処理できるようにします。
処理が完了すると、アプリケーションは DdeEnableCallback 関数を呼び出して、中断された会話に関連付けられているトランザクションを再開します。 DdeEnableCallback を呼び出すと、アプリケーションが会話を中断する原因になったトランザクションが DDEML によって再送信されます。 そのため、アプリケーションは、トランザクションを再処理せずに結果を取得して返すように、トランザクションの結果を格納する必要があります。
アプリケーションは、 DdeEnableCallback の呼び出しでハンドルとEC_DISABLE フラグを指定することで、特定の会話ハンドルに関連付けられているすべてのトランザクションを中断できます。 NULL ハンドルを指定することで、アプリケーションはすべての会話のすべてのトランザクションを中断できます。
会話が中断されると、DDEML は会話のトランザクションをトランザクション キューに保存します。 アプリケーションが会話を再び有効にすると、DDEML は保存されたトランザクションをキューから削除し、各トランザクションを適切なコールバック関数に渡します。 トランザクション キューの容量は大きくなりますが、トランザクションが失われるのを防ぐために、アプリケーションはできるだけ早く中断された会話を再び有効にする必要があります。
アプリケーションは、 DdeEnableCallback で EC_ENABLEALL フラグを指定することで、通常のトランザクション処理を再開できます。 トランザクション処理の再開をより制御するには、アプリケーションで EC_ENABLEONE フラグを指定できます。 このフラグは、トランザクション キューから 1 つのトランザクションを削除し、適切なコールバック関数に渡します。そのトランザクションが処理された後、会話は再度無効になります。
DdeEnableCallback の呼び出しでEC_ENABLEONE フラグと会話ハンドルが指定されている場合、トランザクションの処理後にその会話のみがブロックされます。 NULL 会話ハンドルが指定されている場合、任意の会話でトランザクションが処理された後、すべての会話がブロックされます。
トランザクション クラス
DDEML には、トランザクションの 4 つのクラスがあります。 各クラスは、XCLASS_ プレフィックスで始まる定数によって識別されます。 クラスは DDEML ヘッダー ファイルで定義されます。 クラス値はトランザクション型の値と組み合わされ、受信側アプリケーションの DDE コールバック関数に渡されます。
トランザクションのクラスは、コールバック関数がトランザクションを処理する場合に返される戻り値を決定します。 次の戻り値とトランザクションの種類は、4 つの各トランザクション クラスに関連付けられています。
クラス | 戻り値 | 取引 |
---|---|---|
XCLASS_BOOL | TRUE または FALSE | XTYP_ADVSTART XTYP_CONNECT |
XCLASS_DATA | データ ハンドル、CBR_BLOCKリターン コード、または NULL | XTYP_ADVREQ XTYP_REQUEST XTYP_WILDCONNECT |
XCLASS_FLAGS | トランザクション フラグ: DDE_FACK、DDE_FBUSY、または DDE_FNOTPROCESSED | XTYP_ADVDATA XTYP_EXECUTE XTYP_POKE |
XCLASS_NOTIFICATION | なし | XTYP_ADVSTOP XTYP_CONNECT_CONFIRM XTYP_DISCONNECT XTYP_ERROR XTYP_REGISTER XTYP_UNREGISTER XTYP_XACT_COMPLETE |
Transaction Types
各 DDE トランザクションの種類には、受信者と、DDEML が各型を生成するアクティビティが関連付けられています。
トランザクションの種類 | 受領者 | 原因 |
---|---|---|
XTYP_ADVDATA | クライアント | サーバーは、データ ハンドルを 返すことによって、 XTYP_ADVREQ トランザクションに応答しました。 |
XTYP_ADVREQ | [サーバー] | サーバーは DdePostAdvise 関数を呼び出し、アドバイズ ループ内のデータ項目の値が変更されたことを示します。 |
XTYP_ADVSTART | [サーバー] | クライアントは、 DdeClientTransaction 関数の呼び出しで XTYP_ADVSTART トランザクションの種類を指定しました。 |
XTYP_ADVSTOP | [サーバー] | クライアントが DdeClientTransaction の呼び出しで XTYP_ADVSTOP トランザクションの種類を指定しました。 |
XTYP_CONNECT | [サーバー] | クライアントは DdeConnect 関数を呼び出し、サーバーでサポートされるサービス名とトピック名を指定しました。 |
XTYP_CONNECT_CONFIRM | [サーバー] | サーバーは、 XTYP_CONNECT または XTYP_WILDCONNECT トランザクションに応答して TRUE を返しました。 |
XTYP_DISCONNECT | クライアント/サーバー | 会話のパートナーが DdeDisconnect 関数と呼ばれ、両方のパートナーがこのトランザクションを受け取ります。 |
XTYP_ERROR | クライアント/サーバー | クリティカル エラーが発生しました。 DDEML には、続行するのに十分なリソースがない可能性があります。 |
XTYP_EXECUTE | [サーバー] | クライアントが DdeClientTransaction の呼び出しで XTYP_EXECUTE トランザクションの種類を指定しました。 |
XTYP_MONITOR | DDE モニタリング アプリケーション | DDE イベントがシステムで発生しました。 DDE 監視アプリケーションの詳細については、「アプリケーションの監視」を参照してください。 |
XTYP_POKE | [サーバー] | クライアントが DdeClientTransaction の呼び出しで XTYP_POKE トランザクションの種類を指定しました。 |
XTYP_REGISTER | クライアント/サーバー | サーバー アプリケーションは、 DdeNameService 関数を使用してサービス名を登録しました。 |
XTYP_REQUEST | [サーバー] | クライアントが DdeClientTransaction の呼び出しで XTYP_REQUEST トランザクションの種類を指定しました。 |
XTYP_UNREGISTER | クライアント/サーバー | サーバー アプリケーションは、 DdeNameService を使用してサービス名の登録を解除しました。 |
XTYP_WILDCONNECT | [サーバー] | サービス名、トピック名、またはその両方に NULL を指定して、 DdeConnect または DdeConnectList 関数を呼び出したクライアント。 |
XTYP_XACT_COMPLETE | クライアント | クライアントが DdeClientTransaction の呼び出しでTIMEOUT_ASYNC フラグを指定したときに送信される非同期トランザクションが終了しました。 |