Concepts de base (DDE)
Ces concepts sont essentiels pour comprendre l'échange dynamique de données (DDE) et la bibliothèque de gestion de l'échange dynamique de données (DDEML).
- Interaction entre le client et le serveur
- Transactions et fonction de rappel DDE
- Noms des services, des rubriques et des éléments
- Rubrique du système
- Initialisation
- Fonction de rappel
- Gestion des cordes
- DDEML et threads
Interaction entre le client et le serveur
L'échange dynamique de données se produit toujours entre une application client et une application serveur. L'application client DDE initie l'échange en établissant une conversation avec le serveur pour lui envoyer des transactions. Une transaction est une requête de données ou de services. L'application serveur DDE répond aux transactions en fournissant des données ou des services au client. Par exemple, une application graphique peut contenir un graphique à barres représentant les bénéfices trimestriels d'une société, mais les données pour le graphique à barres peuvent être contenues dans une application de feuille de calcul. Pour obtenir les derniers chiffres des bénéfices, l'application graphique (le client) pourrait établir une conversation avec l'application tableur (le serveur). L'application graphique pourrait alors envoyer une transaction à l'application tableur, en requérant les derniers chiffres des bénéfices.
Un serveur peut avoir plusieurs clients en même temps, et un client peut requérir des données auprès de plusieurs serveurs. Une application peut également être à la fois un client et un serveur. Le client ou le serveur peut mettre fin à la conversation à tout moment.
Transactions et fonction de rappel DDE
Le DDEML informe une application de l'activité DDE qui l'affecte en envoyant des transactions à la fonction de rappel DDE de l'application. Une transaction DDE est similaire à un message : il s'agit d'une constante nommée accompagnée d'autres paramètres qui contiennent des informations supplémentaires sur la transaction.
Le DDEML transmet une transaction à une fonction de rappel DDE définie par l'application qui effectue une action appropriée au type de transaction. Par exemple, lorsqu'une application client tente d'établir une conversation avec une application serveur, le client appelle la fonction DdeConnect Cette fonction permet au DDEML d'envoyer une transaction XTYP_CONNECT à la fonction de rappel DDE du serveur. La fonction de rappel peut autoriser la conversation en renvoyant TRUE au DDEML, ou la refuser en renvoyant FALSE. Pour une discussion détaillée sur les transactions, voir la section Gestion des transactions.
Noms de service, noms de rubrique et noms d'élément
Un serveur DDE utilise un nom de service à trois niveaux hiérarchiques (appelé « nom d'application » dans la documentation DDE précédente), un nom de rubrique et un nom d'élément pour identifier de manière unique une unité de données que le serveur peut échanger au cours d'une conversation.
Un nom de service est une chaîne de caractères à laquelle répond une application serveur lorsqu'un client tente d'établir une conversation avec le serveur. Un client doit spécifier ce nom de service pour établir une conversation avec le serveur. Bien qu'un serveur puisse répondre à plusieurs noms de service, la plupart des serveurs ne répondent qu'à un seul nom.
Le nom d'une rubrique est une chaîne de caractères qui identifie un contexte logique de données. Pour les serveurs qui traitent des documents sous forme de fichiers, les noms de rubrique sont généralement des noms de fichiers ; pour les autres serveurs, il s'agit d'autres chaînes spécifiques à l'application. Un client doit spécifier un nom de rubrique en même temps que le nom de service d'un serveur lorsqu'il tente d'établir une conversation avec un serveur.
Un nom d'élément est une chaîne de caractères qui identifie une unité de données qu'un serveur peut transmettre à un client au cours d'une transaction. Par exemple, un nom d'élément peut identifier un nombre entier, une chaîne, plusieurs paragraphes de texte ou une image bitmap.
Les noms de service, de rubrique et d'élément permettent au client d'établir une conversation avec un serveur et de recevoir des données de ce dernier.
Rubrique du système
La rubrique Système fournit un contexte pour les informations d'intérêt général à tout client DDE. Il est recommandé que les applications serveur prennent en charge la rubrique Système à tout moment. La rubrique Système est définie dans le fichier d'en-tête DDEML.H sous le nom de SZDDESYS_TOPIC.
Pour déterminer quels sont les serveurs présents et les types d'informations qu'ils peuvent fournir, une application client peut demander une requête sur la rubrique Système au démarrage, en fixant le nom de l'appareil à NULL. Ces caractères génériques sont coûteux en termes de performances du système et doivent donc être réduits au minimum. Pour plus d'informations sur le lancement de conversations DDE, voir Gestion des conversations.
Un serveur doit prendre en charge les noms d'éléments suivants dans la rubrique System et tout autre nom d'élément utile à un client.
Élément | Description |
---|---|
SZDDE_ITEM_ITEMLIST | Liste des éléments pris en charge dans une rubrique autre que celle du système. (Cette liste peut varier d'un moment à l'autre et d'une rubrique à l'autre). |
SZDDESYS_ITEM_FORMATS | Une liste de chaînes délimitées par des tabulations représentant tous les formats de presse-papiers potentiellement pris en charge par l'application de service. Les chaînes qui représentent des formats de presse-papiers prédéfinis sont équivalentes aux valeurs CF_ sans le préfixe « CF_ ». Par exemple, le format CF_TEXT est représenté par la chaîne « TEXT ». Ces chaînes doivent être en majuscules pour mieux les identifier comme des formats prédéfinis. La liste des formats doit apparaître dans l'ordre du plus riche en contenu au moins riche en contenu. Pour plus d'informations sur les formats du presse-papiers et le rendu des données, voir Presse-papiers. |
SZDDESYS_ITEM_HELP | Informations d'intérêt général lisibles par l'utilisateur. Cet élément doit contenir, au minimum, des informations sur l'utilisation des fonctionnalités DDE de l'application serveur. Ces informations peuvent inclure, sans s'y limiter, la manière de spécifier des éléments dans les rubriques, les chaînes d'exécution que le serveur peut exécuter, les transactions poke autorisées et la manière de trouver de l'aide sur d'autres éléments de la rubrique Système. |
SZDDESYS_ITEM_RTNMSG | Informations complémentaires concernant le dernier message WM_DDE_ACK utilisé. Cet élément est utile lorsque plus de 8 bits de données de retour spécifiques à l'application sont nécessaires. |
SZDDESYS_ITEM_STATUS | Indication de l'état actuel du serveur. En général, cet élément ne prend en charge que le format CF_TEXT et contient la chaîne Ready ou Busy. |
SZDDESYS_ITEM_SYSITEMS | Liste des éléments pris en charge par ce serveur dans la rubrique Système. |
SZDDESYS_ITEM_TOPICS | Liste des rubriques prises en charge par le serveur à l'heure actuelle. (Cette liste peut varier d'un moment à l'autre). |
Ces noms d'éléments sont des valeurs définies dans le fichier d'en-tête DDEML.H. Pour obtenir les handles de ces chaînes, une application doit utiliser les fonctions de gestion des chaînes de DDEML, comme elle le ferait pour n'importe quelle autre chaîne dans une application DDEML. Pour plus d'informations sur la gestion des chaînes de caractères, voir Gestion des chaînes de caractères.
Initialisation
Avant d'appeler toute autre fonction DDEML, une application doit appeler la fonction DdeInitialize. DdeInitialize obtient un identifiant d'instance pour l'application, enregistre la fonction de rappel DDE de l'application avec le DDE et spécifie les indicateurs de filtre de transaction pour la fonction de rappel.
Chaque instance d'une application ou d'une DLL doit transmettre son identifiant d'instance en tant que paramètre idInst à toute autre fonction DDEML qui le requiert. L'objectif des instances DDEML multiples est de prendre en charge les DLL qui doivent utiliser le DDEML en même temps qu'une application l'utilise. Une application ne doit pas utiliser plus d'une instance de DDEML.
Les filtres de transaction optimisent les performances du système en empêchant le DDEML de transmettre des transactions indésirables à la fonction de rappel DDE de l'application. Une application définit les filtres de transaction dans le paramètre ufCmd de DdeInitialize. Une application doit spécifier un indicateur de filtre de transaction pour chaque type de transaction qu'elle ne traite pas dans sa fonction de rappel. Une application peut modifier ses filtres de transaction lors d'un appel ultérieur à DdeInitialize. Pour plus d'informations sur les transactions, reportez-vous à la section Gestion des transactions.
L'exemple suivant montre comment initialiser une application pour qu'elle utilise le DDEML.
DWORD idInst = 0;
HINSTANCE hinst;
DdeInitialize(&idInst, // receives instance identifier
(PFNCALLBACK) DdeCallback, // pointer to callback function
CBF_FAIL_EXECUTES | // filter XTYPE_EXECUTE
CBF_SKIP_ALLNOTIFICATIONS, // filter notifications
0);
Une application doit appeler la fonction DdeUninitialize lorsqu'elle n'utilise plus le DDEML. Cette fonction met fin à toutes les conversations actuellement ouvertes pour l'application et libère les ressources DDEML allouées par le système pour l'application.
Fonction de rappel
Une application qui utilise le DDEML doit fournir une fonction de rappel qui traite les événements DDE affectant l'application. Le DDEML informe l'application de ces événements en envoyant des transactions à la fonction de rappel DDE de l'application. Les transactions qu'une fonction de rappel reçoit dépendent des indicateurs de filtre de rappel que l'application a spécifiés dans DdeInitialize et du fait que l'application est un client, un serveur ou les deux. Pour plus d'informations, veuillez consulter DdeCallback.
L'exemple suivant montre la structure générale d'une fonction de rappel pour une application client typique.
HDDEDATA CALLBACK DdeCallback(uType, uFmt, hconv, hsz1,
hsz2, hdata, dwData1, dwData2)
UINT uType; // transaction type
UINT uFmt; // clipboard data format
HCONV hconv; // handle to conversation
HSZ hsz1; // handle to string
HSZ hsz2; // handle to string
HDDEDATA hdata; // handle to global memory object
DWORD dwData1; // transaction-specific data
DWORD dwData2; // transaction-specific data
{
switch (uType)
{
case XTYP_REGISTER:
case XTYP_UNREGISTER:
.
.
.
return (HDDEDATA) NULL;
case XTYP_ADVDATA:
.
.
.
return (HDDEDATA) DDE_FACK;
case XTYP_XACT_COMPLETE:
//
return (HDDEDATA) NULL;
case XTYP_DISCONNECT:
//
return (HDDEDATA) NULL;
default:
return (HDDEDATA) NULL;
}
}
Le paramètre uType spécifie le type de transaction envoyé à la fonction de rappel par le DDEML. Les valeurs des autres paramètres dépendent du type de transaction. Les types de transaction et les événements qui les génèrent sont décrits dans les rubriques suivantes. Pour obtenir des informations détaillées sur chaque type de transaction, reportez-vous à la section Gestion des transactions.
Gestion des chaînes de caractères
Pour exécuter une tâche DDE, de nombreuses fonctions DDEML nécessitent l'accès à des chaînes de caractères. Par exemple, un client doit spécifier un nom de service et un nom de rubrique lorsqu'il appelle la fonction DdeConnect pour demander une conversation avec un serveur. Une application spécifie une chaîne en passant un handle de chaîne (HSZ) plutôt qu'un pointeur dans une fonction DDEML. Un handle de chaîne est une valeur DWORD, attribuée par le système, qui identifie une chaîne.
Une application peut obtenir un handle de chaîne de caractères pour une chaîne particulière en appelant la fonction DdeCreateStringHandle. Cette fonction enregistre la chaîne avec le système et renvoie un handle de chaîne à l'application. L'application peut transmettre le handle aux fonctions DDEML qui doivent accéder à la chaîne. L'exemple suivant permet d'obtenir des handles de chaîne pour la chaîne de la rubrique Système et la chaîne du nom du service.
HSZ hszServName;
HSZ hszSysTopic;
hszServName = DdeCreateStringHandle(
idInst, // instance identifier
"MyServer", // string to register
CP_WINANSI); // Windows ANSI code page
hszSysTopic = DdeCreateStringHandle(
idInst, // instance identifier
SZDDESYS_TOPIC, // System topic
CP_WINANSI); // Windows ANSI code page
Le paramètre idInst dans l'exemple précédent spécifie l'identifiant de l'instance obtenu par la fonction DdeInitialize.
La fonction de rappel DDE d'une application reçoit un ou plusieurs handles de chaîne au cours de la plupart des transactions DDE. Par exemple, un serveur reçoit deux chaînes de caractères au cours de la transaction XTYP_REQUEST : l'une identifie une chaîne de caractères spécifiant un nom de rubrique, et l'autre identifie une chaîne de caractères spécifiant un nom d'élément Une application peut obtenir la longueur de la chaîne correspondant à une poignée de chaîne et copier la chaîne dans un tampon défini par l'application en appelant la fonction DdeQueryString, comme le montre l'exemple suivant.
DWORD idInst;
DWORD cb;
HSZ hszServ;
PSTR pszServName;
cb = DdeQueryString(idInst, hszServ, (LPSTR) NULL, 0,
CP_WINANSI) + 1;
pszServName = (PSTR) LocalAlloc(LPTR, (UINT) cb);
DdeQueryString(idInst, hszServ, pszServName, cb, CP_WINANSI);
Un handle de chaîne spécifique à une instance ne peut pas être mappé d'un handle de chaîne à une chaîne et de nouveau à un handle de chaîne. Par exemple, bien que DdeQueryString crée une chaîne à partir d'un handle de chaîne et que DdeCreateStringHandle crée un handle de chaîne à partir de cette chaîne, les deux handles ne sont pas identiques, comme le montre l'exemple suivant.
DWORD idInst;
DWORD cb;
HSZ hszInst, hszNew;
PSZ pszInst;
DdeQueryString(idInst, hszInst, pszInst, cb, CP_WINANSI);
hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI);
// hszNew != hszInst !
Pour comparer les valeurs de deux chaînes de caractères, utilisez la fonction DdeCmpStringHandles.
Un handle de chaîne transmis à la fonction de rappel DDE d'une application devient invalide lorsque la fonction de rappel est renvoyée. Une application peut sauvegarder un handle de chaîne de caractères pour l'utiliser après le retour de la fonction de rappel en utilisant la fonction DdeKeepStringHandle.
Lorsqu'une application appelle DdeCreateStringHandle, le système entre la chaîne spécifiée dans une table de chaînes et génère un handle qu'il utilise pour accéder à la chaîne. Le système maintient également un compte d'utilisation pour chaque chaîne dans la table des chaînes.
Lorsqu'une application appelle DdeCreateStringHandle et spécifie une chaîne qui existe déjà dans la table, le système incrémente le nombre d'utilisations au lieu d'ajouter une autre occurrence de la chaîne. (Une application peut également incrémenter le nombre d'utilisations en utilisant DdeKeepStringHandle). Lorsqu'une application appelle la fonction DdeFreeStringHandle, le système décrémente le nombre d'utilisations.
Une chaîne est supprimée de la table lorsque son compte d'utilisation est égal à zéro. Étant donné que plusieurs applications peuvent obtenir l'identifiant d'une chaîne particulière, une application ne doit pas libérer un identifiant de chaîne plus de fois qu'elle n'a créé ou conservé l'identifiant. Dans le cas contraire, l'application peut entraîner la suppression de la chaîne de caractères de la table, empêchant ainsi les autres applications d'accéder à la chaîne de caractères.
Les fonctions de gestion des chaînes de caractères du DDEML sont basées sur le gestionnaire d'atomes et sont soumises aux mêmes restrictions de taille que les atomes.
DDEML et threads
La fonction DdeInitialize enregistre une application avec le DDEML, en créant une instance DDEML. Une instance DDEML est basée sur un thread, associée au thread qui a appelé DdeInitialize.
Tous les appels de fonctions DDEML pour des objets appartenant à une instance DDEML doivent être effectués à partir du même thread que celui qui a appelé DdeInitialize pour créer l'instance. Si vous appelez une fonction DDEML à partir d'un thread différent, la fonction échouera. Vous ne pouvez pas accéder à une conversation DDEML à partir d'un thread autre que celui qui a alloué la conversation.