TooltipClassName: B§ 'Tooltips_class32',0Note the window style: TIS_ALWAYSTIP. This style specifies that the tooltip will be shown when the mouse pointer is over the designated area regardless of the status of the window that contains the area. Put simply, if you use this flag, when the mouse pointer hovers over the area you register to the tooltip control, the tooltip window will appear even if the window under the mouse pointer is inactive......
call 'COMCTL32.InitCommonControls'
call 'USER32.CreateWindowExA' &NULL TooltipClassName &NULL &TIS_ALWAYSTIP, &CW_USEDEFAULT &CW_USEDEFAULT &CW_USEDEFAULT &CW_USEDEFAULT, NULL, &NULL D§hInstance &NULL
[TOOLINFO:
cbSize: D§ ?
uFlags: ?
hWnd: ?
uId: ?
rect: RECT <>
hInst: ?
lpszText: ?
lParam: ?]
Field Name | Explanation |
cbSize | The size of the TOOLINFO structure. You MUST fill this member. Windows will not flag error if this field is not filled properly but you will receive strange, unpredictable results. |
uFlags | The bit flags that specifies the characteristics
of the tool. This value can be a combination of the following flags:
|
hWnd | Handle to the window that contains the tool. If
you specify TTF_IDISHWND flag, this
field is ignored since Windows will use the value in uId
member as the window handle. You need to fill this field if:
|
uId | The value in this field can have two meanings,
depending on whether the uFlags member
contains the flag
TTF_IDISHWND.
|
rect | A RECT structure that specifies the dimension of the tool. This structure defines a rectangle relative to the upper left corner of the client area of the window specified by the hWnd member. In short, you must fill this structure if you want to specify a tool that covers only a part of the client area. The tooltip control will ignore this field if you specify TTF_IDISHWND flag (you choose to use a tool that covers the whole client area) |
hInst | The handle of the instance that contains the string resource that will be used as the tooltip text if the value in the lpszText member specifies the string resource identifier. This may sound confusing. Read the explanation of the lpszText member first and you will understand what this field is used for. The tooltip control ignores this field if the lpszText field doesn't contain a string resource identifier. |
lpszText | This field can have several values:
|
To recapitulate, you need to fill the TOOLINFO structure prior to submitting it to the tooltip control. This structure describes the characteristics of the tool you desire.
; data?SendMessage for this message will return TRUE if the tool is successfully registered with the tooltip control, FALSE otherwise.
[TOOLINFO <>]
.......
; code
.......
<fill the TOOLINFO structure>
.......
call 'USER32.SendMessageA' D§hwndTooltip &TTM_ADDTOOL &NULL TOOLINFO
____________________________________________________________________________________________; Equates:
[IDD_MAINDIALOG 1000]
____________________________________________________________________________________________; Data:
[hwndTool: 0 hInstance: 0
ToolTipsClassName: 'Tooltips_class32' 0
MainDialogText1: 'This is the upper left area of the dialog' 0
MainDialogText2: 'This is the upper right area of the dialog' 0
MainDialogText3: 'This is the lower left area of the dialog' 0
MainDialogText4: 'This is the lower right area of the dialog' 0]
[TOOLINFO: TI_cbSize: len TI_uFlags: 0 TI_hWnd: 0 TI_uId: 0
TI_rect: TIRECT_left: 0 TIRECT_top: 0 TIRECT_right: 0 TIRECT_bottom: 0
TI_hInst: 0 TI_lpszText: 0]
[ID: 0][RECT: RECT_left: 0 RECT_top: 0 RECT_right: 0 RECT_bottom: 0]
____________________________________________________________________________________________
____________________________________________________________________________________________main:
call 'Kernel32.GetModuleHandleA' &NULL | mov D§hInstance eax
call 'USER32.DialogBoxParamA' D§hInstance IDD_MAINDIALOG &NULL DialogProc &NULL
call 'Kernel32.ExitProcess' eax
____________________________________________________________________________________________
____________________________________________________________________________________________Proc DialogProc:
Arguments @Adressee,@Message, @wParam, @lParampushad
.If D@Message = &WM_INITDIALOG
call 'Comctl32.InitCommonControls'
call 'USER32.CreateWindowExA' &NULL ToolTipsClassName &NULL,
&TTS_ALWAYSTIP &CW_USEDEFAULT,
&CW_USEDEFAULT &CW_USEDEFAULT &CW_USEDEFAULT &NULL &NULL,
D§hInstance &NULL
mov D§hwndTool eax
mov D§id 0, D§ti_uFlags &TTF_SUBCLASS
move D§ti_hWnd D@Adressee
call 'USER32.GetWindowRect' D@Adressee RECT
call SetDlgToolArea1call 'USER32.EnumChildWindows' D@Adressee SetChildrenToolTips TOOLINFO
.Else_If D@Message = &WM_CLOSE
call 'USER32.EndDialog' D@Adressee &NULL
.Else
popad | mov eax &FALSE | Exit
.Endif
popad | mov eax &TRUE
EndP__________________________________________________________________________________
[ButtonTextBuffer: 0 #20]; "EnumChildWindows" CallBack does NOT work like all other CallBacks do (!!!!!!!):
; if i write:
;
; > pop eax, D§D§TI_uId, ebx | push eax | ret
;
; ... it hangs. I suppose that "EnumChildWindows" takes care of the stack by itself
; (undocumented).
;
; I have verified that the stack is the same before and after upper call to
; call 'USER32.EnumChildWindows' ... It is!?
SetChildrenToolTips:
pop eax, D§TI_uId | push D§TI_uId, eax | or D§TI_uFlags &TTF_IDISHWND
call 'USER32.GetWindowTextA' D§TI_uId ButtonTextBuffer 80
mov D§TI_lpszText ButtonTextBuffer
call 'USER32.SendMessageA' D§hwndTool &TTM_ADDTOOL &NULL TOOLINFO
ret__________________________________________________________________________________
; The Dialog Box is divided in four rooms. I use Regs like this:
;
; 0 eax ebx
;
; ecx eax/ecx ebx/ecx
;
; edx eax/edx ebx/edx
SetDlgToolArea1:
mov eax D§RECT_right | sub eax D§RECT_left | mov ebx eax | shr eax 1
mov ecx D§RECT_bottom | sub ecx D§RECT_Top | mov edx ecx | shr ecx 1
mov D§TIRECT_left 0, D§TIRECT_top 0, D§TIRECT_Right eax, D§TIRECT_bottom ecx
mov D§TI_lpszText MainDialogText1
call SendToolTipMessagemov D§TIRECT_left eax, D§TIRECT_top 0, D§TIRECT_Right ebx, D§TIRECTBottom ecx
mov D§TI_lpszText MainDialogText2
call SendToolTipMessagemov D§TIRECT_left 0, D§TIRECT_top ecx, D§TIRECT_Right eax, D§TIRECTBottom edx
mov D§TI_lpszText MainDialogText3
call SendToolTipMessagemov D§TIRECT_left eax, D§TIRECT_top ecx, D§TIRECT_Right ebx, D§TIRECTBottom edx
mov D§TI_lpszText MainDialogText4
call SendToolTipMessageret
SendToolTipMessage:
pushad
call 'USER32.SendMessageA' D§hwndTool &TTM_ADDTOOL &NULL TOOLINFO
popad
ret
After that, we proceed to define four tools for each corner of the dialog box.
.If D@Message = &WM_INITDIALOG
call 'Comctl32.InitCommonControls'
call 'USER32.CreateWindowExA' &NULL ToolTipsClassName &NULL,
&TTS_ALWAYSTIP &CW_USEDEFAULT,
&CW_USEDEFAULT &CW_USEDEFAULT,
&CW_USEDEFAULT, &NULL &NULL,
D§hInstance &NULL
mov D§hwndTool eax
mov D§id 0, D§ti_uFlags &TTF_SUBCLASS
move D§ti_hWnd D@Adressee
call 'USER32.GetWindowRect' D@Adressee
RECT
call SetDlgToolArea1
call 'USER32.EnumChildWindows' D@Adressee SetChildrenToolTips TOOLINFO
We initialize the members of TOOLINFO
structure.
Note that we want to divide the client area into 4 tools so we need to
know the dimension of the client area. That's why we call GetWindowRect.
We don't want to relay mouse messages to the tooltip control ourselves
so we specify
TIF_SUBCLASS flag.
SetDlgToolArea
is a function that calculates the bounding rectangle of each tool and registers
the tool to the tooltip control. I won't go into gory detail on the calculation,
suffice to say that it divides the client area into 4 areas with the same
sizes. Then it sends TTM_ADDTOOL message
to the tooltip control, passing the address of the TOOLINFO
structure in the lParam parameter.
call 'USER32.SendMessageA' D§hwndTool &TTM_ADDTOOL &NULL TOOLINFO
After all 4 tools are registered, we can go on to the buttons on the dialog box. We can handle each button by its ID but this is tedious. Instead, we will use EnumChildWindows API call to enumerate all controls on the dialog box and then registers them to the tooltip control. EnumChildWindows has the following syntax:
EnumChildWindows proto hWnd:DWORD, lpEnumFunc:DWORD, lParam:DWORDhWnd is the handle to the parent window. lpEnumFunc is the address of the EnumChildProc function that will be called for each control enumerated. lParam is the application-defined value that will be passed to the EnumChildProc function. The EnumChildProc function has the following definition:
EnumChildProc proto hwndChild:DWORD, lParam:DWORDhwndChild is the handle to a control enumerated by EnumChildWindows. lParam is the same lParam value you pass to EnumChildWindows.
call 'USER32.EnumChildWindows' D@Adressee SetChildrenToolTips TOOLINFOWe pass the address of the TOOLINFO structure in the lParam parameter because we will register each child control to the tooltip control in the EnumChild function. If we don't use this method, we need to declare ti as a global variable which can introduce bugs.
Note that in this case, we use a different type of tool: one that covers the whole client area of the window. We thus need to fill the uID field with the handle to the window that contains the tool. Also we must specify TTF_IDISHWND flag in the uFlags member.SetChildrenToolTips:
pop eax, D§TI_uId | push D§TI_uId, eax | or D§TI_uFlags &TTF_IDISHWND
call 'USER32.GetWindowTextA' D§TI_uId ButtonTextBuffer 80
mov D§TI_lpszText ButtonTextBuffer
call 'USER32.SendMessageA' D§hwndTool &TTM_ADDTOOL &NULL TOOLINFO
ret