交談管理
用戶端與伺服器之間的交談一律會在用戶端的要求建立。 建立交談時,每個夥伴都會收到識別交談的句柄。 合作夥伴在其他動態數據交換管理連結庫 (DDEML) 函式中使用此句柄來傳送交易和管理交談。 用戶端可以要求與單一伺服器的交談,也可以要求與一或多部伺服器進行多個交談。
下列主題描述應用程式如何建立新的交談,並取得現有交談的相關信息。
單一交談
用戶端應用程式會呼叫 Dde 連線 函式並指定字串句柄,以識別包含伺服器應用程式服務名稱的字串,以及交談的主題名稱,以要求與伺服器進行單一交談。 DDEML 會藉由將XTYP_CONNECT交易傳送至每個伺服器應用程式的動態數據交換 (DDE) 回呼函式來回應,這些函式已註冊符合 Dde 中指定的服務名稱 連線 或呼叫 DdeNameService 來關閉服務名稱篩選。 伺服器也可以藉由在 DdeInitialize 函式中指定CBF_FAIL_CONNECTIONS篩選旗標來篩選XTYP_CONNECT交易。 在 XTYP_CONNECT 交易期間,DDEML 會將服務名稱和主題名稱傳遞至伺服器。 如果伺服器支援服務名稱和主題名稱組,則伺服器必須檢查名稱並傳回 TRUE,否則為 FALSE。
如果沒有伺服器對用戶端連線的要求做出正面回應,用戶端就會從 Dde 接收 NULL 連線 且未建立任何交談。 如果伺服器傳 回 TRUE,則會建立交談,而用戶端會收到交談句柄, 這是 識別交談的 DWORD 值。 用戶端會在後續的 DDEML 呼叫中使用 句柄,從伺服器取得數據。 伺服器會收到 XTYP_CONNECT_CONFIRM 交易(除非伺服器指定了CBF_SKIP_CONNECT_CONFIRMS篩選旗標)。 此交易會將交談句柄傳遞至伺服器。
下列範例會使用可辨識服務名稱 MyServer 的伺服器,在 System 主題上要求交談。 hszServName 和 hszSysTopic 參數先前是建立的字串句柄。
HCONV hConv; // conversation handle
HWND hwndParent; // parent window handle
HSZ hszServName; // service name string handle
HSZ hszSysTopic; // System topic string handle
hConv = DdeConnect(
idInst, // instance identifier
hszServName, // service name string handle
hszSysTopic, // System topic string handle
(PCONVCONTEXT) NULL); // use default context
if (hConv == NULL)
{
MessageBox(hwndParent, "MyServer is unavailable.",
(LPSTR) NULL, MB_OK);
return FALSE;
}
在上述範例中,Dde 連線 會導致 MyServer 應用程式的 DDE 回呼函式接收XTYP_CONNECT交易。
在下列範例中,伺服器會藉由比較主題名稱字串句柄傳遞至伺服器的 DDEML,以及主題名稱字串句柄伺服器所支援之陣列中的每個元素,來回應 XTYP_CONNECT 交易。 如果伺服器找到相符專案,則會建立交談。
#define CTOPICS 5
HSZ hsz1; // string handle passed by DDEML
HSZ ahszTopics[CTOPICS]; // array of supported topics
int i; // loop counter
// Use a switch statement to examine transaction types.
// Here is the connect case.
case XTYP_CONNECT:
for (i = 0; i < CTOPICS; i++)
{
if (hsz1 == ahszTopics[i])
return TRUE; // establish a conversation
}
return FALSE; // Topic not supported; deny conversation.
// Process other transaction types.
如果伺服器傳回 TRUE 以回應XTYP_CONNECT交易,DDEML 會將XTYP_CONNECT_CONFIRM交易傳送至伺服器的 DDE 回呼函式。 伺服器可以藉由處理此交易來取得交談的句柄。
用戶端可以藉由指定服務名稱字串句柄、主題名稱字串句柄或呼叫 Dde 中的兩者,來建立通配符交談 連線。 如果至少有一個字串句柄是 NULL,DDEML 會將XTYP_WILDCONNECT交易傳送至所有 DDE 應用程式的回呼函式(但篩選XTYP_WILDCONNECT交易除外)。 每個伺服器應用程式都應該傳回可識別 HSZPAIR 結構 Null 終止陣列的數據句柄來回應。 如果伺服器應用程式尚未呼叫 DdeNameService 來註冊其服務名稱,而且如果篩選開啟,伺服器就不會收到XTYP_WILDCONNECT交易。 如需數據句柄的詳細資訊,請參閱 資料管理。
陣列必須包含每個服務名稱和主題名稱組的一個結構,這些結構符合用戶端指定的配對。 DDEML 會選取其中一組來建立交談,並傳回用戶端識別交談的句柄。 DDEML 會將 XTYP_CONNECT_CONFIRM 交易傳送至伺服器(除非伺服器篩選此交易)。 下列範例顯示一般伺服器對XTYP_WILDCONNECT交易的回應。
#define CTOPICS 2
UINT uType;
HSZPAIR ahszp[(CTOPICS + 1)];
HSZ ahszTopicList[CTOPICS];
HSZ hszServ, hszTopic;
WORD i, j;
if (uType == XTYP_WILDCONNECT)
{
// Scan the topic list and create an array of HSZPAIR structures.
j = 0;
for (i = 0; i < CTOPICS; i++)
{
if (hszTopic == (HSZ) NULL ||
hszTopic == ahszTopicList[i])
{
ahszp[j].hszSvc = hszServ;
ahszp[j++].hszTopic = ahszTopicList[i];
}
}
// End the list with an HSZPAIR structure that contains NULL
// string handles as its members.
ahszp[j].hszSvc = NULL;
ahszp[j++].hszTopic = NULL;
// Return a handle to a global memory object containing the
// HSZPAIR structures.
return DdeCreateDataHandle(
idInst, // instance identifier
(LPBYTE) &ahszp, // pointer to HSZPAIR array
sizeof(HSZ) * j, // length of the array
0, // start at the beginning
(HSZ) NULL, // no item name string
0, // return the same format
0); // let the system own it
}
用戶端或伺服器都可以呼叫 DdeDisconnect 函式,隨時終止交談。 此函式會導致交談中夥伴的回呼函式接收 XTYP_DISCONNECT 交易(除非夥伴指定CBF_SKIP_DISCONNECTS篩選旗標)。 一般而言,應用程式會使用 DdeQueryConvInfo 函式來回應XTYP_DISCONNECT交易,以取得終止交談的相關信息。 在回呼函式從處理 XTYP_DISCONNECT 交易傳回之後,交談句柄就不再有效。
在 DDE 回呼函式中接收 XTYP_DISCONNECT 交易的用戶端應用程式,可以呼叫 DdeReconnect 函式來嘗試重新建立交談。 用戶端必須在 DDE 回呼函式內呼叫 DdeReconnect 。
多個交談
用戶端應用程式可以使用 Dde 連線 List 函式來判斷系統中是否有任何感興趣的伺服器。 用戶端會在呼叫 Dde 連線 List 時指定服務名稱和主題名稱,導致 DDEML 將XTYP_WILDCONNECT交易廣播至符合服務名稱的所有伺服器的 DDE 回呼函式(但篩選交易除外)。 伺服器的回呼函式應該會傳回可識別 HSZPAIR 結構的 Null 終止數位的數據句柄。 數位應該包含每個服務名稱和主題名稱組的一個結構,這些結構符合用戶端指定的配對。 DDEML 會為伺服器填滿的每個 HSZPAIR 結構建立交談,並將交談清單句柄傳回給用戶端。 伺服器會透過XTYP_CONNECT交易接收交談句柄(除非伺服器篩選此交易)。
用戶端可以在呼叫 Dde 連線 List 時,為服務名稱、主題名稱或兩者指定 NULL。 如果服務名稱為 NULL,則系統中支援指定主題名稱的所有伺服器都會回應。 每個回應伺服器都會建立交談,包括相同伺服器的多個實例。 如果主題名稱為 NULL,則會在每個符合服務名稱的伺服器所辨識的每個主題上建立交談。
用戶端可以使用 DdeQueryNextServer 和 DdeQueryConvInfo 函式來識別回應 Dde 連線 List 的伺服器。 DdeQueryNextServer 會傳回交談清單中的下一個交談句柄,而 DdeQueryConvInfo 會填入 CONVINFO 結構,其中包含交談的相關信息。 用戶端可以保留所需的交談句柄,並從交談清單中捨棄其餘的句柄。
下列範例會使用 Dde 連線 List 與支援 System 主題的所有伺服器建立交談,然後使用 DdeQueryNextServer 和 DdeQueryConvInfo 函式來取得伺服器的服務名稱字元串句柄,並將其儲存在緩衝區中。
HCONVLIST hconvList; // conversation list
DWORD idInst; // instance identifier
HSZ hszSystem; // System topic
HCONV hconv = NULL; // conversation handle
CONVINFO ci; // holds conversation data
UINT cConv = 0; // count of conv. handles
HSZ *pHsz, *aHsz; // point to string handles
// Connect to all servers that support the System topic.
hconvList = DdeConnectList(idInst, NULL, hszSystem, NULL, NULL);
// Count the number of handles in the conversation list.
while ((hconv = DdeQueryNextServer(hconvList, hconv)) != NULL)
cConv++;
// Allocate a buffer for the string handles.
hconv = NULL;
aHsz = (HSZ *) LocalAlloc(LMEM_FIXED, cConv * sizeof(HSZ));
// Copy the string handles to the buffer.
pHsz = aHsz;
while ((hconv = DdeQueryNextServer(hconvList, hconv)) != NULL)
{
DdeQueryConvInfo(hconv, QID_SYNC, (PCONVINFO) &ci);
DdeKeepStringHandle(idInst, ci.hszSvcPartner);
*pHsz++ = ci.hszSvcPartner;
}
// Use the handles; converse with the servers.
// Free the memory and terminate the conversations.
LocalFree((HANDLE) aHsz);
DdeDisconnectList(hconvList);
應用程式可以藉由呼叫 DdeDisconnect 函式,終止交談清單中的個別交談。 應用程式可以藉由呼叫 DdeDisconnectList 函式,終止交談清單中的所有交談。 這兩個函式都會讓 DDEML 將XTYP_DISCONNECT交易傳送至每個夥伴的 DDE 回呼函式。 DdeDisconnectList 會針對清單中的每個交談句柄傳送 XTYP_DISCONNECT 交易。
用戶端可以將現有的交談清單句柄傳遞至 Dde 連線 List,以擷取交談清單中的交談句柄清單。 列舉程式會從清單中移除終止交談的句柄,並新增符合指定服務名稱和主題名稱的非重複數據刪除交談。
如果 Dde 連線 List 指定現有的交談清單句柄,函式會建立新的交談清單,其中包含任何新交談的句柄,以及現有清單中的句柄。
如果存在重複的交談,Dde 連線 List 會嘗試防止交談清單中的重複交談句柄。 重複交談是相同服務名稱和主題名稱上具有相同伺服器的第二個交談。 兩個這類交談會有不同的句柄,但他們會識別相同的交談。