2

I have a MFC C++ project which uses a NMTTDISPINFO structure. Everything works correctly when the tooltip text less than 80 characters, but sometimes I need to use a text that is more than 80 characters.

As I have read at MSDN I must use lpszText rather than sztext.

NMTTDISPINFOA structure

My code is:

TTooltipText& tiTxt = *(TTooltipText*)nmhdr;
::SendMessage(NMHDR(tiTxt).hwndFrom, TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
CString pricesStr = GetPrices();
tiTxt.lpszText = pricesStr.GetBuffer(pricesStr.GetLength());

But unfortunately this code doesn't work, any help please?

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
Bassam Najeeb
  • 607
  • 2
  • 7
  • 16
  • 1
    Make sure `hinst` is set to NULL if lpszText is the address of the tooltip text string. Is there any ampersand character or tab character in your string? – Rita Han Jul 09 '19 at 08:30
  • @RitaHan-MSFT Yes I'm use \t and \n characters, but also I have tried a long string without any special characters, also didn't work – Bassam Najeeb Jul 09 '19 at 08:54
  • Have you checked the return value of `SendMessage` to see if it success? – Rita Han Jul 09 '19 at 09:47
  • @RitaHan-MSFT I' checking it now, it returns error -1, why that? any error in my code? – Bassam Najeeb Jul 09 '19 at 09:56
  • Try to send `TTM_SETMAXTIPWIDTH` immediately after creating the tooltip control. It might be too late to call it in tooltip notification handler. – zett42 Jul 09 '19 at 10:08
  • 4
    https://learn.microsoft.com/en-us/cpp/atl-mfc-shared/reference/csimplestringt-class?view=vs-2019#getbufferMSDN: "The buffer memory is automatically freed when the CSimpleStringT object is destroyed." You are passing a pointer to a string (GetPrices) that is not valid after your function goes out of scope. Try to save this string as a class member. – EylM Jul 09 '19 at 10:11
  • @BassamNajeeb Send [TTM_GETMAXTIPWIDTH](https://learn.microsoft.com/en-us/windows/win32/controls/ttm-getmaxtipwidth) message after sending TTM_SETMAXTIPWIDTH. Returns an INT value that represents the maximum tooltip width, in pixels. If no maximum width was set previously, the message returns -1. – Rita Han Jul 10 '19 at 01:22
  • @RitaHan-MSFT TTM_GETMAXTIPWIDTH message returns exactly same length sent by TTM_SETMAXTIPWIDTH message – Bassam Najeeb Jul 10 '19 at 07:19

3 Answers3

0

I can't reproduce your issue with win32 application.

With SendMessage(hwndTT, TTM_SETMAXTIPWIDTH, 0, 150); I get Multiline Tooltips like this:

enter image description here

Without SendMessage(hwndTT, TTM_SETMAXTIPWIDTH, 0, 150); I get single line Tooltips like this:

enter image description here

The code I use(c++) as below based on official document:

void CreateToolTipForRect(HWND hwndParent)
{
    // 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,
        hwndParent, NULL, hInst, NULL);

    SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0,
        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

    // Set up "tool" information. In this case, the "tool" is the entire parent window.

    TOOLINFO ti = { 0 };
    ti.cbSize = sizeof(TOOLINFO);
    ti.uFlags = TTF_SUBCLASS;
    ti.hwnd = hwndParent;
    ti.hinst = hInst;
    ti.lpszText = (LPSTR)"this string length is more than 80 !!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-80-!!!!!!!!!!!!!!!";

    GetClientRect(hwndParent, &ti.rect);

    SendMessage(hwndTT, TTM_SETMAXTIPWIDTH, 0, 150);

    // Associate the tooltip with the "tool" window.
    SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
}
Rita Han
  • 9,574
  • 1
  • 11
  • 24
  • thanks @Rita, I write same code but now my application making a crash at _tWinMain, and no call stack else an error at ntdll.dll "External code" any advice to solve it? – Bassam Najeeb Jul 13 '19 at 08:07
  • another info I'm using ti.lpszText = LPSTR_TEXTCALLBACK to handle an TTN_NEEDTEXT message as ON_NOTIFY(TTN_NEEDTEXT, 0, HandleTooltipText). afx_msg void HandleTooltipText(NMHDR* nmhdr, LRESULT*) – Bassam Najeeb Jul 13 '19 at 08:52
  • @BassamNajeeb Have you tried using a win32 windows application([Walkthrough: Create a traditional Windows Desktop application (C++)](https://learn.microsoft.com/en-us/cpp/windows/walkthrough-creating-windows-desktop-applications-cpp?view=vs-2019)) instead of MFC? If yes, please show a mini, complete and reproducible sample. – Rita Han Jul 15 '19 at 08:21
0

First create a tooltip as following:

HWND CreateToolTip(HWND hwndParent)
{
   // 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,
    hwndParent, NULL, hInst, NULL);

    SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0,
     SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

    //Set up "tool" information. In this case, the "tool" is the entire parent window

  TOOLINFO ti = { 0 };
  ti.cbSize = sizeof(TOOLINFO);
  ti.uFlags = TTF_SUBCLASS;
  ti.hwnd = hwndParent;
  ti.hinst = hInst;
  ti.lpszText = LPSTR_TEXTCALLBACK; // this to use tooltip notify message

  GetClientRect(hwndParent, &ti.rect);

  SendMessage(hwndTT, TTM_SETMAXTIPWIDTH, 0, 500);

   // Associate the tooltip with the "tool" window.
  SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
}

Note: using a LPSTR_TEXTCALLBACK means you must define a TTN_NEEDTEXT message handler

ON_NOTIFY(TTN_NEEDTEXT, 0, HandleTooltipText)

Finally we define a TTN_NEEDTEXT message handler as:

void HandleTooltipText(NMHDR* nmhdr, LRESULT*)
{
    NMTTDISPINFO* toolTip = (NMTTDISPINFO*)nmhdr;
    CString prices = GetPrices();
    if (toolTip->hdr.code == TTN_GETDISPINFO)
    {
       toolTip->lpszText = new TCHAR[prices.GetLength() + 1];
       memset(toolTip->lpszText, 0, (prices.GetLength() + 1) * sizeof(TCHAR));
       _tcscpy_s(toolTip->lpszText, prices.GetLength() + 1, prices.GetString());
       toolTip->hinst = 0;
    }
}
Bassam Najeeb
  • 607
  • 2
  • 7
  • 16
0

Set the max width for the MFC shared tooltip ctrl.

static CToolTipCtrl* pToolTip = NULL;
CToolTipCtrl* pTT = AfxGetModuleThreadState()->m_pToolTip;

// MFC shared tooltip sometimes loses its maxtipwidth eventhough
// its object has not changed
if (/*pTT != pToolTip 
        && */pTT != NULL) {
    pToolTip = pTT;
    pToolTip->SetMaxTipWidth(SHRT_MAX);
    pToolTip->SetDelayTime(TTDT_AUTOPOP, SHRT_MAX);
}
Farid Z
  • 960
  • 1
  • 9
  • 18