1

I have a problem when I try hooking mouse events. It works if I click outside of my application window. But when I click inside my app window, it doesn't detect the WM_LBUTTONUP event. For few seconds mouse movement is very slow. And from this time it doesn't detect any events. Even if I click outside of my app window.

So my app runs indefinitely. I wonder if this is something related to threads or something. Maybe if I want to track something globally, in all threads in my computer (for example tracking mouse movement) then I can do nothing in my app thread? But this is very strange to me.

Here is code for mouse hooking. main.cpp

#include <windows.h>
#include <iostream>
#include "MyHook.h"

using namespace std;

int main()
{
    MyHook::Instance().InstallHook();
    return MyHook::Instance().Messsages();
}

MyHook.h

#pragma once
#include <Windows.h>

class MyHook
{
public:
    //single ton
    static MyHook& Instance()
    {
        static MyHook myHook;
        return myHook;
    }

    // function to install our mouseHook
    void InstallHook();

    // function to uninstall our mouseHook
    void UninstallHook();

    // function to "deal" with our messages
    int Messsages();

public:
    HHOOK mouseHook; // handle to the mouse hook
    HHOOK windowHook; // handle to the window hook
    MSG msg; // struct with information about all messages in our queue
};

LRESULT CALLBACK MyMouseCallback(int nCode, WPARAM wParam, LPARAM lParam);

MyHook.cpp

#include "MyHook.h"

#include <stdio.h>

void MyHook::InstallHook()
{
    /*
    SetWindowHookEx(
    WM_MOUSE_LL = mouse low level mouseHook type,
    MyMouseCallback = our callback function that will deal with system messages about mouse
    NULL, 0);

    c++ note: we can check the return SetWindowsHookEx like this because:
    If it return NULL, a NULL value is 0 and 0 is false.
    */
    if (!(mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MyMouseCallback, NULL, 0)))
    {
        printf_s("Error: %x \n", GetLastError());
    }
}

// function to uninstall our mouseHook
void MyHook::UninstallHook()
{
    UnhookWindowsHookEx(mouseHook);
}

MSG msg; // struct with information about all messages in our queue

// function to "deal" with our messages
int MyHook::Messsages()
{
    // while we do not close our application
    while (msg.message != WM_QUIT)
    {
        if (GetMessage(&msg, NULL, 0, 0/*, PM_REMOVE*/))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        Sleep(1);
    }
    UninstallHook(); // if we close, let's uninstall our mouseHook
    return (int)msg.wParam; // return the messages
}

LRESULT CALLBACK MyMouseCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam; // WH_MOUSE_LL struct
    /*
    nCode, this parameters will determine how to process a message
    This callback in this case only have information when it is 0 (HC_ACTION): wParam and lParam contain info

    wParam is about WINDOWS MESSAGE, in this case MOUSE messages.
    lParam is information contained in the structure MSLLHOOKSTRUCT
    */

    // we have information in wParam/lParam ? If yes, let's check it:
    if (nCode == 0)
    { 
        // Mouse struct contain information?    
        // if (pMouseStruct != NULL)
        // {
        //  printf_s("Mouse Coordinates: x = %i | y = %i \n", pMouseStruct->pt.x, pMouseStruct->pt.y);
        // }

        switch (wParam)
        {
            case WM_LBUTTONDOWN:
            {
                printf_s("LEFT CLICK DOWN\n");
            }
            break;
            case WM_LBUTTONUP:
            {
                printf_s("LEFT CLICK UP\n");
            }
            break;


        }

    }

    /*
    Every time that the nCode is less than 0 we need to CallNextHookEx:
    -> Pass to the next mouseHook
         MSDN: Calling CallNextHookEx is optional, but it is highly recommended;
         otherwise, other applications that have installed hooks will not receive mouseHook notifications and may behave incorrectly as a result.
    */
    return CallNextHookEx(MyHook::Instance().mouseHook, nCode, wParam, lParam);
}
  • "*But my app freezes every time*" - StackOverflow is not a debugging service. Did you try stepping through the code with a debugger to see exactly where the freeze is actually happening? – Remy Lebeau Feb 21 '20 at 22:49
  • Yes, I use a debugger when I have problems. But in this situation, I don't know how it could be useful. I have almost no variables. I have only one implicit loop. For all active windows I display coordinates and I try to change the position of the window with SetWindowPos(). I know that displaying coordinates isn't a problem. So there is something with SetWindowPos(). –  Feb 21 '20 at 23:02
  • "*I don't know how it could be useful*" - it would allow you to find the *exact* line of code that is actually freezing. You *think* it is the `SetWindowPos()`, but did you *verify* that? Maybe it is the `std::cin.ignore()` instead? Who knows. Don't make assumptions. Oh, and BTW, your `enumWindowCallback()` is not doing adequate error handling, and is leaking memory. – Remy Lebeau Feb 21 '20 at 23:09
  • I used the debugger a moment ago and yes, the problem is with SetWindowPos(). But I don't know why. I fixed the code and now I release memory. But it still not work. –  Feb 21 '20 at 23:18
  • If I had to guess, you are trying to move an `HWND` that belongs to your process, but you have no message loop to process window interactions with. Try having your callback function use `GetWindowThreadProcessId()` to ignore any `HWND`s whose process ID matches `GetCurrentProcessId()`. – Remy Lebeau Feb 21 '20 at 23:35
  • I managed to fix the problem with the windows. Freeing memory, deleting cin.ignore() and using this function https://stackoverflow.com/questions/7277366/why-does-enumwindows-return-more-windows-than-i-expected to check if window IsAltTabWindow() helped me. But I still have a problem with the mouse. I will try to apply your suggestion to my mouse hooking issues. –  Feb 21 '20 at 23:42
  • 1
    Please do not morph the question. The original question was about enumerating windows and repositioning them. The new question is about mouse hooks. The comments related to the old question make no sense any more. If you have a new question, ask a new question. – Raymond Chen Feb 23 '20 at 17:44

1 Answers1

0

I didn't run your code, so I'm not sure, but I have an idea.

printf_s does console output. Clicking on your console window does this fancy stuff with selecting/copying your output and blocks functions like printf_s, to avoid selection from running away. As your hooking function is blocked, mouse is blocked. Later on Windows may be able to remove your hook for this behavior of running hook procedure for too long.

Log to a file instead, or post your log to a queue and print from that queue.

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79