0

I've been trying for a couple of hours to interrogate tooltips to give up the text they contain to no avail. I've found How to get tooltip text for a given HWND? and tried that without success.

This shouldn't be that hard. I'm just not sure what I'm doing wrong. Here's a section of my code:

BOOL CALLBACK EnumWindowsProc(
    _In_  HWND hwnd,
    _In_  LPARAM lParam
    )
{
    TCHAR className[200];
    GetClassName(hwnd, className, _countof(className));
    ASSERT(IsWindow(hwnd));
    if (_tcscmp(className, _T("tooltips_class32")) == 0)
    {
        TOOLINFO ti = { 0 };
        ti.cbSize = sizeof(TOOLINFO);
        TCHAR text[500] = { 0 };
        ti.lpszText = text;
        ti.hwnd = GetParent(hwnd);
        IsWindow(ti.hwnd);
        ti.uId = GetDlgCtrlID(hwnd);
        int result = SendMessage(hwnd, TTM_GETTEXT, _countof(text), (LPARAM)&ti);
        CString info;
        info.Format(_T("%p: %s \"%s\"\r\n"), hwnd, className, ti.lpszText);
        CString& output = *(CString*)lParam;
        output += info;
    }
    return 1;
}

void CTooltipVerifyDlg::OnTimer(UINT_PTR nIDEvent)
{
    m_output = "";
    VERIFY(EnumWindows(EnumWindowsProc, (LPARAM)&m_output));

    SYSTEMTIME systemTime;
    GetLocalTime(&systemTime);
    CString text;
    text.Format(_T("%02u:%02u:%02u.%03u\r\n"), systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
    m_output = text + m_output;
    this->UpdateData(FALSE);
    CDialogEx::OnTimer(nIDEvent);
}

CTooltipVerifyDlg is a dialogue with a text box which I communicate to with m_output, a CString that is bound to the text box.

When the SendMessage call is done, something on my desktop (or even the desktop manager) crashes. Any ideas why it would be crashing and not giving me the text that I desire?

Community
  • 1
  • 1
Adrian
  • 10,246
  • 4
  • 44
  • 110
  • 1
    `TTM_GETTEXT` most likely doesn't work cross-process. – Jonathan Potter Jun 24 '14 at 20:41
  • @JonathanPotter, I didn't see reference to that. Also, I've tried TTM_GETTOOLINFO as per [this](https://forum.tuts4you.com/topic/29093-how-to-get-all-windows-handles-having-same-class-name/) message without success. – Adrian Jun 24 '14 at 20:47
  • `TTM_GETTOOLINFO` probably doesn't either. Only certain messages are marshalled automatically across the process boundary (e.g. `WM_GETTEXT`). Normally you would need to inject code into the target process to read data from it. – Jonathan Potter Jun 24 '14 at 21:00
  • 2
    Same problem, the LPARAM pointer you pass is only valid in your process. You can monkey with VirtualAllocEx and ReadProcessMemory, etc, but the standard answer is "don't do this yourself, use an UI Automation library". – Hans Passant Jun 24 '14 at 21:13
  • @JonathanPotter Do you have a reference that states that and shows how it could be done? – Adrian Jun 24 '14 at 21:18
  • @HansPassant, thanks. Worked when I used AHK. – Adrian Jun 24 '14 at 21:41
  • 1
    "[The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling.](http://msdn.microsoft.com/en-us/library/windows/desktop/ms644950(v=vs.85).aspx)." – Raymond Chen Jun 25 '14 at 00:08

0 Answers0