基本的な概念 (DDE)
これらの概念は、動的データ交換 (DDE) と動的データ交換管理ライブラリ (DDEML) を理解するための重要な概念です。
クライアントとサーバーの対話
DDE は、クライアント アプリケーションとサーバー アプリケーションの間で常に発生します。 DDE クライアント アプリケーション は、サーバーにトランザクションを送信するサーバーとの会話を確立することによって、交換を開始します。 トランザクションは、データまたはサービスの要求です。 DDE サーバー アプリケーション は、クライアントにデータまたはサービスを提供することによってトランザクションに応答します。 たとえば、グラフィックス アプリケーションには、企業の四半期ごとの利益を表す棒グラフが含まれている場合がありますが、棒グラフのデータはスプレッドシート アプリケーションに含まれている可能性があります。 最新の利益を得るために、グラフィックス アプリケーション (クライアント) はスプレッドシート アプリケーション (サーバー) との会話を確立できます。 その後、グラフィックス アプリケーションは、最新の利益数値を要求して、スプレッドシート アプリケーションにトランザクションを送信できます。
サーバーは同時に多数のクライアントを持つ場合があり、クライアントは複数のサーバーからデータを要求できます。 アプリケーションは、クライアントとサーバーの両方にすることもできます。 クライアントまたはサーバーは、いつでも会話を終了できます。
トランザクションと DDE コールバック関数
DDEML は、アプリケーションの DDE コールバック関数にトランザクションを送信することによって、アプリケーションに影響を与える DDE アクティビティについてアプリケーションに通知します。 DDE トランザクション は、トランザクションに関する追加情報を含む他のパラメーターを伴う名前付き定数であるメッセージに似ています。
DDEML は、トランザクションの種類に適したアクションを実行する、アプリケーション定義の DDE コールバック関数にトランザクションを渡します。 たとえば、クライアント アプリケーションがサーバー アプリケーションとの会話を確立しようとすると、クライアントは DdeConnect 関数を呼び出します。 この関数により、DDEML はサーバーの DDE コールバック関数に XTYP_CONNECT トランザクションを送信します。 コールバック関数は、DDEML に TRUE を返すことによって会話を許可するか、 FALSE を返すことによって会話を拒否できます。 トランザクションの詳細については、「トランザクション管理」を参照してください。
サービス名、トピック名、および項目名
DDE サーバーは、3 レベルの階層サービス名 (以前の DDE ドキュメントでは "アプリケーション名" と呼ばれます) とトピック名、およびアイテム名を使用して、サーバーが会話中に交換できるデータの単位を一意に識別します。
サービス名 は、クライアントがサーバーとの会話を確立しようとしたときにサーバー アプリケーションが応答する文字列です。 クライアントは、サーバーとの会話を確立するために、このサービス名を指定する必要があります。 サーバーは多くのサービス名に応答できますが、ほとんどのサーバーは 1 つの名前にのみ応答します。
トピック名 は、論理データ コンテキストを識別する文字列です。 ファイル ベースのドキュメントを操作するサーバーの場合、トピック名は通常ファイル名です。他のサーバーの場合は、他のアプリケーション固有の文字列です。 クライアントは、サーバーとの会話を確立しようとするときに、トピック名とサーバーのサービス名を指定する必要があります。
項目名 は、トランザクション中にサーバーがクライアントに渡すことができるデータの単位を識別する文字列です。 たとえば、項目名は、整数、文字列、複数のテキストの段落、またはビットマップを識別できます。
サービス名、トピック名、および項目名を使用すると、クライアントはサーバーとの会話を確立し、サーバーからデータを受信できます。
システム トピック
System トピックでは、DDE クライアントに関する一般的な情報のコンテキストを提供します。 サーバー アプリケーションでは、システム トピックを常にサポートすることをお勧めします。 システム トピックは、DDEML.H ヘッダー ファイルで SZDDESYS_TOPIC として定義されます。
クライアント アプリケーションは、存在するサーバーと提供できる情報の種類を決定するために、起動時にシステム トピックに対する会話を要求し、デバイス名を NULL に設定できます。 このようなワイルドカード会話はシステムパフォーマンスの面でコストがかかるため、最小限に抑える必要があります。 DDE 会話の開始の詳細については、「会話の管理」を参照してください。
サーバーは、システム トピック内の次の項目名と、クライアントに役立つその他の項目名をサポートする必要があります。
アイテム | 説明 |
---|---|
SZDDE_ITEM_ITEMLIST | システム以外のトピックでサポートされている項目の一覧。 (この一覧は、瞬間によって、トピックごとに異なる場合があります)。 |
SZDDESYS_ITEM_FORMATS | サービス アプリケーションでサポートされる可能性のあるすべてのクリップボード形式を表す文字列のタブ区切りのリスト。 定義済みのクリップボード形式を表す文字列は、"CF_" プレフィックスが削除されたCF_値と同じです。 たとえば、CF_TEXT形式は文字列 "TEXT" で表されます。 これらの文字列は、定義済みの形式としてさらに識別するために大文字である必要があります。 形式の一覧は、最もリッチなコンテンツから最もリッチなコンテンツの順に表示される必要があります。 クリップボードの形式とレンダリング データの詳細については、「クリップボード」を参照してください。 |
SZDDESYS_ITEM_HELP | ユーザーが読み取り可能な一般的な関心のある情報。 この項目には、少なくともサーバー・アプリケーションの DDE 機能の使用方法に関する情報が含まれている必要があります。 この情報には、トピック内の項目を指定する方法、サーバーが実行できる実行文字列、許可されるポケ トランザクション、および他のシステム トピック項目に関するヘルプの検索方法が含まれますが、これらに限定されません。 |
SZDDESYS_ITEM_RTNMSG | 最近使用 した WM_DDE_ACK メッセージの詳細をサポートします。 この項目は、8 ビットを超えるアプリケーション固有のリターン データが必要な場合に便利です。 |
SZDDESYS_ITEM_STATUS | サーバーの現在の状態を示します。 通常、この項目はCF_TEXT形式のみをサポートし、準備完了またはビジー状態の文字列を含みます。 |
SZDDESYS_ITEM_SYSITEMS | このサーバーのシステム トピックでサポートされている項目の一覧。 |
SZDDESYS_ITEM_TOPICS | サーバーが現在サポートしているトピックの一覧。 (このリストは時々変化する可能性があります。)。 |
これらの項目名は、DDEML.H ヘッダー ファイルで定義された値です。 これらの文字列の文字列ハンドルを取得するには、アプリケーションで DDEML アプリケーション内の他の文字列の場合と同様に、DDEML 文字列管理機能を使用する必要があります。 文字列の管理の詳細については、「文字列の管理」を参照してください 。
初期化
他の DDEML 関数を呼び出す前に、アプリケーションで DdeInitialize 関数を呼び出す必要があります。 DdeInitialize は、アプリケーションのインスタンス識別子を取得し、アプリケーションの DDE コールバック関数を DDE に登録し、コールバック関数のトランザクション フィルター フラグを指定します。
アプリケーションまたは DLL の各インスタンスは、そのインスタンス識別子を idInst パラメーターとして、それを必要とする他の DDEML 関数に渡す必要があります。 複数の DDEML インスタンスの目的は、アプリケーションで DDEML を同時に使用する必要がある DLL をサポートすることです。 アプリケーションは、DDEML の複数のインスタンスを使用してはなりません。
トランザクション フィルター は、DDEML が不要なトランザクションをアプリケーションの DDE コールバック関数に渡さないようにすることで、システム パフォーマンスを最適化します。 アプリケーションは、DdeInitialize ufCmd パラメーターでトランザクション フィルターを設定します。 アプリケーションは、コールバック関数で処理しないトランザクションの種類ごとにトランザクション フィルター フラグを指定する必要があります。 アプリケーションは、 DdeInitialize の後続の呼び出しでトランザクション フィルターを変更できます。 トランザクションについて詳しくは、「トランザクションの管理」をご覧ください。
次の例は、DDEMLを使用するようにアプリケーションを初期化する方法を示しています。
DWORD idInst = 0;
HINSTANCE hinst;
DdeInitialize(&idInst, // receives instance identifier
(PFNCALLBACK) DdeCallback, // pointer to callback function
CBF_FAIL_EXECUTES | // filter XTYPE_EXECUTE
CBF_SKIP_ALLNOTIFICATIONS, // filter notifications
0);
アプリケーションは、DDEML を 使用しなくなったときに DdeUninitialize 関数を呼び出す必要があります。 この関数は、アプリケーションに対して現在開いているすべての会話を終了し、アプリケーションに割り当てられているシステムの DDEML リソースを解放します。
コールバック関数
DDEML を使用するアプリケーションは、アプリケーションに影響を与える DDE イベントを処理するコールバック関数を提供する必要があります。 DDEML は、アプリケーションの DDE コールバック関数にトランザクションを送信することによって、このようなイベントをアプリケーションに通知します。 コールバック関数が受け取るトランザクションは、 DdeInitialize で指定されたアプリケーションにフラグを設定するコールバック フィルターと、アプリケーションがクライアント、サーバー、またはその両方であるかどうかによって異なります。 詳細については、 DdeCallbackを参照してください。
次の例は、一般的なクライアント アプリケーションのコールバック関数の一般的な構造を示しています。
HDDEDATA CALLBACK DdeCallback(uType, uFmt, hconv, hsz1,
hsz2, hdata, dwData1, dwData2)
UINT uType; // transaction type
UINT uFmt; // clipboard data format
HCONV hconv; // handle to conversation
HSZ hsz1; // handle to string
HSZ hsz2; // handle to string
HDDEDATA hdata; // handle to global memory object
DWORD dwData1; // transaction-specific data
DWORD dwData2; // transaction-specific data
{
switch (uType)
{
case XTYP_REGISTER:
case XTYP_UNREGISTER:
.
.
.
return (HDDEDATA) NULL;
case XTYP_ADVDATA:
.
.
.
return (HDDEDATA) DDE_FACK;
case XTYP_XACT_COMPLETE:
//
return (HDDEDATA) NULL;
case XTYP_DISCONNECT:
//
return (HDDEDATA) NULL;
default:
return (HDDEDATA) NULL;
}
}
uType パラメーターは、DDEML によってコールバック関数に送信されるトランザクションの種類を指定します。 再メインパラメーターの値は、トランザクションの種類によって異なります。 トランザクションの種類と、それらを生成するイベントについては、次のトピックで説明します。 各トランザクションの種類の詳細については、「トランザクション管理」を参照してください。
文字列管理
DDE タスクを実行するには、多くの DDEML 関数が文字列にアクセスする必要があります。 たとえば、 DdeConnect 関数を呼び出してサーバーとの会話を要求する場合、クライアントはサービス名とトピック名を指定する必要があります。 アプリケーションは、DDEML 関数内のポインターではなく、文字列ハンドル (HSZ) を渡すことによって文字列を指定します。 文字列ハンドル は、システムによって割り当てられた DWORD 値で、文字列を識別します。
アプリケーションは、 DdeCreateStringHandle 関数を呼び出すことによって、特定の文字列への文字列ハンドルを取得できます。 この関数は、文字列をシステムに登録し、アプリケーションに文字列ハンドルを返します。 アプリケーションは、文字列にアクセスする必要がある DDEML 関数にハンドルを渡すことができます。 次の例では、System トピック文字列とサービス名文字列に対する文字列ハンドルを取得します。
HSZ hszServName;
HSZ hszSysTopic;
hszServName = DdeCreateStringHandle(
idInst, // instance identifier
"MyServer", // string to register
CP_WINANSI); // Windows ANSI code page
hszSysTopic = DdeCreateStringHandle(
idInst, // instance identifier
SZDDESYS_TOPIC, // System topic
CP_WINANSI); // Windows ANSI code page
前の例の idInst パラメーターは、 DdeInitialize 関数によって取得されたインスタンス識別子を指定します。
アプリケーションの DDE コールバック関数は、ほとんどの DDE トランザクション中に 1 つ以上の文字列ハンドルを受け取ります。 たとえば、サーバーは、 XTYP_REQUEST トランザクション中に 2 つの文字列ハンドルを受け取ります。1 つはトピック名を指定する文字列を識別し、もう 1 つはアイテム名を指定する文字列を識別します。 アプリケーションは、次の例に示すように、 DdeQueryString 関数を呼び出すことによって、文字列ハンドルに対応する文字列の長さを取得し、アプリケーション定義バッファーに文字列をコピーできます。
DWORD idInst;
DWORD cb;
HSZ hszServ;
PSTR pszServName;
cb = DdeQueryString(idInst, hszServ, (LPSTR) NULL, 0,
CP_WINANSI) + 1;
pszServName = (PSTR) LocalAlloc(LPTR, (UINT) cb);
DdeQueryString(idInst, hszServ, pszServName, cb, CP_WINANSI);
インスタンス固有の文字列ハンドルは、文字列ハンドルから文字列ハンドルにマップしたり、文字列ハンドルに戻したりすることはできません。 たとえば、 DdeQueryString は文字列ハンドルから文字列を作成し、次に DdeCreateStringHandle はその文字列から文字列ハンドルを作成しますが、2 つのハンドルは 次の例に示すように、これらは同じではありません。
DWORD idInst;
DWORD cb;
HSZ hszInst, hszNew;
PSZ pszInst;
DdeQueryString(idInst, hszInst, pszInst, cb, CP_WINANSI);
hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI);
// hszNew != hszInst !
2 つの文字列ハンドルの値を比較するには、 DdeCmpStringHandles 関数を使用します。
アプリケーションの DDE コールバック関数に渡される文字列ハンドルは、コールバック関数が返されるときに無効になります。 アプリケーションは、 DdeKeepStringHandle 関数を使用してコールバック関数が戻った後に使用する文字列ハンドルを保存できます。
アプリケーションが DdeCreateStringHandle を呼び出すと、システムは指定された文字列を文字列テーブルに入力し、文字列へのアクセスに使用するハンドルを生成します。 また、システムメイン文字列テーブル内の各文字列の使用量カウントも含まれます。
アプリケーションが DdeCreateStringHandle を呼び出し、テーブルに既に存在する文字列を指定すると、システムは、文字列をもう 1 回追加するのではなく、使用カウントをインクリメントします。 (アプリケーションは DdeKeepStringHandle を使用して使用回数を増やすこともできます) アプリケーションが DdeFreeStringHandle 関数を呼び出すと、システムは使用回数をデクリメントします。
使用カウントが 0 の場合、文字列はテーブルから削除されます。 複数のアプリケーションが特定の文字列のハンドルを取得できるため、アプリケーションは、ハンドルを作成または保持した回数よりも多くの時間、文字列ハンドルを解放することはできません。 そうしないと、アプリケーションによって文字列がテーブルから削除され、他のアプリケーションから文字列へのアクセスが拒否される可能性があります。
DDEML 文字列管理機能は Atom マネージャーに基づいており、アトムと同じサイズ制限の対象となります。
DDEML とスレッド
DdeInitialize 関数は DDEML にアプリケーションを登録し、 DDEML インスタンスを作成します。 DDEML インスタンスはスレッドベースであり、 DdeInitialize を呼び出した スレッドに関連付けられています。
DDEML インスタンスに属するオブジェクトに対するすべての DDEML 関数呼び出しは、インスタンスを作成するために DdeInitialize を呼び出したのと同じスレッドから行う必要があります。 別のスレッドから DDEML 関数を呼び出すと、関数は失敗します。 会話を割り当てたスレッド以外のスレッドから DDEML 会話にアクセスすることはできません。