The usual WinAPI message loop looks something like this:
MSG msg;
while (GetMessage(&msg, hwnd, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Is it allowed not to call DispatchMessage() but to handle the message on your own? If not, how could I nicely approach this behavior while avoiding global variables and thread problems?
Edit:
I basically want to use my own callback function, which hasn't the WndProc signature. But I can't think of a way to call that function out of a WndProc without using static or global variables.
[Which would require locking, which I think isn't the best thing you can do with a callback function which probably gets called very frequently.]
Thanks for your help.
Is it allowed not to call DispatchMessage() but to handle the message on your own? If not, how could I nicely approach this behavior while avoiding global variables and thread problems?
If you are planning to use multiple threads in your GUI then each thread that creates a window will need to manage it's own message queue.
From this page: http://msdn.microsoft.com/en-us/library/ms810439.aspx
Changes to the Message Loop
Applications with multiple threads must include a message loop in each
thread that creates a window. The message loop and window procedure
for a window must be processed by the thread that created the window.
If the message loop does not reside in the same thread that created
the window, the DispatchMessage function will not get messages for the
window. As a result, the window will appear but won't show activation
and won't repaint, be moved, receive mouse messages, or generally work
as you expect it to.
You can react to a message there, but you still need/want to call DispatchMessage and actually handle the message in your normal wndproc. I'd be happy to say more about avoiding globals and/or threading problems, but it's hard to comment without more details about what you want to avoid.
Yes, you can handle the message yourself, if you wish. I usually set the result field to 0, but Windows only make use of this field for a few messages.
Related
I'm looking for some feedback on an issue that I can workaround, but want to understand better. I have some multithreaded code where a worker thread uses the Win32 API PostMessage function to post a message to the main UI thread in order to update a TreeView. Some of the posted messages sometimes fail to ever appear via the UI thread's message pump, despite my logging showing that the PostMessage returned successfully.
I've already found numerous explanations of how this could happen if I'd done something funky in my message pump, due to the presence of a modal message pump in certain circumstances, but I'm not doing anything funky.
I think (but would like confirmed) that my problem is due to calling PostMessage too early in the UI thread's lifetime. My WinMain calls CreateWindowEx to create its main window, and the WM_CREATE handler for that window indirectly launches the background threads that will, fairly quickly, call PostMessage using the main windows's HWND, possibly even before the WM_CREATE handler finishes, very likely before WinMain's message pump is started.
Is it possible/likely that some messages in this situation would be lost, even though PostMessage returned success? In testing, I've determined that adding a small delay (Sleep(50)) in the worker thread before it calls PostMessage is enough to prevent any message loss. However, I'm not convinced that this is solving the underlying problem so would like to know if I need to keep digging.
EDIT:
There's only one message loop in all my code and it's not doing anything unusual beyond calling the usual TranslateAccelerator etc:
// Enter the message loop
while (GetMessage (&msg, NULL, 0, 0)) {
if (!TranslateMDISysAccel(hwndClient, &msg) && !TranslateAccelerator (hwndFrame, hAccel, &msg)) {
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
I've already found numerous explanations of how this could happen if I'd done something funky in my message pump, due to the presence of a modal message pump in certain circumstances, but I'm not doing anything funky.
Modal loops don't throw away window messages, unless they are coded wrong and don't pass unknown messages to TranslateMessage()/DispatchMessage() like they should.
I think (but would like confirmed) that my problem is due to calling PostMessage too early in the UI thread's lifetime.
If that were the case, PostMessage() would simply fail, but you have already ruled that out. As soon as a thread calls any user32.dll function, the message queue is created and can begin receiving messages, even if the queue is not polled right away.
Is it possible/likely that some messages in this situation would be lost, even though PostMessage returned success?
No. Something else is going on. Either your message loop is filtering messages incorrectly, or a malformed modal loop is discarding messages, or you are simply posting to the wrong HWND. Hard to say as you did not show any of your code.
In testing, I've determined that adding a small delay (Sleep(50)) in the worker thread before it calls PostMessage is enough to prevent any message loss.
What is your main thread normally doing during those 50ms? Sounds like something in your UI code is receiving and discarding your posted messages during that time.
On the other hand, how do the threads know which HWND to post to? Is your WM_CREATE handler passing its hwnd parameter to the threads, or are the threads relying on the HWND returned by CreateWindowEx()? In the latter case, PostMessage() should fail if called before CreateWindowEx() exits. Unless your receiving HWND variable is initially uninitialized and contains a random non-null value that PostMessage() interprets as a valid HWND elsewhere on the system.
I was writing code for a win32 application when I came across a problem, how to use a handle as a function parameter. For instance whit this function:
void refreshWindow (HWND myWNDhandle)
{
InvalidateRect(myWNDhandle, NULL, FALSE);
}
If I would pass in "hwnd" as the parameter and run the code, like this:
refreshWindow (hwnd);
I would assume my window will be painted again, unfortunately my window won't.
What did i do wrong?
Mechanically your call is perfect. So either the HWND itself is invalid and, as other commenters suggest, you should assert on IsWindow() to validate that, or you are falling victim to the asynchronous nature of window repainting:
Calling InvalidateRect will merely mark the window as in need of painting, and a subsequent call to GetMessage will generate a paint message to paint the window if there are no other higher priority events or messages to process.
Typically then, methods that want to refresh the contents of a window immediately, follow the call to InvalidateRect with a call to UpdateWindow - which will ensure the window is repainted before returning.
I noticed that some messages in WinAPI can be retrieved only in the "main message loop" with PeekMessage() (like WM_QUIT), others can only be retrieved in the user defined winProc() function (like WM_CLOSE and WM_SIZE), and some messages like WM_MOUSEMOVE are retrieved with both.
What's the difference? How do I know where the WM message is going to be sent to?
Messages that were posted with a NULL window handle can only be retrieved in the message loop. Necessarily so, DispatchMessage() can't do its job. This is quite rare.
But yes, WM_QUIT, note how PostQuitMessage() does not take a window handle. That's rather inevitable, when you call PostQuitMessage() you (usually) don't have any window left so only a NULL window handle is sensible. Of course its real intention is to make GetMessage() return FALSE and thus terminate the message loop.
The only other case I can think of are messages generated with PostThreadMessage(). Note how this is a pretty dangerous function, it should never be used to post messages to a thread that ever displays any window. Such messages fall in the bit-bucket when another message loop pumps. Like the one that allows the user to move/resize a window. Or the one that keeps MessageBox() modal. It is only useful in process and thread interop marshaling.
So just ignore this, it is a corner-case.
I'm asking as the title says. Is it possible?
Since a MSG already contains all the things I need for a self-made event handler, I figured maybe I could make one. I'm asking this mostly to get rid of interpreted casting so I can use internal functions and classes inside my window class for performance. I also want to know if its possible to just get the MSG alone and do whatever I want with it.
Basically is there another way to get the window message, and then process it not similar to the general loops found in this thread?
EDIT:
Currently I'm using GetMessage() function to get the MSG struct and use that in my own event handler, however I am not getting all the messages that I want with this. Is there anything else I should do?
Thank you in advanced.
Currently I'm using GetMessage() function to get the MSG struct
Which is the problem, GetMessage() only retrieves messages that were posted to the message queue. It does not detect messages that were sent with SendMessage(). Which bypasses the message queue and calls the window procedure directly.
You therefore must use WndProc to see all the messages for a window.
The subset of posted messages that go into the queue and thus returned by GetMessage() is a small one. In a nutshell, the input notification messages for mouse and keyboard and the low-priority messages (WM_PAINT, WM_TIMER, WM_QUIT). WM_ACTIVATE is always sent.
Replacing the WndProc of a window is certainly a common technique, it is called "sub-classing the window". Any C++ class library wrapper uses it to map messages to C++ methods. Best to not re-invent that wheel.
I have an external application that calls my application and is supposed to end it when the job is done. The log from this external application claims it uses WM_CLOSE on my app.
How can I intercept the WM_CLOSE message in my application to do some cleanup operations? I tried at_exit() and wrapping it in a class, but I think I have the wrong approach.
The official solution for console applications is HandlerRoutine, a callback set by SetConsoleCtrlHandler. Windows will call your handler with a CTRL_CLOSE_EVENT argument in case of a WM_CLOSE exit.
When you're using a class method with SetConsoleCtrlHandler, it must be a static method - Windows won't provide you with a this pointer.
You could just handle WM_CLOSE in your message loop to do whatever cleanup is necessary, or even abort the close (by returning 1 instead of 0). See e.g. this: http://cboard.cprogramming.com/windows-programming/141438-handling-wm_close-wm_destroy.html#post1056273
Edit: for console applications, this may be of interest: http://support.microsoft.com/kb/178893
You must create hidden window using winapi, and handle WM_CLOSE message in its message loop. Is your app using any gui elements?
The easiest way I think is to call PeekMessage from time to time.
BOOL IsCloseEventReceived()
{
MSG msg;
return PeekMessage(&msg, NULL, WM_CLOSE, WM_CLOSE, PM_NOREMOVE);
}
This function should work to check if a WM_CLOSE message has been posted. It's not blocking, and you'll need to call it on a regular basis.
I might be wrong, but I think you don't need a hidden window to handle messages, a message queue is attached to your process the first time you call a messages-related function, like PeekMessage. However if you receive a WM_CLOSE message prior to your first call of this function it might be lost.