locked
How to call TTM_GETBUBBLESIZE before activating tooltip? RRS feed

  • Question

  • I'm trying to position a tracking tooltip before displaying it.  I want to call TTM_GETBUBBLESIZE before activating (TTM_TRACKACTIVATE) the tooltip, so that I can position it properly.  The code works fine on Vista/Win7, but on XP if you call TTM_GETBUBBLESIZE before activating the tooltip, an access violation exception is thrown.  For example:

    HWND CreateTrackingToolTip(int toolID, HWND hDlg, WCHAR* pText)
    {
      // Create a tooltip.
      HWND hwndTT = CreateWindowEx(WS_EX_TOPMOST,
        TOOLTIPS_CLASS, NULL,
        WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,		
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        hDlg, NULL, g_hInst,NULL);
    
      if (!hwndTT)
      {  
        return NULL;
      }
    
      // Set up tool information.
      // In this case, the "tool" is the entire parent window.
      g_toolItem.cbSize = sizeof(TOOLINFO);
      g_toolItem.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
      g_toolItem.hwnd = hDlg;
      g_toolItem.hinst = g_hInst;
      g_toolItem.lpszText = pText;
      g_toolItem.uId = (UINT_PTR)hDlg;
      GetClientRect (hDlg, &g_toolItem.rect);
    
      // Associate the tooltip with the tool window.
      SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &g_toolItem);	
    
      // If I don't do this first, the TTM_GETBUBBLESIZE call throws an exception
      // SendMessage(hwndTT, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&g_toolItem);
    
      // This throws an exception under XP...
      SendMessage(hwndTT, TTM_GETBUBBLESIZE, 0, (LPARAM)&g_toolItem);
    
      return hwndTT;
    }
    

     

    Any suggestions/ideas?

    Thanks,

    Mark

    http://www.beiley.com

    Saturday, March 26, 2011 10:32 PM

Answers

  • Yes, TTM_GETBUBBLESIZE throws access violation if used before TTM_TRACKACTIVATE. I don't know why.

    Workaround can be:

    HWND hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,		
    							 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, hInst, NULL);
    
    TOOLINFO g_toolItem;
    g_toolItem.cbSize = sizeof(TOOLINFO);
    g_toolItem.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
    g_toolItem.hwnd = hWnd;
    g_toolItem.hinst = hInst;
    g_toolItem.lpszText = L"Text";
    g_toolItem.uId = (UINT_PTR)hWnd;
    
    SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &g_toolItem);
    
    SendMessage(hwndTT, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&g_toolItem);
    
    DWORD dwBS = SendMessage(hwndTT, TTM_GETBUBBLESIZE, 0, (LPARAM)&g_toolItem);
    
    RECT rWindowRect = {0};
    GetWindowRect(hWnd, &rWindowRect);
    int nX = (rWindowRect.left + (rWindowRect.right - rWindowRect.left) / 2) - (LOWORD(dwBS) / 2);
    int nY = (rWindowRect.top + (rWindowRect.bottom - rWindowRect.top) / 2) - (HIWORD(dwBS) / 2);
    SendMessage(hwndTT, TTM_TRACKPOSITION, 0, MAKELPARAM(nX, nY));
    


    Nikita Leontiev
    • Marked as answer by lucy-liu Monday, April 4, 2011 9:22 AM
    Tuesday, March 29, 2011 9:54 AM

All replies

  • Are you using ZeroMemory() to initialize g_toolItem?  I ask because of unused fields, like lpReserved which must be NULL.  Try ZeroMemory() and see if it helps.
    MCP
    Sunday, March 27, 2011 6:03 AM
  • Thanks for the help.  Yes, I am zeroing the memory before use.

     

    Mark

    Sunday, March 27, 2011 5:06 PM
  • HWND hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,		
    							 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, hInst, NULL);
    
    TOOLINFO g_toolItem;
    g_toolItem.cbSize = sizeof(TOOLINFO);
    g_toolItem.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
    g_toolItem.hwnd = hWnd;
    g_toolItem.hinst = hInst;
    g_toolItem.lpszText = L"Text";
    g_toolItem.uId = (UINT_PTR)hWnd;
    
    SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &g_toolItem);
    
    RECT rWindowRect = {0};
    GetWindowRect(hWnd, &rWindowRect);
    SendMessage(hwndTT, TTM_TRACKPOSITION, 0, MAKELPARAM(rWindowRect.left + 50, rWindowRect.top + 50));
    
    SendMessage(hwndTT, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&g_toolItem);
    


    Nikita Leontiev
    Monday, March 28, 2011 10:14 AM
  • Hi Nikita,

    Thanks for the help.  I can see how that would work.  It seems odd to me though that you would have to do this.  Is it known that you must call TTM_TRACKACTIVATE before TTM_GETBUBBLESIZE?  There is no mention of it in the documentation that I could find.

    Mark

    Monday, March 28, 2011 3:04 PM
  • According to Implementing Tracking Tooltips article displaying tracking tooltip task can be divided in 3 parts:

    • creating tooltip and using TTM_ADDTOOL to register tooltip;
    • activating tooltip using TTM_TRACKACTIVATE;
    • moving tooltip to right position using TTM_TRACKPOSITION;

    For what purpose TTM_GETBUBBLESIZE is needed?


    Nikita Leontiev
    Monday, March 28, 2011 10:05 PM
  • Hi Nikita,

    I want to center the tooltip above a specific position in the window.  I call TTM_GETBUBBLESIZE so that I know how big it is, and can center it above this position.

    Mark

    Monday, March 28, 2011 10:21 PM
  • Yes, TTM_GETBUBBLESIZE throws access violation if used before TTM_TRACKACTIVATE. I don't know why.

    Workaround can be:

    HWND hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,		
    							 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, hInst, NULL);
    
    TOOLINFO g_toolItem;
    g_toolItem.cbSize = sizeof(TOOLINFO);
    g_toolItem.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
    g_toolItem.hwnd = hWnd;
    g_toolItem.hinst = hInst;
    g_toolItem.lpszText = L"Text";
    g_toolItem.uId = (UINT_PTR)hWnd;
    
    SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &g_toolItem);
    
    SendMessage(hwndTT, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&g_toolItem);
    
    DWORD dwBS = SendMessage(hwndTT, TTM_GETBUBBLESIZE, 0, (LPARAM)&g_toolItem);
    
    RECT rWindowRect = {0};
    GetWindowRect(hWnd, &rWindowRect);
    int nX = (rWindowRect.left + (rWindowRect.right - rWindowRect.left) / 2) - (LOWORD(dwBS) / 2);
    int nY = (rWindowRect.top + (rWindowRect.bottom - rWindowRect.top) / 2) - (HIWORD(dwBS) / 2);
    SendMessage(hwndTT, TTM_TRACKPOSITION, 0, MAKELPARAM(nX, nY));
    


    Nikita Leontiev
    • Marked as answer by lucy-liu Monday, April 4, 2011 9:22 AM
    Tuesday, March 29, 2011 9:54 AM
  • Hi Nikita,

    Thanks again for the help.  This is what I ended up doing, after much trial/error figuring out that it is necessary to call TTM_TRACKACTIVATE before you can get the size.  It seems like a Windows bug, or at the least the documentation needs to be updated to inform you that you must do it in this order.  Ideally you could position the tooltip before activating it.

    Mark

    Tuesday, March 29, 2011 3:27 PM