I'm trying to send a keystroke to another application. I can successfully find the window handle since using SendMessage worked exactly as intended.
However, when I switched the SendMessage over to PostMessage, the application no longer received the messages.
I did, however, find a workaround by using HWND_BROADCAST as the window handle, and it works fine, but isn't the ideal way to go about it.
What I'm asking is, I have a valid hWnd, how can I send it messages using PostMessage and not SendMessage?
Edit
This is what I'm trying to do.
HWND Target = FindWindow(0, "Window Title Goes Here");
LPARAM lParam = (1 | (57<<16)); // OEM Code and Repeat for WM_KEYDOWN
WPARAM wParam = VK_SPACE;
PostMessage(HWND_BROADCAST, WM_KEYDOWN, wParam, lParam); // Works
PostMessage(Target, WM_KEYDOWN, wParam, lParam); // Doesn't Work
SendMessage(Target, WM_KEYDOWN, wParam, lParam); // Works, but I need Post
The PostMessage function does not work when the message numbers between 0 and WM_USER-1. Use RegisterWindowMessage function to register your own messages.
Sent messages and posted messages take completely different routeres. Target is recieving your posted message, it's just either filtering or dispatching it to another window. It gets to do what ever it wants with it. When you send the messages, it goes directly to the window procedure without filtering, so is most likely that cause of that issue.
I don't know why HWND_BROADCAST is working; my best guess is that a window other than Target is processing the message. Or maybe its even being sent to a different window than Target. (You do realize that HWND_BROADCAST sends the messages to every top level window)
There is a Win32 API function designed to send input, SendInput(), that places the messages on the input queue just like a user keypress. However this doesn't let you specify a window, it sends its input to the active window. To use it you would have to activate and switch focus to Target, which means the user would see that window move to the top (just like you Alt-Tabbed to it). Along that same route VBScript has a SendKeys() function that does the same thing, but is easier to use.
As a final alternative you could use SendMessageCallback() which will give you the behavior of an asynchronous SendMessage which is what I assume you want. (And is different than PostMessage. Posted messages go into the posted message queue, sent messages are delivered directly)
*For the lparam go here http://msdn.microsoft.com/en-us/library/ms646280%28v=vs.85%29.aspx, change the 32 bits (31...3 2 1 0) of lParam. Once you have the binary sentence you want for your paramaters (cRepeat, Scancode etc), convert it to hexadecimal.
try this :
void SendString(HWND h, char *text)
{
int len = strlen(text);
for(int i = 0; i < len; i++)
PostMessage(h, WM_CHAR, text[i], 0);
}
HWND Target = FindWindow(0, "Window Title Goes Here");
LPARAM lParam = //The hexadecimal value matching with the parameters you want* example 0x29A1.
WPARAM wParam = VK_SPACE;
PostMessage(HWND_BROADCAST, WM_KEYDOWN, wParam, lParam);
PostMessage(Target, WM_KEYDOWN, wParam, lParam);
SendString(Target, (char*)"themessageyouwant\n");
Related
I need to be able to determine which window the message is intended for, but I don’t understand how to do it correctly. In WH_MOUSE has a special structure (MOUSEHOOKSTRUCT) that stores the hwnd of the window, but where to get the hwnd in WH_KEYBOARD?
LRESULT CALLBACK messageHandler(int nCode, WPARAM wParam, LPARAM lParam)
{
// ???
}
DWORD WINAPI messageDispatcher(LPVOID thread)
{
hookHandle = SetWindowsHookEx(WH_KEYBOARD, messageHandler, GetModuleHandle(nullptr), *reinterpret_cast<DWORD*>(thread));
if (!hookHandle)
{
return GetLastError();
}
MSG message{};
while (GetMessage(&message, 0, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
return 0;
}
In theory, I could use GetForegroundWindow, but it seems to me that this is a terrible option, because the window can receive a keyboard message from some other process (if another process sends a SendMessage to this window) and not the fact that the current window will be exactly the one for which the message was intended.
At the time a keyboard action is generated, the OS doesn't know yet which window will eventually receive the message. That is why the WH_KEYBOARD hook doesn't provide a target HWND, like a WH_MOUSE hook does (since a mouse message carries window-related coordinates).
When a keyboard message is being routed to a target, the message gets delivered to the window that currently has input focus.
Per About Keyboard Input:
The system posts keyboard messages to the message queue of the foreground thread that created the window with the keyboard focus. The keyboard focus is a temporary property of a window. The system shares the keyboard among all windows on the display by shifting the keyboard focus, at the user's direction, from one window to another. The window that has the keyboard focus receives (from the message queue of the thread that created it) all keyboard messages until the focus changes to a different window.
Since your hook runs inside of the message queue of the target thread, you can use GetFocus() to get the target HWND at that time:
Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue.
Otherwise, you can use a WH_CALLWNDPROC/RET hook instead, which gets called when the message is actually delivered to a window. However, you can't block messages with this hook (as you were asking about in your previous question).
I think what you might be looking for is a hook of type WH_JOURNALRECORD.
With this, the callback procedure that Windows will call in response to the various events that this hook intercepts is of type JournalRecordProc, and the lparam parameter passed to this function points to an EVENTMSG structure, which looks like this:
typedef struct tagEVENTMSG {
UINT message;
UINT paramL;
UINT paramH;
DWORD time;
HWND hwnd;
} EVENTMSG;
And there is your hwnd!
If I have a console application with a handle to it set up like so;
HWND hWnd = GetConsoleWindow();
Then how do I set up a new wndProc for the window?
I tried using
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)conProc);
With conProc being defined as
LRESULT CALLBACK conProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NCHITTEST:
return HTCAPTION;
}
return DefWindowProc(hWnd, msg, wParam, lParam );
}
But it doesn't work and says "Error code: 5 - Access is denied" on GetLastError()
I understand that it's pretty difficult to modify the console application like this, since it's a csrss.exe application and all, but I'd still like to try..
Thanks.
While the impression is that console window belongs to your process (like other window), it is in fact hosted by CSRSS system process and its WndProc is there. This makes you unable to subclass the window and provide your own WndProc living in your process.
Some related reading:
The process that is in charge of displaying the GUI windows in which consoles are presented is... CSRSS
SetWindowsHookEx with WH_KEYBOARD doesn't work for me, what do I wrong?
Subclassing XP Console Window
First of all SetWindowLong is superseded by SetWindowLongPtr, you should use that function.
Are you trying to change the WNDPROC of your own console window or another process?
From the MSDN docs :
GWL_WNDPROC
-4
Sets a new address for the window procedure.
You cannot change this attribute if the window does not belong to the same process as the calling thread.
Hello everyone I am new to windows32 programming and I have a couple of questions-:
When I use the following code in a program it works fine -:
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
But when I replace null of GetMessage to hwnd(the handle of the window just created) the doesn't seem to close it still remains running in the background. Why does this happen when I replace NULL with hwnd means I am receiving messages for only one window then why doesn't it work????
while(GetMessage(&msg,hwnd,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
By the way the windows function is-:
LRESULT CALLBACK WinProc(HWND hWnd, UINT message,
WPARAM wparam, LPARAM lparam){
switch(message){
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wparam, lparam);
}
return 0;
}
Secondly-:
Is there any way I can see all the messages sent to any particular window????
Thirdly-:
What is the reason behind writing __stdcall(WINAPI) when compiling my windows programs ????
A quick reply would be appreciated.Thank You.
GetMessage returns 0 (making the loop end) only when it receives a WM_QUIT, but a WM_QUIT is not associated to any particular window, so it is never received if you have a GetMessage that asks only messages for a certain hWnd.
If it's a window of yours, you already see them inside their window procedure; if you want to filter them before dispatching them to their window procedure, you can check the msg structure that is populated by GetMessage before calling DispatchMessage.
The whole Windows API uses the stdcall calling convention (I think because it is slightly faster/produces less boilerplate code than the usual cdecl), so also your callbacks must follow that calling convention. Notice that you must use WINAPI (i.e. stdcall) only on functions that are called by Windows API functions, for the other ones you are free to use whatever calling convention you like best.
PostQuitMessage generates WM_QUIT which is processed by the message queue, but not associated with a particular window. By filtering only hwnd messages in your call to GetMessage, you don't process WM_QUIT.
Regarding seeing all messages being sent to a window / thread / process, see https://stackoverflow.com/questions/4038730/i-am-looking-for-a-windows-spy-application
Finally, regarding __stdcall, see What does "WINAPI" in main function mean?
I want to disallow the user of my application from using alt-tab. I'm trying to solve this by using a low level keyboard hook.
Setting it up works perfectly, the callback procedure is triggered when I press the key combination etc. The weird thing that happens is that I can alt-tab out of the application but then alt-tabbing is disabled, completely. I switch applications with the mouse and try alt-tabbing but nothing happens. I switch back to my application and alt-tab again and it switches the application, but only one step. When out of my application the alt-tab isn't working anymore.
I've tried different scenarios, first I thought it had something to do with the debugger in VS2010 but no, running it with out the debugger gives the same results.
Have I completely misunderstood this hook procedure, is it meant to only catch stuff happening when the application isn't in focus?
osman.hpp :
static HHOOK m_hhook;
static LRESULT CALLBACK lowLevelKeyboardProc( int key, WPARAM wParam, LPARAM lParam );
osman.cpp :
HHOOK OSMan::m_hhook;
/*
* pseudo init code
*/
void OSMan::init()
{
m_hHook = SetWindowsHookEx( WH_KEYBOARD_LL, (HOOKPROC)lowLevelKeyboardProc, 0, 0 );
}
LRESULT CALLBACK OSMan::lowLevelKeyboardProc( int key, WPARAM wParam, LPARAM lParam )
{
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;
switch (key)
{
case HC_ACTION:
{
if (pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN)
return 1;
}
default:
break;
}
return CallNextHookEx( m_hHook, key, wParam, lParam);
}
edit:
added code.
If you want to disable alt+tab correctly, you should just register the hotkey via RegisterHotKey(0,0,MOD_ALT,VK_TAB); and then handle (well, more ignore) the message that this generates, this allows you to make it application local, not worry about Windows hook chains and allows you to easily enable or disable it on the fly.
Although for a game, the idTech 4 input handling code has a vast array of the input gems.
You are installing a System Wide hook, that is why you have disabled the use of Alt-TAB on the whole system.
You can't use a WH_KEYBOARD_LL you must use a WH_KEYBOARD hook, and make it process specific.
The params of the SetWindowsHookEx will change if you make your hook process specific.
Here is an overview of the params :
dwThreadId [in]
Type: DWORD
The identifier of the thread with which the hook procedure is to be associated.
If this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread.
PS : in reply to comment :
The hook only is installed after the process got one appropriate event. While hooking onto keyboard messages, you will have to send at least one keyboard message before the hook is installed.
Work Around
Maybe you want to work around this issue by using the ShowWindow function ?
Here is the doc : http://www.pinvoke.net/default.aspx/user32.showwindow
cf : http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces
cf http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
and
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644959(v=vs.85).aspx#wh_keyboardhook
if i close my application via Alt-F4, or the corner "X" button, or by posting destroywindow(hwnd) myself, the application closes correctly, and everything works just as expected.
but recently i realized, on windows7, when i close the app by right klicking on the icon in the taskbar, and clicking "Close Window", the window closes, but my app is still running. when debugging, i don't get into either of the WM_QUIT/DESTROY/CLOSE events.
is there some special behavior when closing a window via taskbar? how can i detect that?
You should get WM_CLOSE. Maybe you're getting it on a different window that the one you're expecting? Although that shouldn't be able to happen unless you have multiple top-level windows.
via Alt-F4, or the corner "X" button, or by posting destroywindow(hwnd) myself
You can't post DestroyWindow(). Ensure that the window procedure of your main window resembles this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
// Other cases
//...
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
The PostQuitMessage() function call ensures that your message loop exits, GetMessage() returns FALSE when it receives the WM_QUIT message. This makes your main window behave like the main window, closing it ends the process. You may have other top-level windows that don't, they shouldn't have this WM_DESTROY message handler. DestroyWindow() is already called automatically by DefWindowProc() when it processes the WM_CLOSE message.