0

I have a quick question. I created a standard window with the window api from the MSDN creating a window site. What I want the program to do is change the title of the window the mouse cursor is at when i press a key on the keyboard. To do so i've installed a low level mouse hook like so:

LRESULT CALLBACK LowLevelMouseProc(__in  int nCode, __in  WPARAM wParam, __in  LPARAM lParam) {
    MSLLHOOKSTRUCT* p = (MSLLHOOKSTRUCT*)lParam;
    HWND hiWnd = WindowFromPoint(p->pt); //Get a handle to the top-most window
    ScreenToClient(hiWnd, &p->pt); //Converts the cursor position from screen to the specified window
    char buf[33];

    switch (wParam) {

    case WM_MOUSEMOVE:
        snprintf(buf, sizeof(buf) - 1, "X:%ld, Y:%ld", p->pt.x, p->pt.y); //Put the cursor coordinates into a char buffer
        SendMessage(hiWnd, WM_SETTEXT, 0, (LPARAM)buf); //Send a message to the other window to change the title
        break;
    }
    return CallNextHookEx(0, nCode, wParam, lParam);
}

Upon calling the mouse hook, Only my program changes text. Also, the text is a bunch of Chinese Characters, And not one or two, but a bunch like so:

藡覶 跾 瑍痸碚 齫儽戃 羭聧蔩, 圪妀 跾 鶀嚵巆 堔埧娾 爂犤繵 摿斠榱 軥軱逴 潫 徖梜, 薍薝 

Do I have to mess around with the foreground window and instead get the background window? Or window where current mouse pos is at? I would assume that

ScreenToClient(hiWnd, &p->pt)

Thanks for the help guys!

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Omar Martinez
  • 37
  • 1
  • 6
  • Chinese text strongly suggests you are accidentally passing an ANSI string to a Unicode function. We already see that you are passing an ANSI string in `buf`, so half of the theory is confirmed. The other half is determining whether you are using the Unicode version of `SendMessage`. – Raymond Chen Aug 21 '15 at 05:11

1 Answers1

0

What I want the program to do is change the title of the window the mouse cursor is at when i press a key on the keyboard

Then why are you using a mouse hook instead of a keyboard hook? In a keyboard hook, you can use GetCursorPos() to get the current mouse screen position.

As for your actual problem, you are not checking to make sure WindowFromPoint() is even finding a window at all, you are not passing a properly-aligned memory pointer to WM_SETTEXT, and you are not taking into account whether the destination window is Ansi or Unicode.

Try something more like this instead:

Keyboard hook:

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if ((nCode == HC_ACTION) && (wParam == WM_KEYUP))
    {
        KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
        if (p->vkCode == ...) // whatever key you are looking for
        {
            POINT pt;
            GetCursorPos(&pt);

            HWND hiWnd = WindowFromPoint(pt);
            if (hiWnd)
            {
                ScreenToClient(hiWnd, &pt);

                if (IsWindowUnicode(hiWnd))
                {
                    LPWSTR buf = (LPWSTR) GlobalAlloc(GMEM_FIXED, 33 * sizeof(WCHAR));
                    if (buf)
                    {
                        snwprintf(buf, 33, L"X:%ld, Y:%ld", pt.x, pt.y);
                        SendMessageW(hiWnd, WM_SETTEXT, 0, (LPARAM)buf);
                        GlobalFree(buf);
                    }
                }
                else
                {
                    LPSTR buf = (LPSTR) GlobalAlloc(GMEM_FIXED, 33);
                    if (buf)
                    {
                        snprintf(buf, 33, "X:%ld, Y:%ld", pt.x, pt.y);
                        SendMessageA(hiWnd, WM_SETTEXT, 0, (LPARAM)buf);
                        GlobalFree(buf);
                    }
                }
            }
        }
    }

    return CallNextHookEx(0, nCode, wParam, lParam);
}

Mouse hook:

LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if ((nCode == HC_ACTION) && (wParam == WM_MOUSEMOVE))
    {
        MSLLHOOKSTRUCT* p = (MSLLHOOKSTRUCT*)lParam;

        HWND hiWnd = WindowFromPoint(p->pt);
        if (hiWnd)
        {
            POINT pt = p->pt;
            ScreenToClient(hiWnd, &pt);

            if (IsWindowUnicode(hiWnd))
            {
                LPWSTR buf = (LPWSTR) GlobalAlloc(GMEM_FIXED, 33 * sizeof(WCHAR));
                if (buf)
                {
                    snwprintf(buf, 33, L"X:%ld, Y:%ld", pt.x, pt.y);
                    SendMessageW(hiWnd, WM_SETTEXT, 0, (LPARAM)buf);
                    GlobalFree(buf);
                }
            }
            else
            {
                LPSTR buf = (LPSTR) GlobalAlloc(GMEM_FIXED, 33);
                if (buf)
                {
                    snprintf(buf, 33, "X:%ld, Y:%ld", pt.x, pt.y);
                    SendMessageA(hiWnd, WM_SETTEXT, 0, (LPARAM)buf);
                    GlobalFree(buf);
                }
            }
        }
    }

    return CallNextHookEx(0, nCode, wParam, lParam);
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Wouldn't i need a low level mouse for cursor position outside the main window, and mouse clicks? – Omar Martinez Aug 21 '15 at 04:00
  • As I said and showed, you can use `GetCursorPos()` to get the mouse position. But if you want to react to mouse clicks (which you did not mention earlier), then you can use a mouse hook. Though you should consider using the [Raw Input](https://msdn.microsoft.com/en-us/library/windows/desktop/ms645536.aspx) API instead of low level hooks. The LowLevelKeyboardProc and LowLevelMouseProc documentations even say as much: "*In most cases where the application needs to use low level hooks, it should monitor raw input instead.*" – Remy Lebeau Aug 21 '15 at 06:13
  • I don't think you need to call `GlobalAlloc` to allocate buffers. Since `WM_SETTEXT` is a standard Windows message, the system automatically marshals pointer arguments across process boundaries. – IInspectable Aug 21 '15 at 13:46
  • @IInspectable: Yes, `WM_SETTEXT` auto-marshals across processes, but it is also known to fail if the pointer is not aligned correctly. There is a comment posted about that on the [`WM_SETTEXT` documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632644.aspx): "**Severe 64 Bit Windows Bug** - *If the String pointer passed to WM_SETTEXT or to SetWindowText() is not at an even address in memory the funtion/message will not set the WindowText and return TRUE... I observed this only on Windows 7 - 64 Bit version no matter if the application was compiled as 32 Bit or 64 Bit.*" – Remy Lebeau Aug 21 '15 at 17:47
  • @IInspectable: Letting the OS allocate the memory buffer is one way to ensure correct alignment. You can probably use `LocalAlloc()` or maybe even `new`, but I wouldn't rely on using a stack buffer if this issue is real. – Remy Lebeau Aug 21 '15 at 17:48
  • @RemyLebeau: I wasn't aware of this particular limitation. I don't see anything wrong with relying on the compiler to do the right thing, though. It doesn't matter, whether an array is dynamically allocated, or uses automatic storage duration. The compiler will properly align the memory. If you wind up with a pointer, that isn't properly aligned, you have undefined behavior anyway. The guy complaining in the Community Additions is apparently unaware of **his** bug, caused by constructing an unaligned pointer. – IInspectable Aug 21 '15 at 18:15
  • @IInspectable: he constructed an ill-aligned pointer on purpose for demonstration purposes, but also stated that "If you use structs that are BYTE aligned and contain strings you may easily run into this problem". That is not the case in this situation, but it is a real-world possibility nontheless. – Remy Lebeau Aug 21 '15 at 18:22
  • @RemyLebeau: That doesn't change the core issue: You are starting out with an unaligned pointer. Whether the pointer is ill-aligned on purpose, or (more subtly) ill-aligned due to **erroneous** structure packing is not relevant here. It's undefined behavior either way. – IInspectable Aug 21 '15 at 18:28