Viewing Win32 messages - c++

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?

Related

C++: How to set a new wndProc for a console application?

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.

How to handle keyboard events in a winapi standard dialog?

i don't often work with winapi, i'm writing almost .NET code. But at this time I have to use the winapi to make a simple dialog. There i want to handle some keyevents. Therefore i watched for the corresponding callback message WM_KEYDOWN or WM_KEYUP at MSDN and added it to my callback function.
INT_PTR CALLBACK cbfunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch(message) {
// ...
case WM_KEYUP:
MMsgBox("up"); // I never get here
return 0;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
return 0;
// ...
}
return 0;
}
But neither WM_KEYUP nor WM_KEYDOWN ever get triggered. Then I stated looking for a solution for this problem. I thought may my dialog eats this messages. So I added:
case WM_GETDLGCODE:
return DLGC_WANTALLKEYS;
With the result that it doesn't help.
Other solutions I've found were the following:
Alternatively using the WM_GETDLGCODE event to handle this keys as suggested on here.
I've found a lot of threads (like this one) talking about a method called PreTranslateMessage. But I don't even have got this class, because I simply create my dialog by using DialogBoxParam
So none of them worked for me. In the moment i have got no idea how to handle it. Something I've noticed, is that on key press a WM_COMMAND message seems to occur.
Regards Nem.
According to this link, certain messages are hard to trap with dialog boxes because Windows processes them internally and they never get to the DialogProc. Here are two of the options I can think of:
Use GetAsyncKeyState on a WM_COMMAND event
Create a custom dialog box, the DialogProc for which will handle WM_KEYDOWN etc. messages.
DialogProc doesn't receive WM_KEY events (and many others too). You can:
Subclass the dialog window (overwrite its WndProc) and process all
messages there, sample
Register hot key for the dialog window's HWND and then receive WM_HOTKEY in DlgProc (but registered key combinations will be system-wide)
Create your own message loop, link
Replace This
case WM_KEYUP:
MMsgBox("up"); // I never get here
return 0;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
return 0;
With This
case WM_KEYUP:
MMsgBox("up"); // I never get here
break;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
break;

not properly closing from taskbar closing event

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.

Windows Messages Bizarreness

Probably just a gross oversight of some sort, but I'm not receiving any WM_SIZE messages in the message loop. However, I do receive them in the WndProc. I thought the windows loop gave messages out to WndProc?
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
case WM_SIZE:
return 0;
break;
}
printf("wndproc - %i\n", message);
// Handle any messages the switch statement didn't
return DefWindowProc (hWnd, message, wParam, lParam);
}
... and now the message loop...
while(TRUE)
{
// Check to see if any messages are waiting in the queue
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
// check to see if it's time to quit
if(msg.message == WM_QUIT)
{
break;
}
if(msg.message == WM_SIZING)
{
printf("loop - resizing...\n");
}
}
else
{
//do other stuff
}
}
If a message is sent by the system to your window while it's in DefWindowProc or elsewhere in that netherworld that's the Windows message queue, then that message is not going to be seen by your message loop at all.
Note that this is only true for sent messages. Posted messages will show up in the message loop.
If you want to filter all messages, use SetWindowsHookEx with your thread ID, and the appropriate hook type. Or better yet, process them properly in your WndProc.
While you've got hold of the sizing gripper, I believe that Windows is running its own message loop. That will dispatch to your message queue, but your loop is out of the picture while the sizing is ongoing.
The frame window will call SetCapture to capture all subsequent mouse messages. Then it'll resize your window as the mouse moves. It'll also pump the message loop; you can see some similar code here: ftp://ftp.ringdale.com/support/Nlynx/Tech%20Support%20Docs/Midrange/EmeraldSeries/ADK/DDE/C/APITERM/TRACK.C. Note the message loop in the middle of that function.
It pumps the queue itself so that the sizing code doesn't have to return until after the resize tracking is complete.
Edit: I bring up the tracking rectangle code since that's how window resizing used to work, showing just a thin rectangular outline of the window, until we got dynamic window resizing where the entire window updates on the fly while you resize. The behavior internally is likely similar.
Edit 2: Still, credit to the guys who mentioned posted vs sent messages... sent messages won't ever go through the message pump. Sent messages quickly boil down to a function call of your wnd proc. Unless they're sent to windows owned by a different thread, which becomes a lot more complex; they get added to an internal queue belonging to the destination thread's message queue, and are processed internally - before posted messages are returned -inside GetMessage. Getting the sent message's return value back to the source thread involves more gyrations :)
WM_SIZING and WM_SIZE are not the same message. I think ordinary mouse operations to resize a window send WM_SIZING first, but if some program sends a WM_SIZE message then you're only going to get WM_SIZE without WM_SIZING.

PostMessage for cross application messages

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");