I've got the C++ code snipped below from a comment in https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx
And I used it (and variations on it) successfully.
The user who wrote it claims it was inspired by a ms recommendation on a Windows Vista best practices guide, to forward the mouse wheel event to whatever window is hovered by the mouse cursor. The virtue of his/her implementation is that it's completely unintrusive, you just drop it and it set the hooks, referencing your main thread. It avoids forwarding the event to windows belonging to other processes, but perhaps that could actually be a good thing.
namespace {
LRESULT CALLBACK mouseInputHook(int nCode, WPARAM wParam, LPARAM lParam) {
//"if nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function
//without further processing and should return the value returned by CallNextHookEx"
if (nCode >= 0) {
MSG& msgInfo = *reinterpret_cast<MSG*>(lParam);
if (msgInfo.message == WM_MOUSEWHEEL ||
msgInfo.message == WM_MOUSEHWHEEL) {
POINT pt = {};
pt.x = ((int)(short)LOWORD(msgInfo.lParam)); //yes, there's also msgInfo.pt, but let's not take chances
pt.y = ((int)(short)HIWORD(msgInfo.lParam)); //
//visible child window directly under cursor; attention: not necessarily from our process!
//http://blogs.msdn.com/b/oldnewthing/archive/2010/12/30/10110077.aspx
if (HWND hWin = ::WindowFromPoint(pt))
if (msgInfo.hwnd != hWin && ::GetCapture() == nullptr) {
DWORD winProcessId = 0;
::GetWindowThreadProcessId(//no-fail!
hWin, //_In_ HWND hWnd,
&winProcessId); //_Out_opt_ LPDWORD lpdwProcessId
if (winProcessId == ::GetCurrentProcessId()) //no-fail!
msgInfo.hwnd = hWin; //it would be a bug to set handle from another process here
}
}
}
return ::CallNextHookEx(nullptr, nCode, wParam, lParam);
}
struct Dummy {
Dummy() {
hHook = ::SetWindowsHookEx(WH_GETMESSAGE, //__in int idHook,
mouseInputHook, //__in HOOKPROC lpfn,
nullptr, //__in HINSTANCE hMod,
::GetCurrentThreadId()); //__in DWORD dwThreadId
assert(hHook);
}
~Dummy() {
if (hHook)
::UnhookWindowsHookEx(hHook);
}
private:
HHOOK hHook;
} dummy;
}