Gestion des conversations
Une conversation entre un client et un serveur est toujours établie à la demande du client. Lorsqu’une conversation est établie, chaque partenaire reçoit un handle qui identifie la conversation. Les partenaires utilisent ce handle dans d’autres fonctions DDEML (Dynamic Data Exchange Management Library) pour envoyer des transactions et gérer la conversation. Un client peut demander une conversation avec un seul serveur ou demander plusieurs conversations avec un ou plusieurs serveurs.
Les rubriques suivantes décrivent comment une application établit de nouvelles conversations et obtient des informations sur les conversations existantes.
Conversations uniques
Une application cliente demande une conversation unique avec un serveur en appelant la fonction DdeConnect et en spécifiant des handles de chaîne qui identifient les chaînes contenant le nom de service de l’application serveur et le nom de la rubrique pour la conversation. Le DDEML répond en envoyant la transaction XTYP_CONNECT à la fonction de rappel DDE (Dynamic Data Exchange) de chaque application serveur qui a inscrit un nom de service correspondant à celui spécifié dans DdeConnect ou a désactivé le filtrage des noms de service en appelant DdeNameService. Un serveur peut également filtrer XTYP_CONNECT transactions en spécifiant l’indicateur de filtre CBF_FAIL_CONNECTIONS dans la fonction DdeInitialize . Pendant la transaction XTYP_CONNECT , le DDEML transmet le nom du service et le nom de la rubrique au serveur. Le serveur doit examiner les noms et retourner TRUE s’il prend en charge la paire nom du service et nom de rubrique ou FALSE si ce n’est pas le cas.
Si aucun serveur ne répond positivement à la demande de connexion du client, le client reçoit NULL de DdeConnect et aucune conversation n’est établie. Si un serveur retourne TRUE, une conversation est établie et le client reçoit un handle de conversation, une valeur DWORD qui identifie la conversation. Le client utilise le handle dans les appels DDEML suivants pour obtenir des données du serveur. Le serveur reçoit la transaction XTYP_CONNECT_CONFIRM (sauf si le serveur a spécifié l’indicateur de filtre CBF_SKIP_CONNECT_CONFIRMS). Cette transaction transmet le handle de conversation au serveur.
L’exemple suivant demande une conversation sur la rubrique Système avec un serveur qui reconnaît le nom de service MyServer. Les paramètres hszServName et hszSysTopic sont des handles de chaîne précédemment créés.
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;
}
Dans l’exemple précédent, DdeConnect entraîne la réception d’une transaction XTYP_CONNECT par la fonction de rappel DDE de l’application MyServer.
Dans l’exemple suivant, le serveur répond à la transaction XTYP_CONNECT en comparant le handle de chaîne de nom de rubrique que le DDEML a passé au serveur avec chaque élément du tableau de handles de chaîne de nom de rubrique pris en charge par le serveur. Si le serveur trouve une correspondance, il établit la conversation.
#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.
Si le serveur retourne TRUE en réponse à la transaction XTYP_CONNECT , le DDEML envoie une transaction XTYP_CONNECT_CONFIRM à la fonction de rappel DDE du serveur. Le serveur peut obtenir le handle de la conversation en traitant cette transaction.
Un client peut établir une conversation générique en spécifiant NULL pour le handle de chaîne de nom de service, le handle de chaîne de nom de rubrique ou les deux dans un appel à DdeConnect. Si au moins un des handles de chaîne a la valeur NULL, le DDEML envoie la transaction XTYP_WILDCONNECT aux fonctions de rappel de toutes les applications DDE (à l’exception de celles qui filtrent la transaction XTYP_WILDCONNECT ). Chaque application serveur doit répondre en retournant un handle de données qui identifie un tableau de structures HSZPAIR terminées par un caractère Null. Si l’application serveur n’a pas appelé DdeNameService pour inscrire ses noms de service et si le filtrage est activé, le serveur ne reçoit pas de transactions XTYP_WILDCONNECT . Pour plus d’informations sur les handles de données, consultez Gestion des données.
Le tableau doit contenir une structure pour chaque paire nom de service et nom de rubrique qui correspond à la paire spécifiée par le client. Le DDEML sélectionne l’une des paires pour établir une conversation et retourne au client un handle qui identifie la conversation. Le DDEML envoie la transaction XTYP_CONNECT_CONFIRM au serveur (sauf si le serveur filtre cette transaction). L’exemple suivant montre une réponse de serveur classique à la transaction 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
}
Le client ou le serveur peut mettre fin à une conversation à tout moment en appelant la fonction DdeDisconnect . Cette fonction entraîne la réception de la XTYP_DISCONNECT transaction par la fonction de rappel du partenaire dans la conversation (sauf si le partenaire a spécifié l’indicateur de filtre CBF_SKIP_DISCONNECTS). En règle générale, une application répond à la transaction XTYP_DISCONNECT à l’aide de la fonction DdeQueryConvInfo pour obtenir des informations sur la conversation qui s’est terminée. Une fois que la fonction de rappel est retournée après le traitement de la transaction XTYP_DISCONNECT , le handle de conversation n’est plus valide.
Une application cliente qui reçoit une transaction XTYP_DISCONNECT dans sa fonction de rappel DDE peut tenter de rétablir la conversation en appelant la fonction DdeReconnect . Le client doit appeler DdeReconnect à partir de sa fonction de rappel DDE.
Plusieurs conversations
Une application cliente peut utiliser la fonction DdeConnectList pour déterminer si des serveurs intéressants sont disponibles dans le système. Un client spécifie un nom de service et un nom de rubrique lorsqu’il appelle DdeConnectList, ce qui permet à DDEML de diffuser la transaction XTYP_WILDCONNECT aux fonctions de rappel DDE de tous les serveurs qui correspondent au nom du service (à l’exception de ceux qui filtrent la transaction). La fonction de rappel d’un serveur doit retourner un handle de données qui identifie un tableau de structures HSZPAIR terminées par un caractère Null. Le tableau doit contenir une structure pour chaque paire nom de service et nom de rubrique qui correspond à la paire spécifiée par le client. Le DDEML établit une conversation pour chaque structure HSZPAIR remplie par le serveur et retourne un handle de liste de conversations au client. Le serveur reçoit le handle de conversation par le biais de la transaction XTYP_CONNECT (sauf si le serveur filtre cette transaction).
Un client peut spécifier NULL pour le nom du service, le nom de la rubrique ou les deux lorsqu’il appelle DdeConnectList. Si le nom du service est NULL, tous les serveurs du système qui prennent en charge le nom de la rubrique spécifiée répondent. Une conversation est établie avec chaque serveur qui répond, y compris plusieurs instances du même serveur. Si le nom de la rubrique est NULL, une conversation est établie sur chaque rubrique reconnue par chaque serveur qui correspond au nom du service.
Un client peut utiliser les fonctions DdeQueryNextServer et DdeQueryConvInfo pour identifier les serveurs qui répondent à DdeConnectList. DdeQueryNextServer retourne le handle de conversation suivant dans une liste de conversations, et DdeQueryConvInfo remplit une structure CONVINFO avec des informations sur la conversation. Le client peut conserver les handles de conversation dont il a besoin et ignorer le reste de la liste des conversations.
L’exemple suivant utilise DdeConnectList pour établir des conversations avec tous les serveurs qui prennent en charge la rubrique Système, puis utilise les fonctions DdeQueryNextServer et DdeQueryConvInfo pour obtenir les handles de chaîne de nom de service des serveurs et les stocker dans une mémoire tampon.
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);
Une application peut mettre fin à une conversation individuelle dans une liste de conversations en appelant la fonction DdeDisconnect . Une application peut mettre fin à toutes les conversations d’une liste de conversations en appelant la fonction DdeDisconnectList . Les deux fonctions entraînent l’envoi de transactions XTYP_DISCONNECT à la fonction de rappel DDE de chaque partenaire. DdeDisconnectList envoie une transaction XTYP_DISCONNECT pour chaque handle de conversation dans la liste.
Un client peut récupérer une liste des handles de conversation dans une liste de conversations en passant un handle de liste de conversation existant à DdeConnectList. Le processus d’énumération supprime les handles des conversations terminées de la liste, et les conversations non dupliquées qui correspondent au nom de service et au nom de la rubrique spécifiés sont ajoutées.
Si DdeConnectList spécifie un handle de liste de conversations existant, la fonction crée une liste de conversations qui contient les handles de toutes les nouvelles conversations et les handles de la liste existante.
S’il existe des conversations en double, DdeConnectList tente d’empêcher les handles de conversation en double dans la liste des conversations. Une conversation en double est une deuxième conversation avec le même serveur sur le même nom de service et le même nom de rubrique. Deux de ces conversations auraient des handles différents, mais elles identifieraient la même conversation.