Gestione conversazioni
Una conversazione tra un client e un server viene sempre stabilita alla richiesta del client. Quando viene stabilita una conversazione, ogni partner riceve un handle che identifica la conversazione. I partner usano questo handle in altre funzioni DDEML (Dynamic Data Exchange Management Library) per inviare transazioni e gestire la conversazione. Un client può richiedere una conversazione con un singolo server oppure può richiedere più conversazioni con uno o più server.
Negli argomenti seguenti viene descritto come un'applicazione stabilisce nuove conversazioni e ottiene informazioni sulle conversazioni esistenti.
Conversazioni singole
Un'applicazione client richiede una singola conversazione con un server chiamando la funzione Dde Connessione e specificando handle di stringa che identificano le stringhe contenenti il nome del servizio dell'applicazione server e il nome dell'argomento per la conversazione. DDEML risponde inviando la transazione XTYP_CONNECT alla funzione di callback DDE (Dynamic Data Exchange) di ogni applicazione server che ha registrato un nome di servizio corrispondente a quello specificato in Dde Connessione o ha disattivato il filtro dei nomi del servizio chiamando DdeNameService. Un server può anche filtrare XTYP_CONNECT transazioni specificando il flag di filtro CBF_FAIL_CONNECTIONS nella funzione DdeInitialize. Durante la transazione XTYP_CONNECT , DDEML passa il nome del servizio e il nome dell'argomento al server. Il server deve esaminare i nomi e restituire TRUE se supporta il nome del servizio e la coppia di nomi dell'argomento o FAL edizione Standard in caso contrario.
Se nessun server risponde positivamente alla richiesta del client di connettersi, il client riceve NULL da Dde Connessione e non viene stabilita alcuna conversazione. Se un server restituisce TRUE, viene stabilita una conversazione e il client riceve un handle di conversazione, ovvero un valore DWORD che identifica la conversazione. Il client usa l'handle nelle chiamate DDEML successive per ottenere dati dal server. Il server riceve la transazione XTYP_CONNECT_CONFIRM (a meno che il server non ha specificato il flag di filtro CBF_SKIP_CONNECT_CONFIRMS). Questa transazione passa l'handle di conversazione al server.
Nell'esempio seguente viene richiesta una conversazione nell'argomento Sistema con un server che riconosce il nome del servizio MyServer. I parametri hszServName e hszSysTopic vengono creati in precedenza handle di stringa.
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;
}
Nell'esempio precedente, Dde Connessione fa sì che la funzione di callback DDE dell'applicazione MyServer riceva una transazione XTYP_CONNECT.
Nell'esempio seguente, il server risponde alla transazione XTYP_CONNECT confrontando la stringa del nome dell'argomento che gestisce il DDEML passato al server con ogni elemento nella matrice della stringa del nome dell'argomento gestisce il server supportato. Se il server trova una corrispondenza, stabilisce la conversazione.
#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.
Se il server restituisce TRUE in risposta alla transazione XTYP_CONNECT, DDEML invia una transazione XTYP_CONNECT_CONFIRM alla funzione di callback DDE del server. Il server può ottenere l'handle per la conversazione elaborando questa transazione.
Un client può stabilire una conversazione con caratteri jolly specificando NULL per l'handle della stringa del nome del servizio, l'handle stringa del nome dell'argomento o entrambi in una chiamata a Dde Connessione. Se almeno uno degli handle di stringa è NULL, DDEML invia la transazione XTYP_WILDCONNECT alle funzioni di callback di tutte le applicazioni DDE , ad eccezione di quelle che filtrano la transazione XTYP_WILDCONNECT. Ogni applicazione server deve rispondere restituendo un handle di dati che identifica una matrice con terminazione Null di strutture HSZPAIR. Se l'applicazione server non ha chiamato DdeNameService per registrare i relativi nomi di servizio e se il filtro è attivo, il server non riceve XTYP_WILDCONNECT transazioni. Per altre informazioni sugli handle di dati, vedere Gestione dati.
La matrice deve contenere una struttura per ogni coppia nome del servizio e nome argomento corrispondente alla coppia specificata dal client. DDEML seleziona una delle coppie per stabilire una conversazione e torna al client un handle che identifica la conversazione. DDEML invia la transazione XTYP_CONNECT_CONFIRM al server (a meno che il server non filtri questa transazione). Nell'esempio seguente viene illustrata una risposta tipica del server alla transazione 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
}
Il client o il server può terminare una conversazione in qualsiasi momento chiamando la funzione DdeDisconnect. Questa funzione fa sì che la funzione di callback del partner nella conversazione riceva la transazione XTYP_DISCONNECT (a meno che il partner non ha specificato il flag di filtro CBF_SKIP_DISCONNECTS). In genere, un'applicazione risponde alla transazione XTYP_DISCONNECT usando la funzione DdeQueryConvInfo per ottenere informazioni sulla conversazione terminata. Dopo che la funzione di callback viene restituita dall'elaborazione della transazione XTYP_DISCONNECT , l'handle di conversazione non è più valido.
Un'applicazione client che riceve una transazione XTYP_DISCONNECT nella relativa funzione di callback DDE può tentare di ristabilire la conversazione chiamando la funzione DdeReconnect. Il client deve chiamare DdeReconnect dalla relativa funzione di callback DDE.
Conversazioni multiple
Un'applicazione client può usare la funzione Dde Connessione List per determinare se nel sistema sono disponibili server di interesse. Un client specifica un nome di servizio e un nome di argomento quando chiama Dde Connessione List, causando la trasmissione della transazione XTYP_WILDCONNECT DDEML alle funzioni di callback DDE di tutti i server che corrispondono al nome del servizio , ad eccezione di quelli che filtrano la transazione. La funzione di callback di un server deve restituire un handle di dati che identifica una matrice con terminazione Null di strutture HSZPAIR. La matrice deve contenere una struttura per ogni coppia nome del servizio e nome argomento corrispondente alla coppia specificata dal client. Il DDEML stabilisce una conversazione per ogni struttura HSZPAIR riempita dal server e restituisce un handle dell'elenco di conversazioni al client. Il server riceve l'handle di conversazione tramite la transazione XTYP_CONNECT (a meno che il server non filtri questa transazione).
Un client può specificare NULL per il nome del servizio, il nome dell'argomento o entrambi quando chiama Dde Connessione List. Se il nome del servizio è NULL, tutti i server del sistema che supportano il nome dell'argomento specificato rispondono. Viene stabilita una conversazione con ogni server che risponde, incluse più istanze dello stesso server. Se il nome dell'argomento è NULL, viene stabilita una conversazione in ogni argomento riconosciuto da ogni server che corrisponde al nome del servizio.
Un client può usare le funzioni DdeQueryNextServer e DdeQueryConvInfo per identificare i server che rispondono a Dde Connessione List. DdeQueryNextServer restituisce l'handle di conversazione successivo in un elenco di conversazioni e DdeQueryConvInfo riempie una struttura CONVINFO con informazioni sulla conversazione. Il client può mantenere gli handle di conversazione necessari ed eliminare il resto dall'elenco di conversazioni.
L'esempio seguente usa Dde Connessione List per stabilire conversazioni con tutti i server che supportano l'argomento System e quindi usa le funzioni DdeQueryNextServer e DdeQueryConvInfo per ottenere gli handle di stringa del nome del servizio del server e archiviarli in un buffer.
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);
Un'applicazione può terminare una singola conversazione in un elenco di conversazioni chiamando la funzione DdeDisconnect. Un'applicazione può terminare tutte le conversazioni in un elenco di conversazioni chiamando la funzione DdeDisconnectList. Entrambe le funzioni fanno sì che DDEML invii transazioni XTYP_DISCONNECT alla funzione di callback DDE di ogni partner. DdeDisconnectList invia una transazione XTYP_DISCONNECT per ogni handle di conversazione nell'elenco.
Un client può recuperare un elenco degli handle di conversazione in un elenco di conversazioni passando un handle di elenco di conversazioni esistente a Dde Connessione List. Il processo di enumerazione rimuove gli handle delle conversazioni terminate dall'elenco e le conversazioni nonduplicate che soddisfano il nome del servizio e il nome dell'argomento specificati vengono aggiunti.
Se Dde Connessione List specifica un handle di elenco di conversazioni esistente, la funzione crea un nuovo elenco di conversazioni che contiene gli handle di eventuali nuove conversazioni e gli handle dall'elenco esistente.
Se esistono conversazioni duplicate, Dde Connessione List tenta di impedire handle di conversazione duplicati nell'elenco delle conversazioni. Una conversazione duplicata è una seconda conversazione con lo stesso server con lo stesso nome del servizio e lo stesso nome dell'argomento. Due conversazioni di questo tipo avrebbero handle diversi, ma identificano la stessa conversazione.