Why would Windows hooks not receive certain messages? - windows

Microsoft does not recommend DirectInput for keyboard and mouse input. As such, I've written an input manager class that uses SetWindowsHookEx to hook into WndProc and GetMsg. I believe the hooks are set appropriately, though they look to be the cause of various issues.
Neither my WndProc nor GetMsg hooks receive any of the messages that the actual WndProc is receiving. My input manager never receives the WM_INPUT, WM_BUTTON, WM_MOUSEWHEEL, and WM_KEY* messages that it needs.
What gives?
Partial header:
namespace InputManager
{
class CInputManager
{
HWND m_Window;
HHOOK m_WndProcHook;
HHOOK m_GetMessageHook;
static LRESULT CALLBACK WindowsProcedureHookProcedure(int Code, WPARAM WParameter, LPARAM LParameter);
static LRESULT CALLBACK GetMessageHookProcedure(int Code, WPARAM WParameter, LPARAM LParameter);
static LRESULT CALLBACK MessageHandler(HWND Window, UINT Message, WPARAM wParameter, LPARAM lParameter);
};
}
Partial source:
namespace InputManager
{
bool CInputManager::Initialize(HWND Window)
{
m_Window = Window;
// Hook into the sent messages of the target window to intercept input messages.
m_WndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, &(WindowsProcedureHookProcedure), NULL, GetCurrentThreadId());
// Hook into the posted messages of the target window to intercept input messages.
m_GetMessageHook = SetWindowsHookEx(WH_GETMESSAGE, &(GetMessageHookProcedure), NULL, GetCurrentThreadId());
// Register mouse device for raw input.
RAWINPUTDEVICE RawInputDevice;
RawInputDevice.usUsagePage = HID_USAGE_PAGE_GENERIC;
RawInputDevice.usUsage = HID_USAGE_GENERIC_MOUSE;
RawInputDevice.dwFlags = RIDEV_INPUTSINK;
RawInputDevice.hwndTarget = m_Window;
return RegisterRawInputDevices(&(RawInputDevice), 1, sizeof(RawInputDevice));
}
void CInputManager::Shutdown()
{
// Unhook from the posted messages of the target window.
UnhookWindowsHookEx(m_GetMessageHook);
// Unhook from the sent messages of the target window.
UnhookWindowsHookEx(m_WndProcHook);
}
LRESULT CALLBACK CInputManager::WindowsProcedureHookProcedure(int nCode, WPARAM wParameter, LPARAM lParameter)
{
if(nCode == HC_ACTION)
{
// Forward to message handler.
CWPSTRUCT* Message = reinterpret_cast<CWPSTRUCT*>(lParameter);
MessageHandler(Message->hwnd, Message->message, Message->wParam, Message->lParam);
}
return CallNextHookEx(NULL, nCode, wParameter, lParameter);
}
LRESULT CALLBACK CInputManager::GetMessageHookProcedure(int nCode, WPARAM wParameter, LPARAM lParameter)
{
if(nCode == HC_ACTION)
{
// Forward to message handler.
CWPSTRUCT* Message = reinterpret_cast<CWPSTRUCT*>(lParameter);
MessageHandler(Message->hwnd, Message->message, Message->wParam, Message->lParam);
}
return CallNextHookEx(NULL, nCode, wParameter, lParameter);
}
}
I don't include the code for the message handler as it consists of 149 lines, most of which are the switches for the message types. The message values received in the WndProc are not the same as the ones in my callbacks.

I can't seem to add a comment under your original question which is where I would prefer to put this but:
From what it looks like you are trying to do, wouldn't a WH_KEYBOARD and WH_MOUSE hook be more appropriate?

I'm quite late to the party here, but I just spent so many hours figuring out the same problem, and hopefully someone else will find this useful.
My empirical conclusion is that DispatchMessage does not trigger WH_CALLWNDPROC hooks. In other words, messages that are posted in the thread's message queue and go through the message loop (GetMessage -> DispatchMessage) will not be caught by WH_CALLWNDPROC. It only catches messages sent directly to the window procedure with SendMessage etc.. And when you look at the documentation, that's kinda what it says:
An application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function before calling the window procedure to process a message sent to the thread.
And of course the opposite is true for WH_GETMESSAGE hook. It will catch posted messages but not sent messages. To get all messages you either have to use both hooks, or use subclassing to hook the window procedure directly:
WNDPROC realProc;
LRESULT CALLBACK hookProc(HWND h, UINT msg, WPARAM wp, LPARAM lp)
{
return CallWindowProc(realProc, h, msg, wp, lp);
}
...
realProc = (WNDPROC)SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)hookProc);
Also, the reason the OP's GetMessage hook wasn't working is probably because lParameter should be casted to MSG* and not CWPSTRUCT*.

I once had a similar problem. Im not quite shure what it was (i think it was consumed somewhere in PreTranslateMessage but i'm not shure) but i know how i spotted it:
I created one of those vanishing messages myself and debugged its way thru MFC. If i remeber correctly, i just returned somewhere the wrong BOOLEAN. However, this approach might give you the actual clue.

Related

SetWindowsHookEx for WH_KEYBOARD_LL handler PostThreadMessage message not received?

I setup a handler to catch keystrokes for a short time while using a private message loop for the window. And while it works, if I try the PostThreadMessage the window never receives the message?
The callback looked like (I tried other messages to, this one sample was with a private message):
LRESULT CALLBACK LLKeyboardHookProc(int ncode, WPARAM wp, LPARAM lp)
{
if (ncode == HC_ACTION) {
if (wp==WM_KEYDOWN) {
KBDLLHOOKSTRUCT *kbs=reinterpret_cast<KBDLLHOOKSTRUCT*>(lp);
if (kbs->vkCode==VK_ESCAPE) {
PostThreadMessage (GetCurrentThreadId(), UWM_MYCLOSEMESSAGE, 0, 0);
}
}
}
return CallNextHookEx(0, ncode, wp, lp);
}
HHOOK kbhook = SetWindowsHookEx(WH_KEYBOARD_LL, LLKeyboardHookProc, GetModuleHandle(NULL), 0);
The message loop for the WS_EX_LAYERED window looks like:
while (IsWindow(hwnd)) {
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
// let MFC do its idle processing
LONG lIdle=0;
while (AfxGetApp()->OnIdle(lIdle++));
WaitMessage();
}
// clean up
UnhookWindowsHookEx(kbhook);
I changed it to use a volatile variable for now to close the window but I'd really like to send it a message. Using a global HWND wouldn't be thread-safe without locks so didn't want to go that way.
P.S. I did check the PostThreadMessage result and it was not FALSE (no debug messages when I added them) so it seemed to post it somewhere.
PostThreadMessage() posts a thread message to the queue, not a window message. Your message loop is ignoring thread messages, only dispatching window messages. A window will NEVER see a thread message, so you need to handle such messages directly in your message loop instead, eg:
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.hwnd == NULL && msg.message == UWM_MYCLOSEMESSAGE) { // <-- add this
// do something...
}
else {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
However, as Hans Passant stated in a comment:
Never use PostThreadMessage() when you also created a window, something as simple as resizing the window causes the message to get lost.
Raymond Chen has posted several blog articles on this subject:
Thread messages are eaten by modal loops
Watching thread messages disappear
Rescuing thread messages from modal loops via message filters
Why do messages posted by PostThreadMessage disappear?
You could try using a WH_MSGFILTER hook, like Raymond demonstrated. But the best way to solve this is to simply not post a thread message at all, post a window message instead. Have your keyboard hook use PostMessage() (or even SendMessage()) to an HWND that your app owns, and then you can handle the message in that window's message procedure.

SetWindowsHookEx(WH_JOURNALRECORD, ..) sometimes hang the system

I'm trying upgrade an old application to work on Windows 7 and I'm having problems with the "Macro recording" functionality, which is using Journal Hooks. I have followed every step necessary to make this work on Windows 7, that is, setting the uiAccess=true, signing the exe and running it from the Program Files directory.
It usually works, but sometimes, for no apparent reason, it seems like the SetWindowsHookEx function is waiting for something and hang the whole system in a weird way : no input is send to any application. The only way I can get out of this hang is by doing ctrl-alt-del, which force uninstall the hook.
I've replicated the problem with a simple application. Using the default generated Win32 template of Visual Studio, I've modified the About dialog callback to register and unregister the hook :
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
{
// added this
recordHook = ::SetWindowsHookEx(WH_JOURNALRECORD, JournalRecordCallback, hInst, 0);
return (INT_PTR)TRUE;
}
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
// and this
UnhookWindowsHookEx(recordHook);
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
My hook callback function is simply
LRESULT CALLBACK JournalRecordCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
And, as with the larger application, sometimes, the SetWindowsHookEx call hang.
Does anybody has experienced this? I thought that maybe installing the hook inside the MessageLoop was causing the hang and I tried to move it to another thread but still got the hang.
Am I doing something wrong?
Thanks
JournalRecordProc callback function:
An application that has installed a JournalRecordProc hook procedure should watch for the VK_CANCEL virtual key code (which is implemented as the CTRL+BREAK key combination on most keyboards). This virtual key code should be interpreted by the application as a signal that the user wishes to stop journal recording. The application should respond by ending the recording sequence and removing the JournalRecordProc hook procedure. Removal is important. It prevents a journaling application from locking up the system by hanging inside a hook procedure.

How to handle wm_print message in a CWnd (using MFC)?

Is there a way to handle wm_print message in a CWnd (using MFC) ?. I'm trying to intercept this message and prevent printing of a child control. Adding ON_WM_PRINT() to my message map throws compilation errors.
MFC only defines ON_WM_XXXX() macros for the commonest messages, but there is also a general ON_MESSAGE() macro to allow you to handle other cases. Add
ON_MESSAGE(WM_PRINT, OnPrint)
to your message map, and then declare and implement a member function
afx_msg LRESULT OnPrint(WPARAM, LPARAM);
The device context is passed in the WPARAM, so you need something like this in your implementation:
LRESULT MyWindowClass::OnPrint(WPARAM wp, LPARAM)
{
CDC* dc = CDC::FromHandle((HDC)wp);
// Do custom logic here ...
// Only call Default() if you want the default processing for this message too ...
return Default();
}

How to respond to a PropertySheet's OK or Apply button after the pages have processed it?

The PropertySheet API lets you define a PropSheetProc that can (on Windows XP and above) receive messages when the OK or Apply button is pressed. This lets you do processing when one of these buttons is clicked.
However, this handler is called before the individual property pages receive the PSN_APPLY notification through their respective dialog procedures. I want to do my processing after these notifications have been processed, preferably without ugly hacks. How do I do this?
Background: I'm storing my configuration in a single struct, and the individual pages each modify parts of this struct when they are applied. Then, after these values have been written, I want to apply the settings from the struct all at once, instead of re-applying all of them from each property page.
I ended up using the PropSheetProc callback to capture the property sheet's window handle, then hook up a subclass window procedure, like this:
// This is not officially defined, but the whole world uses it.
#define ID_APPLY_NOW 0x3021
WNDPROC origWinProc;
LRESULT CALLBACK MyWinProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
// Call the original window procedure.
LRESULT retVal = CallWindowProc(origWinProc, hwndDlg, msg, wParam, lParam);
// Now, and only now, do our own stuff.
switch (msg) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
case ID_APPLY_NOW:
applyConfig();
saveConfig();
break;
}
break;
}
// Return the original winproc's result.
return retVal;
}
int CALLBACK myPropSheetProc(HWND hwndDlg, UINT msg, LPARAM lParam) {
switch (msg) {
case PSCB_INITIALIZED:
// Override the property sheet's window procedure with our own.
origWinProc = (WNDPROC)SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)&MyWinProc);
break;
}
return 0;
}
(Yes, I use switch statements even if there is only one case to consider. I'm strange like that.)
couldn't you just intercept the WM_COMMAND's BL_CLICKED message for ids IDOK, IDAPPLY and IDCANCEL?
Are you using MFC? or ATL?
Though I can't think of a time I wouldn't be able to intercept the BM_CLICKED...
Edit: Hmm never used property pages through that function... Just had a read through it. Have you set the pfnCallback function and the PSH_USECALLBACK flag set?
Each page also has a dialog proc. Can you not intercept the ok, cancel and apply from there as well? I think the other plan seems to fit more, though.
You don't NEED to apply the struct from inside any of the dialog handlers. So, if its a modal Property Sheet, you could do something simple like:
// Display the property sheet.
PropertySheet(&theSheet);
// The peroperty sheets PSN_APPLY notification sets this bool to true in the struct.
if(theStruct.fApply)
ApplyTheStruct(&theStruct);
Alternatively, I don't understand why, given that the 'struct' is just collecting the information entered on the pages, you dont change the struct as the user interacts with the page. Ignore the per-page PSN_APPLY messages and apply the struct when PropSheetProc is called. OR discard it totally if the notification is PSN_CANCEL.

MFC - execute code right after dialog is shown (.NET equivalent of Form.Shown)

I'm doing some small changes to C++ MFC project. I'm .NET developer so Windows programming is new to me.
I need to launch some method right after CDialog is completely shown (painted) for the first time, but only once.
How can I do this? In .NET I would handle Form.Shown event.
Do I need to handle some message? Which?
Do I need to override some CDialog method?
Or is there no easy way? I'm thinking of handling WM_ACTIVATE and then using a flag to ensure I call another method only once.
Found the answer here: Waiting until the dialog box is displayed before doing something
Short story:
INT_PTR CALLBACK
DlgProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg) {
case WM_INITDIALOG:
return TRUE;
case WM_WINDOWPOSCHANGED:
if ((((WINDOWPOS*)lParam)->flags & SWP_SHOWWINDOW) &&
!g_fShown) {
g_fShown = TRUE;
PostMessage(hwnd, WM_APP, 0, 0);
}
break;
case WM_APP:
MessageBox(hwnd,
IsWindowVisible(hwnd) ? TEXT("Visible")
: TEXT("Not Visible"),
TEXT("Title"), MB_OK);
break;
case WM_CLOSE:
EndDialog(hwnd, 0);
break;
}
return FALSE;
}
If you're using MFC like I am you'll need to map WM_WINDOWPOSCHANGED and then use ON_MESSAGE to map WM_APP. See this CodeProject article for more details.
For reference you don't need to override DlgProc to intercept WM_WINDOWPOSCHANGED.
ON_WM_WINDOWPOSCHANGED()
ON_MESSAGE(MyCDialog::MY_USER_MSG, OnDialogShown)
void MyCDialog::OnWindowPosChanged(WINDOWPOS *wndpos)
{
__super::OnWindowPosChanged(wndpos);
if (!mDialogShown && (wndpos->flags & SWP_SHOWWINDOW)) {
PostMessage(MY_USER_MSG);
mDialogShown = true;
}
}
LRESULT MyCDialog::OnDialogShown(WPARAM, LPARAM)
{
...
}
You can implement the handling inline instead of posting another message if appropriate.
Another approach I've used a number of times with great success is to use a timer. Set it for 10m0s. It'll only fire after the dialog is shown.
Hell put the code in OnPaint() and thow a bool m_fullyInitilized in your class.
I like the timer too.. Though I usually go with 100ms. I also move all my initilization code out of the oninit, in these cases.. Just to protect against too much processing in there.

Resources