In our application we have an MFC dialog that opens and processes some data needed to display. Hence the processing is initiated lazily inside OnPaint() event. The processing
takes some time (about 20-30 sec), and is solely algorithmic (no UI API called).
What happens is that sometimes after the processing is finished the window "disappears". We found out that it's brought behind the parent window (main frame).
Calling SetForegroundWindow() right after processing has finished, or performing the processing in a non-UI thread (letting OnPaint() finish in reasonable time) has eliminated the problem.
Is this issue known? Is there any defined time limit for OnPaint() execution?
Thanks,
Alex.
http://msdn.microsoft.com/en-us/library/01c9aaty%28v=vs.80%29.aspx
The WM_PAINT message is sent when the UpdateWindow or RedrawWindow
member function is called.
A window may receive internal paint messages as a result of calling
the RedrawWindow member function with the RDW_INTERNALPAINT flag set.
In this case, the window may not have an update region. An application
should call the GetUpdateRect member function to determine whether the
window has an update region. If GetUpdateRect returns 0, the
application should not call the BeginPaint and EndPaint member
functions.
It is an application's responsibility to check for any necessary
internal repainting or updating by looking at its internal data
structures for each WM_PAINT message because a WM_PAINT message may
have been caused by both an invalid area and a call to the
RedrawWindow member function with the RDW_INTERNALPAINT flag set.
An internal WM_PAINT message is sent only once by Windows. After an
internal WM_PAINT message is sent to a window by the UpdateWindow
member function, no further WM_PAINT messages will be sent or posted
until the window is invalidated or until the RedrawWindow member
function is called again with the RDW_INTERNALPAINT flag set.
Related
Does the Window Procedure specified as lpfnWndProc by window class during registration runs in a separate thread ?
There is an important concept in windows called the message loop.
It is usually inside the main function (aka: WinMain) and can be characterized in the following manner:
while (true) {
// blocks until there's a new message to process
GetMessage()
TranslateMessage()
// ends up calling the propper WndProc callback
DispatchMessage()
}
Update: When you create a window, the thread on which the window is created owns the windows (and the its message queue). Therefor, it must provide the message loop process. This is usually done in the application's main thread but, as other user stated, it can also be done in a separate thread.
The function DispatchMessage takes care of executing the WindowProc procedure of the window targeted by the message (as specified by the message's hwnd parameter).
So, when you create a window, the lpfnWndProc parameter specifies where you want to be notified for events (mouse clicks, keyboard presses, etc). And it is always called in the same thread (the application's main thread or the one which owns the window).
A word of advice: If you need to perform a potentially long operation as the result of an event, you must create a new thread (aka background worker) for the task, and perform some kind of IPC to notify the main thread when the function is finished.
You can find instructions about how to write a windows procedure here. Also, there is some info about the main loop in this wikipedia page.
Does the Window Procedure specified as lpfnWndProc by window class during registration runs in a separate thread ?
No, it is called (as a callback) when events (aka messages) are dispatched by your message loop. In this way - the so-called 'event-driven' model - your program is able to react to user input as and when it happens without having to deal with any multi-threading or re-entrancy issues.
You might have more than one thread, but if it has windows associated with it (i.e. CreateWindowEx was called by that thread) then it would need to have its own message loop.
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'm trying to debug this problem in a library where a set of controls are not being updated to be disabled. I've drilled down to a point where I've hit a black box. A mfc120ud.dll!CCmdUI::DoUpdate() call will then call CCmdUI::Enable(). It'll then go through a bunch of calls one through ntdll.dll and 4 through user32.dll for which I have no source for and then sometimes stick its head our coming back to mfc123ud.dll or sometimes not.
I don't know why the WM_PAINT message gets invoked sometimes. Does anyone know?
Your call stack shows the reason.
CCmdUI::DoUodate finally calls CCmdUI::Enable.
Look into the CCmdUI::Enable code of the MFC. There are cases that WM_NEXTDLGCTL is called or EnableWindow. WM_NEXTDLGCTL may cause a focus change. It depends how the controls will handle this message. It is possible that they directly call UpdateWindow or RedrawWindow to reflect changes to the UI, instead of just calling Invalidate(Rec). There may be a control inside your ribbon that receives the WM_PAINT message.
The call to EnableMenuItem should be safe and I am sure that it doesn't cause a WM_PAINT call.
Does anyone know the WM_MESSAGE that is sent when a window has been maximized (either by the maximize button being pressed in the title bar, or by double clicking the title bar?)
Is there a windows message for the maximize button being pressed?
Win32/C++, thanks.
You get the WM_SIZE message with the value SIZE_MAXIMIZED in wParam
Edit
The #jamesdlin comment bellow called my atention to WM_WINDOWPOSCHANGED documentation, which states (emphasis mine):
Remarks
By default, the DefWindowProc function sends the WM_SIZE and WM_MOVE messages to the window. The WM_SIZE and WM_MOVE messages are not sent if an application handles the WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient to perform any move or size change processing during the WM_WINDOWPOSCHANGED message without calling DefWindowProc.
Thanks james!
I dealt with this recently, and the approach I settled on was to check IsZoomed in response to WM_WINDOWPOSCHANGED, comparing its result to the previous one to detect when a transition occurs, and then to forward WM_WINDOWPOSCHANGED to the default window procedure.
If you have complete control over the message handling in your application and know that there isn't (and won't ever be) a WM_WINDOWPOSCHANGED handler that suppresses WM_MOVE/WM_SIZE, then you should be able to handle it directly in a WM_SIZE handler as described in jachguate's answer.
Is there a way to hook for a particular windows message without subclassing the window.
There is WH_GETMESSAGE but that seems create performance issues.
Any other solutions apart from these which doesn't deteriorate performance?
AFAIK there's no better solution than what you mentioned. And, of course, subclassing the window is better than hooking all the messages of the thread.
Let's think which path the message passes up until it's handled by the window:
The message is either posted or sent to the window, either by explicit call to PostMessage/SendMessage or implicitly by the OS.
Posted messages only: eventually the thread pops this message from the message queue (by calling GetMessage or similar), and then calls DispatchMessage.
The OS invokes the window's procedure by calling CallWindowProc (or similar).
The CallWindowProc identifies the window procedore associated with the window (via GetClassLong/GetWindowLong)
The above procedure is called.
Subclassing - means replacing the window procedure for the target window. This seems to be the best variant.
Installing hook with WH_GETMESSAGE flag will monitor all the messages posted to the message queue. This is bad because of the following:
Performance reasons.
You'll get notified only for windows created in the specific thread
You'll get notified only for posted messages (sent messages will not be seen)
A "posted" message doesn't necessarily means "delivered". That is, it may be filtered by the message loop (thrown away without calling DispatchMessage).
You can't see what the actual window does and returns for that message.
So that subclassing seems much better.
One more solution - in case your specific message is posted (rather than sent) you may override the message loop, and for every retrieved message you may do some pre/post-processing