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.
Related
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.
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.
I use MessageBox function in Win32 console application.
Application does not not use MFC, not even event loop.
I need to make a wrapper, MessageBoxTimed(), that exits
(and dialog box disappears) after N seconds, if user did not press any button.
Is there more or less simple way to do this ?
This will not be trivial. Since the MessageBox() function itself is modal, you will likely need to start another thread that waits for the predefined number of seconds, and is interrupt-able if the message box is dismissed manually.
If the timer expires, use the FindWindow() API to find the handle of the message box and then simulate a click of the OK button, or perhaps more appropriately a keypress of the ESC button.
EDIT: Actually, not too bad. This isn't fully tested, may need some additional cleanup, but is enough to get you started.
#include <Windows.h>
class TimedMB
{
public:
TimedMB() : timeout_(0), caption_(0)
{
interrupt_ = CreateEvent(NULL, FALSE, FALSE, NULL);
}
~TimedMB()
{
CloseHandle(interrupt_);
}
static DWORD WINAPI timer(LPVOID param)
{
TimedMB* mb = reinterpret_cast<TimedMB*>(param);
if(WAIT_TIMEOUT == WaitForSingleObject(mb->interrupt_, mb->timeout_))
{
HWND message_box = FindWindow(NULL, mb->caption_);
if(::IsWindow(message_box))
{
PostMessage(message_box, WM_COMMAND, IDCANCEL, 0);
}
}
return 0;
}
void DisplayMessageBox(const char* msg, const char* caption, DWORD timeout)
{
timeout_ = timeout;
caption_ = caption;
CreateThread(NULL, 0, &TimedMB::timer, this, 0, NULL);
::MessageBox(NULL, msg, caption, MB_OKCANCEL);
::SetEvent(interrupt_);
}
private:
HANDLE interrupt_;
DWORD timeout_;
const char* caption_;
};
int main()
{
TimedMB mb;
mb.DisplayMessageBox("Hello There!", "My Message Box", 5000);
}
If you need to dismiss it automatically, I'd avoid using MessageBox at all. Instead, I'd just put together a dialog that closes itself after the specified period of time. If memory serves, you can do this pretty easily by setting a time when you display the pseudo-message box dialog. When the time goes off or the user clicks "ok" (or "close", etc.) you close the window and cancel the timer.
Don't do this. Modal dialogs should be closed by user intervention. Deviating from this pattern is just confusing and non-standard. If you want a message windows that closes itself, then use a balloon window.
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.
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.