Konversationsverwaltung
Eine Konversation zwischen einem Client und einem Server wird immer auf Anforderung des Clients eingerichtet. Wenn eine Konversation eingerichtet wird, erhält jeder Partner einen Handle, der die Konversation identifiziert. Die Partner verwenden dieses Handle in anderen DDEML-Funktionen (Dynamic Data Exchange Management Library), um Transaktionen zu senden und die Unterhaltung zu verwalten. Ein Client kann eine Konversation mit einem einzelnen Server anfordern oder mehrere Unterhaltungen mit einem oder mehreren Servern anfordern.
In den folgenden Themen wird beschrieben, wie eine Anwendung neue Unterhaltungen erstellt und Informationen zu vorhandenen Unterhaltungen erhält.
Einzelne Unterhaltungen
Eine Clientanwendung fordert eine einzelne Konversation mit einem Server an, indem sie die DdeConnect-Funktion aufruft und Zeichenfolgenhandles angibt, die die Zeichenfolgen identifizieren, die den Dienstnamen der Serveranwendung und den Themennamen für die Unterhaltung enthalten. Die DDEML antwortet, indem sie die XTYP_CONNECT Transaktion an die DDE-Rückruffunktion (Dynamic Data Exchange) jeder Serveranwendung sendet, die entweder einen Dienstnamen registriert hat, der mit dem in DdeConnect angegebenen übereinstimmt, oder die Dienstnamenfilterung deaktiviert hat, indem sie DdeNameService aufruft. Ein Server kann auch XTYP_CONNECT Transaktionen filtern, indem er das CBF_FAIL_CONNECTIONS Filterflag in der DdeInitialize-Funktion angibt. Während der XTYP_CONNECT Transaktion übergibt die DDEML den Dienstnamen und den Themennamen an den Server. Der Server muss die Namen untersuchen und TRUE zurückgeben, wenn er das Dienstnamen- und Themennamenpaar unterstützt, oder FALSE , falls dies nicht der Fall ist.
Wenn kein Server positiv auf die Verbindungsanforderung des Clients antwortet, erhält der Client NULL von DdeConnect , und es wird keine Konversation eingerichtet. Wenn ein Server TRUE zurückgibt, wird eine Konversation eingerichtet, und der Client empfängt ein Konversationshandle – einen DWORD-Wert , der die Konversation identifiziert. Der Client verwendet das Handle in nachfolgenden DDEML-Aufrufen, um Daten vom Server abzurufen. Der Server empfängt die XTYP_CONNECT_CONFIRM Transaktion (es sei denn, der Server hat das CBF_SKIP_CONNECT_CONFIRMS Filterflag angegeben). Diese Transaktion übergibt das Konversationshandle an den Server.
Im folgenden Beispiel wird eine Unterhaltung zum Thema System mit einem Server angefordert, der den Dienstnamen MyServer erkennt. Die Parameter hszServName und hszSysTopic sind zuvor Zeichenfolgenhandles erstellt.
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;
}
Im vorherigen Beispiel bewirkt DdeConnect , dass die DDE-Rückruffunktion der MyServer-Anwendung eine XTYP_CONNECT Transaktion empfängt.
Im folgenden Beispiel antwortet der Server auf die XTYP_CONNECT Transaktion, indem er das Themanamenszeichenfolgenhandle der an den Server übergebenen DDEML mit jedem Element im Array der Themennamenzeichenfolge vergleicht, die der Server unterstützt. Wenn der Server eine Übereinstimmung findet, wird die Konversation eingerichtet.
#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.
Wenn der Server true als Reaktion auf die XTYP_CONNECT Transaktion zurückgibt, sendet die DDEML eine XTYP_CONNECT_CONFIRM Transaktion an die DDE-Rückruffunktion des Servers. Der Server kann das Handle für die Unterhaltung abrufen, indem er diese Transaktion verarbeitet.
Ein Client kann eine Feldhalterunterhaltung einrichten, indem er null für das Handle für die Dienstnamenzeichenfolge, das Themennamenzeichenfolgenhandle oder beides in einem Aufruf von DdeConnect angibt. Wenn mindestens einer der Zeichenfolgenhandles NULL ist, sendet die DDEML die XTYP_WILDCONNECT Transaktion an die Rückruffunktionen aller DDE-Anwendungen (mit Ausnahme derer, die die XTYP_WILDCONNECT Transaktion filtern). Jede Serveranwendung sollte reagieren, indem sie ein Datenhandle zurückgibt, das ein NULL-beendetes Array von HSZPAIR-Strukturen identifiziert. Wenn die Serveranwendung DdeNameService nicht aufgerufen hat, um ihre Dienstnamen zu registrieren, und wenn die Filterung aktiviert ist, empfängt der Server keine XTYP_WILDCONNECT Transaktionen. Weitere Informationen zu Datenhandles finden Sie unter Datenverwaltung.
Das Array muss eine Struktur für jedes Dienstnamen- und Themennamenspaar enthalten, das dem vom Client angegebenen Paar entspricht. Die DDEML wählt eines der Paare aus, um eine Unterhaltung einzurichten, und gibt dem Client ein Handle zurück, das die Konversation identifiziert. Die DDEML sendet die XTYP_CONNECT_CONFIRM Transaktion an den Server (es sei denn, der Server filtert diese Transaktion). Das folgende Beispiel zeigt eine typische Serverantwort auf die XTYP_WILDCONNECT Transaktion.
#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
}
Entweder der Client oder der Server kann eine Unterhaltung jederzeit beenden, indem die DdeDisconnect-Funktion aufgerufen wird. Diese Funktion bewirkt, dass die Rückruffunktion des Partners in der Unterhaltung die XTYP_DISCONNECT Transaktion empfängt (es sei denn, der Partner hat das CBF_SKIP_DISCONNECTS Filterflag angegeben). In der Regel reagiert eine Anwendung auf die XTYP_DISCONNECT Transaktion, indem sie die DdeQueryConvInfo-Funktion verwendet, um Informationen über die unterhaltung abzurufen, die beendet wurde. Nachdem die Rückruffunktion von der Verarbeitung der XTYP_DISCONNECT Transaktion zurückgegeben wurde, ist das Konversationshandle nicht mehr gültig.
Eine Clientanwendung, die eine XTYP_DISCONNECT Transaktion in ihrer DDE-Rückruffunktion empfängt, kann versuchen, die Konversation durch Aufrufen der DdeReconnect-Funktion wiederherzustellen. Der Client muss DdeReconnect innerhalb seiner DDE-Rückruffunktion aufrufen.
Mehrere Unterhaltungen
Eine Clientanwendung kann die DdeConnectList-Funktion verwenden, um zu bestimmen, ob im System interessante Server verfügbar sind. Ein Client gibt einen Dienstnamen und einen Themennamen an, wenn er DdeConnectList aufruft, wodurch die DDEML die XTYP_WILDCONNECT Transaktion an die DDE-Rückruffunktionen aller Server sendet, die mit dem Dienstnamen übereinstimmen (mit Ausnahme derjenigen, die die Transaktion filtern). Die Rückruffunktion eines Servers sollte ein Datenhandle zurückgeben, das ein NULL-beendetes Array von HSZPAIR-Strukturen identifiziert. Das Array sollte eine Struktur für jedes Dienstnamen- und Themennamenspaar enthalten, das dem vom Client angegebenen Paar entspricht. Die DDEML richtet eine Konversation für jede HSZPAIR-Struktur ein, die vom Server gefüllt wird, und gibt ein Konversationslistenhandle an den Client zurück. Der Server empfängt das Konversationshandle über die XTYP_CONNECT Transaktion (es sei denn, der Server filtert diese Transaktion).
Ein Client kann NULL für den Dienstnamen, den Themennamen oder beides angeben, wenn er DdeConnectList aufruft. Wenn der Dienstname NULL ist, antworten alle Server im System, die den angegebenen Themennamen unterstützen. Mit jedem antwortigen Server wird eine Konversation eingerichtet, einschließlich mehrerer Instanzen desselben Servers. Wenn der Themenname NULL ist, wird eine Konversation für jedes Thema eingerichtet, das von jedem Server erkannt wird, der mit dem Dienstnamen übereinstimmt.
Ein Client kann die Funktionen DdeQueryNextServer und DdeQueryConvInfo verwenden, um die Server zu identifizieren, die auf DdeConnectList reagieren. DdeQueryNextServer gibt das nächste Konversationshandle in einer Unterhaltungsliste zurück, und DdeQueryConvInfo füllt eine CONVINFO-Struktur mit Informationen zur Unterhaltung. Der Client kann die benötigten Konversationshandles beibehalten und den Rest aus der Unterhaltungsliste verwerfen.
Im folgenden Beispiel wird DdeConnectList verwendet, um Unterhaltungen mit allen Servern herzustellen, die das Systemthema unterstützen. Anschließend werden die Funktionen DdeQueryNextServer und DdeQueryConvInfo verwendet, um die Zeichenfolgenhandles des Dienstnamens der Server abzurufen und in einem Puffer zu speichern.
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);
Eine Anwendung kann eine einzelne Unterhaltung in einer Unterhaltungsliste beenden, indem sie die DdeDisconnect-Funktion aufruft. Eine Anwendung kann alle Unterhaltungen in einer Unterhaltungsliste beenden, indem sie die Funktion DdeDisconnectList aufruft. Beide Funktionen bewirken, dass die DDEML XTYP_DISCONNECT Transaktionen an die DDE-Rückruffunktion jedes Partners sendet. DdeDisconnectList sendet eine XTYP_DISCONNECT Transaktion für jedes Konversationshandle in der Liste.
Ein Client kann eine Liste der Konversationshandles in einer Unterhaltungsliste abrufen, indem ein vorhandenes Konversationslistenhandle an DdeConnectList übergeben wird. Durch den Enumerationsprozess werden die Handles beendeter Unterhaltungen aus der Liste entfernt, und nicht duplizierte Unterhaltungen, die dem angegebenen Dienstnamen und dem angegebenen Themennamen entsprechen, werden hinzugefügt.
Wenn DdeConnectList ein vorhandenes Konversationslistenhandle angibt, erstellt die Funktion eine neue Unterhaltungsliste, die die Handles aller neuen Unterhaltungen und die Handles aus der vorhandenen Liste enthält.
Wenn doppelte Unterhaltungen vorhanden sind, versucht DdeConnectList , doppelte Konversationshandles in der Unterhaltungsliste zu verhindern. Eine doppelte Unterhaltung ist eine zweite Unterhaltung mit demselben Server unter demselben Dienstnamen und Themennamen. Zwei solcher Unterhaltungen hätten unterschiedliche Griffe, aber sie würden dieselbe Konversation identifizieren.