SetWindowsHookEx(WH_JOURNALRECORD, ..) sometimes hang the system - winapi

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.

Related

What value should a dialog procedure return on WM_NOTIFY if a particular notification is not processed?

My dialog procedure:
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
INT_PTR result = TRUE;
switch(iMessage)
{
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->idFrom)
{
case ID_xxx:
// process notify from control ID_xxx
break;
case ID_yyy:
// process notify from control ID_yyy
break;
default:
result = FALSE;
}
default:
result = FALSE;
}
return result;
}
In case the notification is from a control that I don't use, or suppose I am not interested in the LVN_ITEMCHANGED notification of a particular listcontrol, I would set result to FALSE, causing the default windows procedure to be called.
Do I always have to do this? Is it a problem if I don't?
In case of notification messages, whether you return TRUE or FALSE from the DlgProc normally doesn't matter. These messages are sent to notify the parent about something that happens in a child. The default window procedure of the parent does not know what to do in response to something that happens in a child, so even when you return FALSE from DlgProc it will do nothing.
Anyway I would return TRUE for notifications that I handled to make immediately clear for any reader of my code that I handled the message completely on my own and don't need any default processing.
So I would write DlgProc like this:
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage)
{
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->idFrom)
{
case ID_xxx:
// process notify from control ID_xxx
return TRUE;
case ID_yyy:
// process notify from control ID_yyy
return TRUE;
}
break;
}
// We are not interested in the message. Let dialog manager do any default processing.
return FALSE;
}
By getting rid of the result variable and returning early from the case branches, the code is simplified and becomes easier to read and maintain. When trying to figure out what a particular case branch does, I no longer have to trace in my mind the state of the result variable down to the final return statement. When I see a return statement in a case branch I can just skip over reading the remaining part of the code.
Per the WM_NOTIFY documentation:
The return value is ignored except for notification messages that specify otherwise.
So, return whatever value you want, except for specific notifications that actually define a return value.
For instance, the LVN_ITEMCHANGED documentation states:
No return value.
However, the DialogProc documentation states:
Return value
Type: INT_PTR
Typically, the dialog box procedure should return TRUE if it processed the message, and FALSE if it did not. If the dialog box procedure returns FALSE, the dialog manager performs the default dialog operation in response to the message.
If the dialog box procedure processes a message that requires a specific return value, the dialog box procedure should set the desired return value by calling SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult) immediately before returning TRUE. Note that you must call SetWindowLong immediately before returning TRUE; doing so earlier may result in the DWL_MSGRESULT value being overwritten by a nested dialog box message.
The following messages are exceptions to the general rules stated above. Consult the documentation for the specific message for details on the semantics of the return value.
WM_CHARTOITEM
WM_COMPAREITEM
WM_CTLCOLORBTN
WM_CTLCOLORDLG
WM_CTLCOLOREDIT
WM_CTLCOLORLISTBOX
WM_CTLCOLORSCROLLBAR
WM_CTLCOLORSTATIC
WM_INITDIALOG
WM_QUERYDRAGICON
WM_VKEYTOITEM
So, just return TRUE for any message that you don't want the default message handler to see, and use DWL_MSGRESULT for any message that requires a return value.

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();
}

Why would Windows hooks not receive certain messages?

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.

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