0

In this MSDN code example:

// Description:
//   Creates a tooltip for an item in a dialog box. 
// Parameters:
//   idTool - identifier of an dialog box item.
//   nDlg - window handle of the dialog box.
//   pszText - string to use as the tooltip text.
// Returns:
//   The handle to the tooltip.
//
HWND CreateToolTip(int toolID, HWND hDlg, PTSTR pszText)
{
    if (!toolID || !hDlg || !pszText)
    {
        return FALSE;
    }
    // Get the window of the tool.
    HWND hwndTool = GetDlgItem(hDlg, toolID);
    
    // Create the tooltip. g_hInst is the global instance handle.
    HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
                              WS_POPUP |TTS_ALWAYSTIP | TTS_BALLOON,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              hDlg, NULL, 
                              g_hInst, NULL);
    
   if (!hwndTool || !hwndTip)
   {
       return (HWND)NULL;
   }                              
                              
    // Associate the tooltip with the tool.
    TOOLINFO toolInfo = { 0 };
    toolInfo.cbSize = sizeof(toolInfo);
    toolInfo.hwnd = hDlg;                          // first HWND
    toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
    toolInfo.uId = (UINT_PTR)hwndTool;             // second HWND
    toolInfo.lpszText = pszText;
    SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);

    return hwndTip;
}

we associate TTM_ADDTOOL operation with two HWND handles, one is the Dialogbox(hDlg), another is a control inside the dialogbox. I tried and found that commenting out toolInfo.hwnd = hDlg; can still have the tooltip show up when mouse hovering on the toolID control.

Then what's the sense passing two HWND handles? Is it a must or useful in other cases?

Jimm Chen
  • 3,411
  • 3
  • 35
  • 59
  • You didn't actually use two window handles, you merely set the tip's *id*. Which can be handy later when you need to dynamically generate the tooltip text. You get the flag and the id back in the TTN_GETDISPINFO and TTN_NEEDTEXT notifications. – Hans Passant Nov 14 '15 at 13:50
  • @HansPassant: The 'ID' really is a *HWND*, when using the `TTF_IDISHWND` flag (which the code in question does). – IInspectable Nov 14 '15 at 15:28
  • Sure. And the notification passes the flag back as well so that the message handler knows that it has a valid window handle. The operating system doesn't care what kind of id you use. – Hans Passant Nov 14 '15 at 15:59

2 Answers2

2

The hwnd in the TOOLINFO structure is also used when you set the lpszText field to LPSTR_TEXTCALLBACK. When the tooltip needs text it will send a TTN_GETDISPINFO notification through a WM_NOTIFY message to that hwnd. That message's LPARAM will then be a pointer to a NMTTDISPINFO structure which you can then use to set the text of the tool tip. Good in case the tooltip's text needs to change.

  • 1
    You're right, and MSDN page(https://msdn.microsoft.com/en-us/library/windows/desktop/bb760250(v=vs.85).aspx) states it explicitly and a bit vaguely. I read it three times to get the idea. So, one HWND is to identify the hot area(called the "tool"), another HWND is used as a notification callback facility -- in case you want that notification. – Jimm Chen Nov 14 '15 at 16:37
0

In addition to the reason explained in the accepted answer, when informing a hwnd, the rect member uses the client area of the window behind this handle as the basis for its coordinates.

When hwnd is not used or it points to an invalid handle, the rect member is screen-relative, which can cause unexpected behavior. So, unless you want to do something very specific that takes the desktop into account, whenever you want to use rect, you need to provide a valid handle in hwnd.

I didn't find this explained anywhere. My observation of using this handle and the rect member made me understand that they are related in this way.