Tutorial 27: Les Bulles d'Information
(Tooltip Control)

Nous allons voir ce qu'est un tooltip et comment le créer puis l'employer. Downloadez l'exemple.

Théorie:

Un tooltip est une petite fenêtre rectangulaire qui apparaît lorsque le pointeur de la souris plane au dessus d'une zone spécifique. En se moment même vous êtes en train de lire ce tutorial, et bien regardez tout en bas à droite, il y a votre horloge. Déplacez votre souris dessus et ne la touchez plus ne cliquez sur rien… voilà ! un ToolTip vient d'apparaître ! c'est ça un ToolTip ! Chaque fenêtre tooltip contient le texte que le programmeur souhaite montrer. À cet égard, un serveur tooltip à le même rôle qu'une fenêtre de statut sauf que ce premier disparaît lorsque l'utilisateur clique ou déplace le pointeur de la souris en dehors du secteur désigné. Vous êtes probablement familiers avec les tooltips qui sont associés aux boutons de la barre d'outils. Ces "tooltips" sont utilement fourni par le contrôle de barre d'outils. Si vous souhaitez avoir des tooltips pour d'autres fenêtres ou commandes, vous avez besoin de créer votre propre contrôle tooltip.
Maintenant que vous savez ce qu'est un tooltip, on va continuer pour voir comment nous pouvons le créer puis l'employer. Les étapes sont déclinées ci-dessous :
  1. Créez un tooltip control avec CreateWindowEx.
  2. Définissez une région, qui si le pointeur de la souris passe dessus, déclenche l'affichage d'un tooltip.
  3. Soumettez cette région au tooltip control.
  4. Retransmettez les messages souris de la région soumise vers le tooltip control (cette étape peut arriver plus tôt, ça dépend de la méthode employée pour retransmettre les messages).
Nous allons ensuite examiner chaque étape en détail.

Création d'un Tooltip:

Un 'tooltip control' est un 'common control' (voir tutorial 18). En tant que tel, vous avez besoin d'appeler InitCommonControls à un moment dans votre code source pour que MASM lie implicitement votre programme avec comctl32.dll. Vous créez un tooltip control avec CreateWindowEx. Le scénario typique est le suivant :
.data
TooltipClassName db "Tooltips_class32",0
.code
.....
invoke InitCommonControls
invoke CreateWindowEx, NULL, addr TooltipClassName, NULL, TIS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL
Remarquez le 'window style': TIS_ALWAYSTIP. Ce style indique que l'on affichera le tooltip lorsque le pointeur de la souris est placée au-dessus du secteur désigné, indépendamment du statut de la fenêtre qui contient ce secteur. Mis seul, si vous employez ce Flag, quand le pointeur de la souris plane sur le secteur, vous faites référence au tooltip control, et la bulle tooltip apparaîtra même si la fenêtre (ou l'objet) sous le pointeur de la souris est inactive.
Vous n'avez pas besoin d'inclure les styles WS_POPUP ni WS_EX_TOOLWINDOW dans CreateWindowEx parce que la procédure de fenêtre du tooltip control les ajoute automatiquement. Vous n'avez pas besoin non plus d'indiquer les coordonnées, la hauteur ni la largeur de la fenêtre tooltip : le tooltip control les ajustera automatiquement en fonction de la longueur de votre texte tooltip qui devra être affichéé, donc nous mettons CW_USEDEFAULT dans les quatre paramètres. Les paramètres restants ne sont négligeables.

Propriétés et définition du Tool (de l'outil).

Le tooltip control est créé mais on ne le montre pas immédiatement. Nous souhaitons que la fenêtre tooltip s'affiche seulement quand le pointeur de la souris plane sur un lieu bien défini. Il est maintenant temps de définir ce secteur. Nous appelons un tel secteur "tool". Chaque tool est un secteur rectangulaire affiché au-dessus du secteur client d'une fenêtre que le tooltip control contrôlera avec le pointeur de la souris. Si la souris passe au dessus d'un tool, la fenêtre tooltip apparaîtra. Ce secteur rectangulaire peut recouvrir le secteur client entier ou bien seulement une partie. Donc nous pouvons divisé les tools dans deux catégories : un qui est fonctionne comme une fenêtre et l'autre qui est fonctionne comme un petit secteur rectangulaire dans le secteur client d'une fenêtre. Tous les deux ont leurs propres utilisations. Un Tool qui recouvre le secteur client d'une fenêtre en entier est le plus fréquemment utilisé, avec en prime d'autres commandes tels que des boutons, des commandes d'édition etc…. Vous n'avez pas besoin de définir les coordonnées ni les dimensions de ce genre de tool : il sera forcément de la taille du secteur client de la fenêtre. Pour un Tool qui fonctionne comme un petit secteur rectangulaire sur le secteur client, on l'utilise seulement lorsque on veut diviser le secteur client d'une fenêtre en plusieurs régions sans employer de fenêtres d'enfant (Child Windows). Avec ce type de tool, vous avez besoin de définir les coordonnées du coin supérieur gauche ainsi que sa largeur et sa hauteur.
Vous définissez un tool grâce à la structure TOOLINFO laquelle a le prototype de fonction suivant :
TOOLINFO STRUCT
  cbSize             DWORD      ?
  uFlags             DWORD      ?
  hWnd               DWORD      ?
  uId                DWORD      ?
  rect               RECT      <>
  hInst              DWORD      ?
  lpszText           DWORD      ?
  lParam             LPARAM     ?
TOOLINFO ENDS
Noms Explications
cbSize est la taille de la structure TOOLINFO. Vous DEVEZ remplir ce membre. Windows vous renverra un flag pour dire qu'il y a une erreur si ce champ n'est pas rempli correctement et vous obtiendrez des résultats étranges, imprévisibles.
uFlags est un flag (de la taille d'un bit) qui défini les caractéristiques du tool. Cette valeur peut être une combinaison de plusieurs flags que voici :
  • TTF_IDISHWND ou "ID est hWnd". Si vous mettez ce flag, ça signifie que vous souhaitez utiliser un tool qui recouvre le secteur client tout entier d'une fenêtre (le premier type de tool vu plus haut). Si vous employez ce flag, vous devez remplir le membre uID de cette structure avec l' handle de la fenêtre que vous souhaitez employer. Si vous ne mettez pas ce Flag, c'est que vous préférez utiliser le deuxième type de tool, celui qui fonctionne comme un petit secteur rectangulaire sur votre fenêtre client. Dans ce cas, vous avez besoin de remplir le membre rect avec les dimensions du rectangle.
  • TTF_CENTERTIP Normalement la fenêtre tooltip apparaîtra à droite et au-dessous du pointeur de la souris. Si vous mettez ce Flag, la fenêtre tooltip apparaîtra toujours directement au-dessous du tool et sera placé indépendamment de la position de la souris.
  • TTF_RTLREADING Vous pouvez laisser tomber ce Flag si votre programme n'est pas conçu spécialement pour des systèmes arabes ou hébreux. Ce Flag affiche le texte tooltip en laissant la possibilité du sens de lecture. Ça ne fonctionnera pas avec d'autres systèmes (comme le notre, système Cyrillique).
  • TTF_SUBCLASS Si vous utilisez ce Flag, ça signifie que vous indiquez au tooltip control de sous-classer la fenêtre sur laquelle le tool est branché, ainsi le tooltip control pourra intercepter les messages souris qui sont envoyés à cette fenêtre. Ce Flag est très pratique. Si vous ne l'employez pas, vous devez faire plus de boulot pour relayer les messages souris vers le tooltip control.
hWnd est l'handle de la fenêtre qui contient le tool. Si vous mettez le flag TTF_IDISHWND, ce champ sera ignoré puisque Windows utilisera la valeur du membre uId en tant qu' handle de la fenêtre. Vous avez besoin de remplir ce champ si :
  • Vous n'utilisez pas le Flag TTF_IDISHWND (Autrement dit, vous utilisez un petit tool rectangulaire)
  • Vous mettez la valeur LPSTR_TEXTCALLBACK dans le membre lpszText. Cette valeur informe le tooltip control que, lorsqu'on a besoin d'afficher la fenêtre tooltip, on doit solliciter cette fenêtre pour que le texte soit affiché. C'est une sorte de mise à jour dynamique du texte tooltip en temps réel. Si vous souhaitez changer dynamiquement votre texte tooltip, vous devez mettre la valeur LPSTR_TEXTCALLBACK dans le membre lpszText. Le tooltip control enverra le message d'avis (l'information) TTN_NEEDTEXT dans la fenêtre identifiée par l'handle hWnd.
uId La valeur a mettre dans ce champ peut avoir deux significations. ça dépend si le membre uFlags (vu plus haut) contient le Flag TTF_IDISHWND.
  • C'est une application définissant l'ID du tool si le flagTTF_IDISHWND n'a pas été indiqué. Puisque dans ce cas vous employez un tool qui recouvre uniquement une petite partie du secteur client, c'est logique que vous puissiez avoir beaucoup de ces mêmes outils semblables sur votre secteur client (sans qu'ils se chevauchent). Le tooltip control a besoin de pouvoir les différencier. Dans ce cas, l'handle de la fenêtre qui est dans le membre hWnd n'est pas assez sélectif puisque tous ces outils sont sur cette même fenêtre. Les 'IDs' sont donc nécessaires. L'IDs représenter n'importe quelles valeurs tant qu'elle restent uniques entre elles.
  • C'est l'handle de la fenêtre dont on utilise la totalité de son secteur client pour afficher le tool si le Flag TTF_IDISHWND a été spécifié. Vous pouvez vous demander pourquoi ce champ est utilisé pour stocker l'handle de la fenêtre au lieu de hWnd. La réponse c'est que le membre hWnd peut déjà être rempli si la valeur LPSTR_TEXTCALLBACK a déjà été spécifiée dans le membre lpszText , en plus la fenêtre qui est responsable de l'approvisionnement du texte tooltip ainsi que la fenêtre qui contient le tool ne peuvent pas être les mêmes (Vous pouvez construire votre programme pour qu'une simple fenêtre puisse jouer ces deux rôles mais c'est trop restrictif. Dans ce cas, Microsoft vous donne plus de liberté. Acclamations.)
rect La structure RECT définie les dimensions du tool. Cette structure définit un rectangle positionné par rapport au coin supérieur gauche du secteur client de la fenêtre (qui peut aussi être un simple objet) choisi par le membre hWnd. Bref, vous devez remplir cette structure si vous voulez avoir un tool qui ne recouvre qu'une partie du secteur client. Le tooltip control ignorera ce champ si vous avez déjà mis le Flag TTF_IDISHWND (Car dans ce cas, c'est que souhaitiez utiliser un tool qui recouvre la totalité de secteur client. Enfin Normalement ! ! ! )
hInst est l'handle de l'instance (du groupe de données) qui contient la chaîne de caractères en ressource lequel sera employé en tant que 'tooltip texte' uniquement si la valeur dans le membre lpszText pointe sur cette chaîne de caractères. Ça peut paraître confus. Lisez d'abord l'explication sur le membre lpszText et vous comprendrez à quoi sert réellement ce champ. Le tooltip control ignora ce champ si le champ lpszText ne contient pas l'identificateur de la chaîne de caractères en ressource.
lpszText Ce champ peut avoir plusieurs valeurs :
  • Si vous mettez la valeur LPSTR_TEXTCALLBACK dans ce champ, le tooltip control enverra le message d'avis TTN_NEEDTEXT à la fenêtre identifiée par son handle dans le champs hWnd pour que la chaîne de caractères soit affichée dans la fenêtre tooltip. C'est la méthode la plus dynamique de mise à jour du texte tooltip : vous pouvez changer ce tooltip texte à chaque fois que la fenêtre tooltip est affichée.
  • Si vous mettez l'identificateur de la chaîne de caractères en ressource dans ce champ, alors lorsque le tooltip control en aura besoin pour montrer le tooltip texte dans la fenêtre tooltip, il recherchera cette chaîne dans le tableau des chaînes de caractères de grâce au membre hInst. Le tooltip control identifie l'identificateur de la chaîne de caractères (en ressource) en vérifiant le mot de poids fort de ce champ (de ce paramètre). Puisque c'est une valeur sur 16 bits, le mot de poids fort dans ce paramètre sera toujours initialisé à zéro. C'est une méthode utile si vous destinez adapter votre programme à d'autres langues. Puisque la chaîne de caractères est définie dans un scénario de ressource, vous n'avez pas besoin de modifier le code source de votre programme lui-même. Il vous suffit seulement de modifier la table des chaînes de caractères et ainsi les tooltip textes changeront sans qu'il y ait le risque que des bogues viennent foutre le bordel dans votre programme.
  • Si la valeur dans ce paramètre n'est pas LPSTR_TEXTCALLBACK et que le mot de poids fort n'est pas à zéro, le tooltip control interprète cette valeur comme l'indicateur (le pointeur) qui est sur la chaîne de caractères qui servira de tooltip texte. Cette méthode est la plus facile à utiliser, mais elle reste moindre flexible.

Pour récapituler, vous avez besoin de remplir la structure TOOLINFO avant de la soumettre au tooltip control. Cette structure définit les caractéristiques du tool que vous désirez obtenir.

Prendre en compte l'existence du 'tool' avec le 'tooltip control'

Après que vous ayez rempli la structure TOOLINFO, vous devez la soumettre au tooltip control. Le tooltip control peut gérer en même temps plusieurs Tools donc il est en général inutile de créer plusieurs tooltip control pour une même fenêtre. Pour associer un tool à un tooltip control, on envoie le message TTM_ADDTOOL au tooltip control. wParam n'est pas utilisé, mais lParam doit absolument contenir l'adresse de la structure TOOLINFO que vous souhaitez enregistrer (lui associer).
.data?
ti TOOLINFO <>
.......
.code
.......
<fill the TOOLINFO structure>
.......
invoke SendMessage, hwndTooltip, TTM_ADDTOOL, NULL, addr ti
SendMessage: Ce message renverra la valeur TRUE si le tool est enregistré avec succès au près du tooltip control, FALSE dans le cas contraire.
Vous pouvez 'désenregistrer' un tool en envoyant le message TTM_DELTOOL au tooltip control.

Transmission des Messages Souris jusqu'au Tooltip Control

Quand on a achevé l'étape ci-dessus, le tooltip control sait quels secteurs (zones) est-ce qu'il doit contrôler quand la souris passe dessus et aussi quel texte il doit afficher dans la fenêtre tooltip. La seule chose qui manque à cette action c'est l' *élément qui la déclenche*. Pensez-y : la zone indiqué par le tool est sur le secteur client de l'autre fenêtre. Comment un tooltip control peut-il intercepter les messages souris destinés à cette fenêtre ? On a besoin de chronométrer les temps de passage du pointeur de la souris au dessus d'un tool pour que si ce temps écoulé est suffisant, pour que le tooltip control affiche la fenêtre du tooltip. Il y a deux méthodes pour faire ça, la première exige la coopération de la fenêtre qui contient le tool alors que l'autre s'effectue sans coopération de la part de cette fenêtre. Voilà. À ce niveau, votre tooltip control est entièrement fonctionnel. Mais il y a plusieurs messages utiles, liés au tooltip, que vous devez connaître.

Exemple:

L'exemple suivant repésente une simple boîte de dialogue munie de deux boutons. Son secteur client est divisé en 4 secteurs : un secteur supérieur gauche, supérieur droit, inférieur droit et inférieur gauche. Chaque secteur sera définit en tant que tool avec son propre tooltip texte. Les deux boutons auront eux aussi leurs propres tooltip textes.
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\comctl32.inc
includelib \masm32\lib\comctl32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD
EnumChild proto :DWORD,:DWORD
SetDlgToolArea proto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
.const
IDD_MAINDIALOG equ 101
.data
ToolTipsClassName db "Tooltips_class32",0
MainDialogText1 db "This is the upper left area of the dialog",0
MainDialogText2 db "This is the upper right area of the dialog",0
MainDialogText3 db "This is the lower left area of the dialog",0
MainDialogText4 db "This is the lower right area of the dialog",0
.data?
hwndTool dd ?
hInstance dd ?
.code
start:
    invoke GetModuleHandle,NULL
    mov hInstance,eax
    invoke DialogBoxParam,hInstance,IDD_MAINDIALOG,NULL,addr DlgProc,NULL
    invoke ExitProcess,eax

DlgProc proc hDlg:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
    LOCAL ti:TOOLINFO
    LOCAL id:DWORD
    LOCAL rect:RECT
    .if uMsg==WM_INITDIALOG
        invoke InitCommonControls
        invoke CreateWindowEx,NULL,ADDR ToolTipsClassName,NULL,\
            TTS_ALWAYSTIP,CW_USEDEFAULT,\
            CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
            hInstance,NULL
        mov hwndTool,eax
        mov id,0
        mov ti.cbSize,sizeof TOOLINFO
        mov ti.uFlags,TTF_SUBCLASS
        push hDlg
        pop ti.hWnd
        invoke GetWindowRect,hDlg,addr rect
        invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText1,id,addr rect
        inc id
        invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText2,id,addr rect
        inc id
        invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText3,id,addr rect
        inc id
        invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText4,id,addr rect
        invoke EnumChildWindows,hDlg,addr EnumChild,addr ti
    .elseif uMsg==WM_CLOSE
        invoke EndDialog,hDlg,NULL
    .else
        mov eax,FALSE
        ret
    .endif
    mov eax,TRUE
    ret
DlgProc endp

EnumChild proc uses edi hwndChild:DWORD,lParam:DWORD
    LOCAL buffer[256]:BYTE
    mov edi,lParam
    assume edi:ptr TOOLINFO
    push hwndChild
    pop [edi].uId
    or [edi].uFlags,TTF_IDISHWND
    invoke GetWindowText,hwndChild,addr buffer,255
    lea eax,buffer
    mov [edi].lpszText,eax
    invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,edi
    assume edi:nothing
    ret
EnumChild endp

SetDlgToolArea proc uses edi esi hDlg:DWORD,lpti:DWORD,lpText:DWORD,id:DWORD,lprect:DWORD
    mov edi,lpti
    mov esi,lprect
    assume esi:ptr RECT
    assume edi:ptr TOOLINFO
    .if id==0
        mov [edi].rect.left,0
        mov [edi].rect.top,0
        mov eax,[esi].right
        sub eax,[esi].left
        shr eax,1
        mov [edi].rect.right,eax
        mov eax,[esi].bottom
        sub eax,[esi].top
        shr eax,1
        mov [edi].rect.bottom,eax
    .elseif id==1
        mov eax,[esi].right
        sub eax,[esi].left
        shr eax,1
        inc eax
        mov [edi].rect.left,eax
        mov [edi].rect.top,0
        mov eax,[esi].right
        sub eax,[esi].left
        mov [edi].rect.right,eax
        mov eax,[esi].bottom
        sub eax,[esi].top
        mov [edi].rect.bottom,eax
    .elseif id==2
        mov [edi].rect.left,0
        mov eax,[esi].bottom
        sub eax,[esi].top
        shr eax,1
        inc eax
        mov [edi].rect.top,eax
        mov eax,[esi].right
        sub eax,[esi].left
        shr eax,1
        mov [edi].rect.right,eax
        mov eax,[esi].bottom
        sub eax,[esi].top
        mov [edi].rect.bottom,eax
    .else
        mov eax,[esi].right
        sub eax,[esi].left
        shr eax,1
        inc eax
        mov [edi].rect.left,eax
        mov eax,[esi].bottom
        sub eax,[esi].top
        shr eax,1
        inc eax
        mov [edi].rect.top,eax
        mov eax,[esi].right
        sub eax,[esi].left
        mov [edi].rect.right,eax
        mov eax,[esi].bottom
        sub eax,[esi].top
        mov [edi].rect.bottom,eax
    .endif
    push lpText
    pop [edi].lpszText
    invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,lpti
    assume edi:nothing
    assume esi:nothing
    ret
SetDlgToolArea endp
end start

Analyse:

Après que la fenêtre de dialogue principale ait été créée, nous créons le tooltip control à son tour avec CreateWindowEx.
invoke InitCommonControls
invoke CreateWindowEx,NULL,ADDR ToolTipsClassName,NULL,\
       TTS_ALWAYSTIP,CW_USEDEFAULT,\
       CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
       hInstance,NULL
mov hwndTool,eax
Après ça, on définit quatre Tools pour chaque coin de la boîte de dialogue.

    mov id,0        ; Employé en tant qu' ID du tool.
    mov ti.cbSize,sizeof TOOLINFO
    mov ti.uFlags,TTF_SUBCLASS    ; Impose au tooltip control de sous-classer la fenêtre de dialogue.
    push hDlg
    pop ti.hWnd    ; handle de la fenêtre qui contient le tool.
    invoke GetWindowRect,hDlg,addr rect    ; Obtient les dimensions du secteur client.
    invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText1,id,addr rect

Nous initialisons les membres de la structure TOOLINFO. Remarquez que nous voulons diviser le secteur client en 4 Tools donc nous avons besoin de connaitre les dimensions du secteur client. C'est pourquoi nous appelons GetWindowRect. Nous ne souhaitons pas transmettre les messages souris au tooltip control nous-mêmes donc nous mettons le Flag TIF_SUBCLASS.
SetDlgToolArea est une fonction qui construit le rectangle de limitation de chaque tool et enregistre ce tool vis à vis du tooltip control. Je n'entrerai pas dans les détails complexes du calcul, il suffirai pour dire qu'elle divise le secteur client en 4 secteurs de mêmes tailles. Donc on envoie le message TTM_ADDTOOL au tooltip control, en passant l'adresse de la structure TOOLINFO dans le paramètre lParam.

    invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,lpti

Après que ces 4 tools soient enregistrés, nous pouvons nous intéresser aux boutons de la boîte de dialogue. Nous pouvons mamipuler chaque bouton par son ID mais ce n'est pas pratique. A la place, nous emploierons l'appel API EnumChildWindows pour dénombrer tous les 'Controls' sur la boîte de dialogue et nous les enregistrons ensuite au près de notre tooltip control. EnumChildWindows a la syntaxe suivante :

EnumChildWindows proto hWnd:DWORD, lpEnumFunc:DWORD, lParam:DWORD
hWnd est l'handle de la fenêtre parente. LpEnumFunc est l'adresse de la fonction EnumChildProc laquelle sera appelée pour chaque contrôle ayant été dénombré. lParam est la valeur que l'on passera à la fonction EnumChildProc. La fonction EnumChildProc a la définition suivante :
EnumChildProc proto hwndChild:DWORD, lParam:DWORD
hwndChild est l'handle d'un contrôle ayant été dénombré par EnumChildWindows. lParam est la même valeur lParam que celle que nous avons passé à EnumChildWindows.
Dans notre exemple, nous appelons EnumChildWindows comme ça :
invoke EnumChildWindows,hDlg,addr EnumChild,addr ti
Nous passons l'adresse de la structure TOOLINFO dans le paramètre lParam parce que nous enregistrerons chaque Child Control de tooltip control dans la fonction EnumChild. Si nous n'utilisons pas cette méthode, nous devons déclarer ti en tant que variable globale, ce qui peut faire apparaître des bogues(défauts).
Lorsqu'on appelle EnumChildWindows, Windows dénombre les Childs Controls de notre boîte de dialogue et appelle la fonction EnumChild à chaque fois qu'il trouve un nouveau control. Donc si notre boîte de dialogue possède deux Childs Controls (ici 2 boutons), EnumChild sera appelée deux fois.
La fonction EnumChild remplit les membres appropriés de la structure TOOLINFO et enregistre ensuite le tool au près du tooltip control.
EnumChild proc uses edi hwndChild:DWORD,lParam:DWORD
    LOCAL buffer[256]:BYTE
    mov edi,lParam
    assume edi:ptr TOOLINFO
    push hwndChild
    pop [edi].uId    ; Nous utilisons la totalité du secteur client du 'Control' en tant que 'tool'.
    or [edi].uFlags,TTF_IDISHWND
    invoke GetWindowText,hwndChild,addr buffer,255
    lea eax,buffer    ; Ceci utilise le texte de la fenêtre comme tooltip texte.
    mov [edi].lpszText,eax
    invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,edi
    assume edi:nothing
    ret
EnumChild endp
Notez que dans ce cas, nous employons un type de tool différent: celui-ci recouvre le secteur client de la fenêtre en entier. Nous avons donc besoin de remplir l'élément uID avec l'handle de la fenêtre qui contient ce tool. C'est pourquoi nous devons mettre le Flag TTF_IDISHWND dans le membre uFlags.

[Iczelion's Win32 Assembly Homepage]


Traduit par Morgatte