Partager via


Gestion des transactions (Échange de données)

Après avoir établi une conversation avec un serveur, un client peut envoyer des transactions pour obtenir des données et des services à partir du serveur.

Les rubriques suivantes décrivent les types de transactions que les clients peuvent utiliser pour interagir avec un serveur.

Transaction de requête

Une application cliente peut utiliser la transaction XTYP_REQUEST pour demander un élément de données à une application serveur. Le client appelle la fonction DdeClientTransaction , en spécifiant XTYP_REQUEST comme type de transaction et en spécifiant l’élément de données dont l’application a besoin.

La bibliothèque de gestion DDEML (Dynamic Data Exchange Management Library) transmet la transaction XTYP_REQUEST au serveur, en spécifiant le nom de la rubrique, le nom de l’élément et le format de données demandés par le client. Si le serveur prend en charge la rubrique, l’élément et le format demandés, le serveur doit retourner un handle de données qui identifie la valeur actuelle de l’élément. Le DDEML transmet ce handle au client comme valeur de retour de DdeClientTransaction. Le serveur doit retourner null s’il ne prend pas en charge la rubrique, l’élément ou le format demandé.

DdeClientTransaction utilise le paramètre lpdwResult pour renvoyer un indicateur status transaction au client. Si le serveur ne traite pas la transaction XTYP_REQUEST , DdeClientTransaction retourne NULL et lpdwResult pointe vers l’indicateur DDE_FNOTPROCESSED ou DDE_FBUSY. Si l’indicateur DDE_FNOTPROCESSED est retourné, le client ne peut pas déterminer pourquoi le serveur n’a pas traité la transaction.

Si un serveur ne prend pas en charge la transaction XTYP_REQUEST , il doit spécifier l’indicateur de filtre CBF_FAIL_REQUESTS dans la fonction DdeInitialize . Cet indicateur empêche le DDEML d’envoyer la transaction au serveur.

Transaction d’poke

Un client peut envoyer des données non sollicitées à un serveur à l’aide de DdeClientTransaction pour envoyer une transaction XTYP_POKE à la fonction de rappel d’un serveur.

L’application cliente crée d’abord une mémoire tampon qui contient les données à envoyer au serveur, puis passe un pointeur vers la mémoire tampon en tant que paramètre vers DdeClientTransaction. Le client peut également utiliser la fonction DdeCreateDataHandle pour obtenir un handle de données qui identifie les données, puis le transmettre à DdeClientTransaction. Dans les deux cas, le client spécifie également le nom de la rubrique, le nom de l’élément et le format des données lorsqu’il appelle DdeClientTransaction.

Le DDEML transmet la transaction XTYP_POKE au serveur, en spécifiant le nom de la rubrique, le nom de l’élément et le format de données demandés par le client. Pour accepter l’élément de données et le format, le serveur doit retourner DDE_FACK. Pour rejeter les données, le serveur doit retourner DDE_FNOTPROCESSED. Si le serveur est trop occupé pour accepter les données, le serveur doit retourner DDE_FBUSY.

Lorsque DdeClientTransaction retourne, le client peut utiliser le paramètre lpdwResult pour accéder à l’indicateur status transaction. Si l’indicateur est DDE_FBUSY, le client doit renvoyer la transaction ultérieurement.

Si un serveur ne prend pas en charge la transaction XTYP_POKE , il doit spécifier l’indicateur de filtre CBF_FAIL_POKES dans DdeInitialize. Cet indicateur empêche le DDEML d’envoyer cette transaction au serveur.

Conseiller la transaction

Une application cliente peut utiliser le DDEML pour établir un ou plusieurs liens vers des éléments dans une application serveur. Lorsqu’un tel lien a été établi, le serveur envoie des mises à jour périodiques sur l’élément lié au client (généralement, chaque fois que la valeur de l’élément associé à l’application serveur change). La liaison établit une boucle d’avertissement entre les deux applications qui reste en place jusqu’à ce que le client la termine.

Il existe deux types de boucles d’avertissement : « chaud » et « chaud ». Dans une boucle d’avis à chaud, le serveur envoie immédiatement un handle de données qui identifie la valeur modifiée. Dans une boucle d’avis chaude, le serveur avertit le client que la valeur de l’élément a changé, mais n’envoie pas le handle de données tant que le client ne le demande pas.

Un client peut demander une boucle de conseil à chaud avec un serveur en spécifiant le type de transaction XTYP_ADVSTART dans un appel à DdeClientTransaction. Pour demander une boucle d’avis chaud, le client doit combiner l’indicateur XTYPF_NODATA avec le type de transaction XTYP_ADVSTART . Dans les deux cas, le DDEML transmet la transaction XTYP_ADVSTART à la fonction de rappel DDE (Dynamic Data Exchange) du serveur. La fonction de rappel DDE du serveur doit examiner les paramètres qui accompagnent la transaction XTYP_ADVSTART (y compris le format, le nom de la rubrique et le nom de l’élément demandé), puis retourner TRUE pour permettre à la boucle d’avis ou FALSE de la refuser.

Une fois qu’une boucle d’avertissement a été établie, l’application serveur doit appeler la fonction DdePostAdvise chaque fois que la valeur de l’élément associé au nom de l’élément demandé change. Cet appel entraîne l’envoi d’une transaction XTYP_ADVREQ à la fonction de rappel DDE du serveur. La fonction de rappel DDE du serveur doit retourner un handle de données qui identifie la nouvelle valeur de l’élément de données. Le DDEML avertit ensuite le client que l’élément spécifié a changé en envoyant la transaction XTYP_ADVDATA à la fonction de rappel DDE du client.

Si le client a demandé une boucle d’avis à chaud, le DDEML transmet le handle de données à l’élément modifié au client pendant la transaction XTYP_ADVDATA . Sinon, le client peut envoyer une transaction XTYP_REQUEST pour obtenir le handle de données.

Un serveur peut envoyer des mises à jour plus rapidement qu’un client ne peut traiter les nouvelles données. La vitesse des mises à jour peut être un problème pour un client qui doit effectuer de longues opérations de traitement sur les données. Dans ce cas, le client doit spécifier l’indicateur XTYPF_ACKREQ lorsqu’il demande une boucle d’avertissement. Cet indicateur oblige le serveur à attendre que le client reconnaisse qu’il a reçu et traité un élément de données avant que le serveur envoie l’élément de données suivant. Les boucles d’avis établies avec l’indicateur XTYPF_ACKREQ sont plus robustes avec les serveurs rapides, mais peuvent parfois manquer des mises à jour. Les boucles d’avertissement établies sans l’indicateur XTYPF_ACKREQ sont garanties de ne pas manquer les mises à jour tant que le client suit le serveur.

Un client peut mettre fin à une boucle d’avertissement en spécifiant le type de transaction XTYP_ADVSTOP dans un appel à DdeClientTransaction.

Si un serveur ne prend pas en charge les boucles d’avertissement, il doit spécifier l’indicateur de filtre CBF_FAIL_ADVISES dans la fonction DdeInitialize . Cet indicateur empêche le DDEML d’envoyer les transactions XTYP_ADVSTART et XTYP_ADVSTOP au serveur.

Exécuter la transaction

Un client peut utiliser la transaction XTYP_EXECUTE pour provoquer l’exécution d’une commande ou d’une série de commandes par un serveur.

Pour exécuter une commande serveur, le client crée d’abord une mémoire tampon qui contient une chaîne de commande que le serveur doit exécuter, puis passe un pointeur vers la mémoire tampon ou un handle de données identifiant la mémoire tampon lorsqu’il appelle DdeClientTransaction. Les autres paramètres requis incluent le handle de conversation, le handle de chaîne de nom d’élément, la spécification de format et le type de transaction XTYP_EXECUTE . Une application qui crée un handle de données pour transmettre des données d’exécution doit spécifier NULL pour le paramètre hszItem de la fonction DdeCreateDataHandle et zéro pour le paramètre uFmt .

Le DDEML transmet la transaction XTYP_EXECUTE à la fonction de rappel DDE du serveur et spécifie le nom de format, le handle de conversation, le nom de la rubrique et le handle de données identifiant la chaîne de commande. Si le serveur prend en charge la commande, il doit utiliser la fonction DdeAccessData pour obtenir un pointeur vers la chaîne de commande, exécuter la commande, puis retourner DDE_FACK. Si le serveur ne prend pas en charge la commande ou ne peut pas terminer la transaction, il doit retourner DDE_FNOTPROCESSED. Le serveur doit retourner DDE_FBUSY s’il est trop occupé pour terminer la transaction.

En règle générale, la fonction de rappel d’un serveur doit traiter la transaction XTYP_EXECUTE avant de retourner avec les exceptions suivantes :

  1. Lorsque la commande passée avec la transaction XTYP_EXECUTE demande l’arrêt du serveur, le serveur ne doit pas s’arrêter tant que sa fonction de rappel n’est pas retournée après le traitement XTYP_EXECUTE.
  2. Si le serveur doit effectuer une opération, telle que le traitement d’une boîte de dialogue ou d’une transaction DDE susceptible de provoquer des problèmes de récursion DDEML, le serveur doit retourner le code de retour CBR_BLOCK pour bloquer la transaction d’exécution, effectuer l’opération, puis reprendre le traitement de la transaction d’exécution.

Lorsque DdeClientTransaction retourne, le client peut utiliser le paramètre lpdwResult pour accéder à l’indicateur status transaction. Si l’indicateur est DDE_FBUSY, le client doit renvoyer la transaction ultérieurement.

Si un serveur ne prend pas en charge la transaction XTYP_EXECUTE , il doit spécifier l’indicateur de filtre CBF_FAIL_EXECUTES dans la fonction DdeInitialize . Cela empêche le DDEML d’envoyer la transaction au serveur.

Transactions synchrones et asynchrones

Un client peut envoyer des transactions synchrones ou asynchrones. Dans une transaction synchrone, le client spécifie une valeur de délai d’attente qui indique la durée maximale pendant laquelle le serveur doit traiter la transaction. DdeClientTransaction ne retourne pas tant que le serveur ne traite pas la transaction, que la transaction échoue ou que la valeur du délai d’expiration n’a pas expiré. Le client spécifie la valeur de délai d’attente lorsqu’il appelle DdeClientTransaction.

Pendant une transaction synchrone, le client entre une boucle modale en attendant que la transaction soit traitée. Le client peut toujours traiter l’entrée utilisateur, mais ne peut pas envoyer une autre transaction synchrone tant que DdeClientTransaction n’est pas retourné.

Un client envoie une transaction asynchrone en spécifiant l’indicateur TIMEOUT_ASYNC dans DdeClientTransaction. La fonction retourne après le début de la transaction, en passant un identificateur de transaction au client. Lorsque le serveur termine le traitement de la transaction asynchrone, le DDEML envoie une XTYP_XACT_COMPLETE transaction au client. L’identificateur de transaction est l’un des paramètres que le DDEML transmet au client pendant la transaction XTYP_XACT_COMPLETE . En comparant cet identificateur de transaction avec l’identificateur retourné par DdeClientTransaction, le client identifie la transaction asynchrone que le serveur a terminée.

Un client peut utiliser la fonction DdeSetUserHandle comme aide au traitement d’une transaction asynchrone. Cette fonction permet à un client d’associer une valeur définie par l’application à un handle de conversation et à un identificateur de transaction. Le client peut utiliser la fonction DdeQueryConvInfo pendant la transaction XTYP_XACT_COMPLETE pour obtenir la valeur définie par l’application. En raison de cette fonction, une application n’a pas besoin de tenir à jour une liste d’identificateurs de transaction actifs.

Lorsqu’un client termine correctement une demande de données à l’aide d’une transaction synchrone, le DDEML n’a aucun moyen de dire quand le client a terminé d’utiliser les données reçues. L’application cliente doit passer le handle de données reçu à la fonction DdeFreeDataHandle , en informant le DDEML que le handle ne sera plus utilisé. Les handles de données retournés par les transactions synchrones appartiennent effectivement au client.

Si un serveur ne traite pas une transaction asynchrone en temps opportun, le client peut abandonner la transaction en appelant la fonction DdeAbandonTransaction . Le DDEML libère toutes les ressources associées à la transaction et ignore les résultats de la transaction lorsque le serveur a terminé son traitement. Un délai d’attente pendant une transaction synchrone annule effectivement la transaction.

La méthode de transaction asynchrone est fournie pour les applications qui doivent envoyer un volume élevé de transactions DDE tout en effectuant simultanément une quantité importante de traitement, comme l’exécution de calculs. La méthode asynchrone est également utile dans les applications qui doivent arrêter temporairement le traitement des transactions DDE afin qu’elles puissent effectuer d’autres tâches sans interruption. Dans la plupart des autres situations, une application doit utiliser la méthode synchrone.

Les transactions synchrones sont plus simples à gérer et sont plus rapides que les transactions asynchrones. Toutefois, une seule transaction synchrone peut être effectuée à la fois, tandis que de nombreuses transactions asynchrones peuvent être effectuées simultanément. Avec les transactions synchrones, un serveur lent peut entraîner l’inactivité d’un client pendant qu’il attend une réponse. En outre, les transactions synchrones obligent le client à entrer une boucle modale qui peut contourner le filtrage des messages dans la boucle de message de l’application.

Si le client a installé une procédure de hook pour filtrer les messages (autrement dit, spécifié le type de hook WH_MSGFILTER dans un appel à la fonction SetWindowsHookEx ), une transaction synchrone n’entraîne pas le contournement de la procédure de hook par le système. Lorsqu’un événement d’entrée se produit alors que le client attend la fin d’une transaction synchrone, la procédure de hook reçoit un code de hook MSGF_DDEMGR. Le main danger de l’utilisation d’une boucle modale de transaction synchrone est qu’une boucle modale créée par une boîte de dialogue peut interférer avec son fonctionnement. Les transactions asynchrones doivent toujours être utilisées lorsque le DDEML est utilisé par une DLL.

Contrôle des transactions

Une application peut suspendre les transactions vers sa fonction de rappel DDE, soit les transactions associées à un handle de conversation spécifique, soit toutes les transactions, quel que soit le handle de conversation. Cette fonctionnalité est utile lorsqu’une application reçoit une transaction qui nécessite un traitement long. Dans ce cas, l’application peut retourner le code de retour CBR_BLOCK pour suspendre les transactions futures associées au handle de conversation de la transaction, afin que l’application soit libre de traiter d’autres conversations.

Une fois le traitement terminé, l’application appelle la fonction DdeEnableCallback pour reprendre les transactions associées à la conversation suspendue. L’appel de DdeEnableCallback entraîne le renvoi de la transaction par le DDEML qui a entraîné la suspension de la conversation par l’application. Par conséquent, l’application doit stocker le résultat de la transaction de telle sorte qu’elle puisse obtenir et retourner le résultat sans retraiter la transaction.

Une application peut suspendre toutes les transactions associées à un handle de conversation spécifique en spécifiant le handle et l’indicateur EC_DISABLE dans un appel à DdeEnableCallback. En spécifiant un handle NULL , une application peut suspendre toutes les transactions pour toutes les conversations.

Lorsqu’une conversation a été suspendue, le DDEML enregistre les transactions pour la conversation dans une file d’attente de transactions. Lorsque l’application réactive la conversation, le DDEML supprime les transactions enregistrées de la file d’attente et passe chaque transaction à la fonction de rappel appropriée. La capacité de la file d’attente de transactions est importante, mais une application doit réactiver une conversation suspendue dès que possible pour éviter de perdre des transactions.

Une application peut reprendre le traitement habituel des transactions en spécifiant l’indicateur EC_ENABLEALL dans DdeEnableCallback. Pour une reprise plus contrôlée du traitement des transactions, l’application peut spécifier l’indicateur EC_ENABLEONE. Cet indicateur supprime une transaction de la file d’attente de transactions et la transmet à la fonction de rappel appropriée ; une fois cette transaction traitée, toutes les conversations sont à nouveau désactivées.

Si l’indicateur EC_ENABLEONE et un handle de conversation sont spécifiés dans l’appel à DdeEnableCallback, seule cette conversation est bloquée une fois la transaction traitée. Si un handle de conversation NULL est spécifié, toutes les conversations sont bloquées une fois qu’une transaction a été traitée dans une conversation.

Transaction Classes

Le DDEML a quatre classes de transactions. Chaque classe est identifiée par une constante qui commence par le préfixe XCLASS_. Les classes sont définies dans le fichier d’en-tête DDEML. La valeur de classe est combinée à la valeur de type transaction et est transmise à la fonction de rappel DDE de l’application de réception.

La classe d’une transaction détermine la valeur de retour qu’une fonction de rappel est censée retourner si elle traite la transaction. Les valeurs de retour et les types de transaction suivants sont associés à chacune des quatre classes de transaction.

Classe Valeur retournée Transaction
XCLASS_BOOL TRUE ou FALSE XTYP_ADVSTART
XTYP_CONNECT
XCLASS_DATA Un handle de données, le code de retour CBR_BLOCK ou NULL XTYP_ADVREQ
XTYP_REQUEST
XTYP_WILDCONNECT
XCLASS_FLAGS Indicateur de transaction : DDE_FACK, DDE_FBUSY ou DDE_FNOTPROCESSED XTYP_ADVDATA
XTYP_EXECUTE
XTYP_POKE
XCLASS_NOTIFICATION None XTYP_ADVSTOP
XTYP_CONNECT_CONFIRM
XTYP_DISCONNECT
XTYP_ERROR
XTYP_REGISTER
XTYP_UNREGISTER
XTYP_XACT_COMPLETE

Types de transactions

Chaque type de transaction DDE a un récepteur et une activité associée qui entraîne la génération de chaque type par le DDEML.

Type de transaction Destinataire Cause
XTYP_ADVDATA Client Un serveur a répondu à une transaction XTYP_ADVREQ en retournant un handle de données.
XTYP_ADVREQ Serveur Un serveur a appelé la fonction DdePostAdvise , indiquant que la valeur d’un élément de données dans une boucle d’avis avait changé.
XTYP_ADVSTART Serveur Un client a spécifié le type de transaction XTYP_ADVSTART dans un appel à la fonction DdeClientTransaction .
XTYP_ADVSTOP Serveur Un client a spécifié le type de transaction XTYP_ADVSTOP dans un appel à DdeClientTransaction.
XTYP_CONNECT Serveur Un client a appelé la fonction DdeConnect et a spécifié un nom de service et un nom de rubrique pris en charge par le serveur.
XTYP_CONNECT_CONFIRM Serveur Le serveur a retourné TRUE en réponse à une transaction XTYP_CONNECT ou XTYP_WILDCONNECT .
XTYP_DISCONNECT Client/serveur Un partenaire dans une conversation appelée fonction DdeDisconnect , ce qui permet aux deux partenaires de recevoir cette transaction.
XTYP_ERROR Client/serveur Une erreur critique s’est produite. Le DDEML n’a peut-être pas suffisamment de ressources pour continuer.
XTYP_EXECUTE Serveur Un client a spécifié le type de transaction XTYP_EXECUTE dans un appel à DdeClientTransaction.
XTYP_MONITOR Application de supervision DDE Un événement DDE s’est produit dans le système. Pour plus d’informations sur les applications de supervision DDE, consultez Supervision des applications.
XTYP_POKE Serveur Un client a spécifié le type de transaction XTYP_POKE dans un appel à DdeClientTransaction.
XTYP_REGISTER Client/serveur Une application serveur a utilisé la fonction DdeNameService pour inscrire un nom de service.
XTYP_REQUEST Serveur Un client a spécifié le type de transaction XTYP_REQUEST dans un appel à DdeClientTransaction.
XTYP_UNREGISTER Client/serveur Une application serveur a utilisé DdeNameService pour annuler l’inscription d’un nom de service.
XTYP_WILDCONNECT Serveur Un client appelé fonction DdeConnect ou DdeConnectList , spécifiant NULL pour le nom du service, le nom de la rubrique ou les deux.
XTYP_XACT_COMPLETE Client Une transaction asynchrone, envoyée lorsque le client a spécifié l’indicateur TIMEOUT_ASYNC dans un appel à DdeClientTransaction, s’est terminée.