First off, what I wanted to accomplish: intercepting (via a low level mouse hook) WM_MOUSEHWHEEL
messages to go back and forward in Windows' file explorer history, or at least to the parent window if access to the history weren't possible.
That was what started it all, not that I had any idea if it'd be possible or not, specially with a touchpad, but that was my intention. So I started looking at the more usual WM_MOUSEWHEEL
(vertical scrolling), only to find out that those messages aren't being generated much of the time!
As per the MSDN docs on WM_MOUSEWHEEL
:
Sent to the focus window when the mouse wheel is rotated. The DefWindowProc function propagates the message to the window's parent. There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until it finds a window that processes it.
Okay, looks good, so when the mouse wheel is rotated that message is sent to the window that has the focus. Let's see if that's the case with the help of Spy++ from the Visual Studio pack of utilities, made a recording of it and uploaded it to YouTube, embedding doesn't seem to be allowed in this Stack Exchange: https://youtu.be/YJvjw_BPJf0
Summing it up though, there's no WM_MOUSEWHEEL
being generated for all of the programs tested. Explorer was the first one I tried to look at, focusing on the different sub-windows a window had and made sure it was scrollable.
I could see some related messages being received by the scrollbar section of it, but that's it, no sign of that message anywhere (however, VM_VSCROLL
was posted to one of the windows of the scrollbar).
Next up was Notepad3, nada, its SysListView32
doesn't see anything and the parent window gets some notification, activation messages and the like but nothing scrolling related.
Everything's SysListView32
received some LVS_SCROLL
messages but it didn't act on them (its message loop is probably looking for the darn WM_MOUSEWHEEL
s instead).
Finally a browser, nothing at all, the "view" didn't register anything at all while the parent window captured the mouse by the look of the events.
NOTE: For those of you who see the video, note that while Spy++ was on top it didn't have focus during all tests, it was merely pinned so I could see the messages.
I almost gave up, starting from the default example Win32 application they give you in Visual Studio I added a hook procedure and if that message was received it'd print a message box, just in case it was the shell the one getting the messages somehow.
There was my surprise when I ran the code directly in VS that I see message boxes when I scroll through the code. WTF?!
Fire Spy++ again (also 64-bit because it was the 2022 Preview I was running) and let's see, there they are!
The code editor sub-window is receiving those messages whenever I scroll vertically with the trackpad using two fingers. So, what is going on?
I mean, I even tried to run that sample code elevated to be at a higher integrity level and see if that'd make those messages appear, but to no avail.
The code is as simple as it gets, most of it was autogenerated as a sample Win32 application, but the hook and procedure are as follows:
// The callback procedure:
LRESULT CALLBACK mouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == 0) {
if (wParam == WM_MOUSEWHEEL)
MessageBox(NULL, L"We got it!", L"Yay!", MB_OK);
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
...
// Setting the mouse hook (at the application's entry point):
HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc, hInstance, 0);
if (!mouseHook) {
LPWSTR errorMessage = NULL;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, (LPWSTR)&errorMessage, 0, NULL) == 0) {
MessageBox(NULL, L"Couldn't format the error message...", L"Error", MB_OK | MB_ICONERROR);
}
MessageBox(NULL, errorMessage, L"Damn", MB_OK | MB_ICONERROR);
LocalFree(errorMessage);
return FALSE;
}
Although I tagged it as C, it really applies to any language that runs in Windows and can access low level mouse events, be it managed or not.
PS. By the way, although the intention I mentioned at the beginning was the motivation that started it all, I reckon it's impossible to do. If vertical scroll messages aren't always generated even in scrollable controls, I don't see horizontal ones being generated when there's nothing to scroll. It'd need to be implemented in the File Explorer itself most likely.