As you know, OnIdle can be specified in MFC UI thread. For details, you can read this reference http://msdn.microsoft.com/en-us/library/1sa2f19f.aspx. But I am not sure how it can be used in practice.
According to the reference above,
"OnIdle is called in the default message loop when the thread's message queue is empty. Use your override to call your own background idle-handler tasks."
So I can understand that when the UI thread is not busy, the method is called. According to the documentation above,
"Because the application cannot process messages until OnIdle returns, do not perform lengthy tasks in this function."
But what tasks can be done in the idle event? A single example would suffice. Thanks
UPDATE: One discouraging fact is that this old (1996) article by Russell Weisz, titled "First Aid for the Thread-Impaired: Using Multiple Threads with MFC." was very helpful to understand CWinThread.
UPDATE2: As Microsoft removed the MSJ article, this one might be helpful.
MFC uses its default OnIdle processing to enable and disable menu items and toolbar buttons, as you can see in the documentation for CWinApp::OnIdle. There doesn't have to be explicit code to enable or disable these items as conditions change, it just happens automatically when nothing else is going on.
Windows itself uses a similar strategy for firing WM_PAINT messages - those only get generated when nothing else is in the message queue.
You use this technique when you have a low-priority task you want to do.
Related
I need to pump COM messages while waiting for an event to fix a deadlock. It's better to pump as few messages as possible just to process that COM call. The best candidate for this role is CoWaitForMultipleHandles but starting from Vista it pumps WM_PAINT in addition to COM messages. Pumping WM_PAINT is too dangerous for me from re-entrance perspective and I don't want to install a custom shim database as a solution for this problem.
I'm trying to pump COM messages sent to the hidden message-only window manually.
I have found two ways to get HWND of the hidden window:
((SOleTlsData *) NtCurrentTeb()->ReservedForOle)->hwndSTA using ntinfo.h from .NET Core. This seems to be undocumented and not reliable solution in terms of future changes.
Find window of OleMainThreadWndClass as suggested in this question. The problem is that CoInitialize does not create the window. It is created later on first cross-apartment call which may or may not happen in my application. Running the search loop every time I need HWND is bad from performance perspective but caching HWND seems impossible because I don't know when it's created.
Is there a way to determine if the hidden window is created for the current apartment? I suppose it will be cheaper than the loop and then I could find and cache HWND.
Is there a better way to pump COM messages without pumping WM_PAINT?
Update: you can force the window creation by calling CoMarshalInterThreadInterfaceInStream for any interface. Then call CoReleaseMarshalData to release the stream pointer. This is what I end up doing along with the search for OleMainThreadWndClass.
WM_PAINT is generated when there is no other message in the message queue and you execute GetMessage or use PeekMessage.
But WM_PAINT is only sent if you Dispatch it. Also there is no new WM_PAINT message until a window is invalidated again.
So it depends on you if you dispatch a WM_PAINT message or not. But be aware, there are other chances of reentrances like a WM_TIMER message.
The details about this are in the docs for WM_PAINT.
From my point of view the best solution would be to set you application in a "wait" mode, that even can handle WM_PAINT in this undefined waiting state. You know when you are reentered. It is always after a WM_PAINT... or similar messages that arrive like other input messages. So I don't see any problems here. An STA has one thread and you always process messages to an end, until you execute GetMessage, launch a modal dialog or show a MessageBox. When you are inside some message handling, nothing will disturb you.
Maybe an other solution would be to wait inside a second thread for this event. This thread may not have any windows and you can translate the event to anything you need in your application.
So you question may not have enough information how this deadlock really appears. So this answer may not be sufficient.
After writing als this I tend to the opinion that this is an XY problem.
I have a CListCtrl in my MFC application. The list needs to be updated when I get some notification from the server. Updating list works quite good when there are less notification as operations on the list are less. But in case of heavy load, list control and in turn the application gets freeze.
I am aware of updating UI items in the separate thread in case of bulk updates, but in this case I have the notifications that can come in any order and in any volume, I need to handle in such way that my main thread is not getting blocked.
If anyone faced the issue before please suggest the approach for this case.
You could put all the updates into a queue. Then do a limited number of updates from the queue to the control in the OnIdle function. OnIdle is called when your GUI message queue is empty. It could do up to, say, 20 updates and then return. The main thread would than process any GUI input and when finished with that it would call OnIdle again. In this way you delay and spread out the updates while keeping the GUI alive.
I had a similar situation and resolved it using a Timer. Only when the Timer ticked the ListCtrl could got updated.
Side note: You should do
SetRedraw(FALSE);
before a bulk update
and
SetRedraw(TRUE);
after.
You should not have the control drawing itself at a one-by-one item level, when doing a bulk operation.
Use Thread.I had the same problem and I solved it by just having the loop of adding elements into the clistctrl in thread function. That is,is the POSTMESSAGE() function in the thread should be called as much time as we want to add elements .
MFC Application getting stuck when adding list control elements
Also refer the above link to get some idea
My application has 2 parts, one is a MFC based window, while the other is a C++ based code.
I need to have a timer attached to both these parts, that would trigger a behaviour at repeated intervals.
I used to be able to do this easily with QTimer, when I had worked with Qt.
With MFC/C++ I'm not sure what to use. Would a single setTimer() suffice, and how would the message handler look like in the C++ part of the code?
Kindly suggest how to attach one timer which would work with both these sections.
Thanks.
You cannot have a single timer invoke more than one action. If you want an expired timer to result in more than one action you will have to trigger all those actions from a single timer handler.
To set up a timer you can use SetTimer. You get to decide whether an expired timer posts a WM_TIMER message or calls a callback routine instead. Either way you can trigger whichever actions you desire.
How you implement the communication is up to you. The details you provide in your question are vague. Windows does not know or care what C++ is. Saying that part of your application is C++ based code does not help much. I'm sure the MFC part is C++ based as well.
SetTimer only works with a window. What you refer to as the C++ part of the code cannot have a message handler unless it creates a window to receive messages.
I have a third party encryption library, which may create a MessageBox if key creation fails. The failure can be caused by bad random number generation or other rarities, and in most cases, trying again will result in success. My code will attempt key creation up to three times before deciding it failed.
Now, the issue is that the program may be used with automation. If a MessageBox is created during automation, it will block the process forever, because there's nobody to click the 'OK' button.
Does anyone know of a way to catch when this message box is created and automatically close it?
Anything is fair game, as long as it's not something that will make security suites angry. This means no hooking or code tunneling.
In summary, I need to catch when a MessageBox is created and close it. The MessageBox's creation is outside of my control. Modifying the code at runtime is not acceptable.
Also, I've noticed there are some other similar questions, but they don't have the same requirements.
EDIT: Additional note, I can find the message box via searching through all windows until I find one with a matching title and then send it a WM_CLOSE message, but I don't think this is a great solution. I also have no guarantee that the message box has been/will be displayed, or how long after my call it will be displayed. It could display instantly, it could display 1200 ms later, or it could not display at all.
Just before you begin the encryption process, install a WH_CBT hook, and in its callback watch for an nCode of HCBT_CREATEWND. If you get a matching class name ('#32770 (Dialog)' ?) and a matching title either return a nonzero value from the callback, or if that doesn't work post a WM_CLOSE (or a BM_CLICK to a relevant button if selecting an option is necessary). Uninstall the hook after the process for not messing with every possible dialog your application pops up.
That sounds like bad design on the part of that library. Generally any sort of utility library (like encryption) has no business invoking any kind of GUI (unless you explicitly ask it to).
Is there possibly some configuration or setting in this library that could disable its use of message boxes?
If not, I'd suggest that you might want to investigate using a different library. After all, if the designers of this library have already made this kind of poor design decision once, then there may be other unfortunate surprises lurking in there.
You can hope that it will be found by GetForegroundWindow, but this may catch other applications. The more brute force way is to iterate over all windows with EnumWindows looking for something that has a caption or text equal to this shown by the library.
I have once "remote controlled" an application by sending mouse click events to some controls. I guess you would have to do this in a separate thread that is watching for Events if a window is opened. Pretty ugly but working...
Create a new thread. If your function fails and a Message Box is opened, obtain a handle to the message box by looping through the windows (GetTopWindow, GetNextWindow) and comparing the window's process id to the one returned from GetCurrentProcessId().
Or, you can avoid all the hard work and just hook the MessageBox API with detours. It's not very hard, and if you don't want to pay for detours, you can do it manually.
Call VirtualProtect and set the memory protection at MessageBox at PAGE_EXECUTE_READWRITE
Create a naked function, and use it as a trampoline.
Create a function identical in parameters to MessageBox (this will be your hook)
Create a jump from MessageBox to your hook function.
Does any one know how the event handler manages the posted events?
In my app i have two threads (guiThread and computationThread). After an exception is thrown I call postEvent(..) to an existing dialog. The Qt-Event-Handler holds this one back until the dialog is closed.
Sorry my question is a bit cloudy. I will write it more exactly, if I have time left. I found a work around. But for me the problem is still interesting.
As mentionned in the Qt documentation about QCoreApplication::postEvent :
When control returns to the main event loop, all events that are stored in the queue will be sent using the notify() function.
...which explains why the Qt Event Handler holds the event until the dialog is closed.
If I understand correctly what you want to do, I would try using sendEvent.
I'm guessing that the dialog you created is modal, which would mean that it is running its own event loop. No events posted to the general guiThread will be processed until all modal event loops are exited.
Alternately, if you need the dialog to both be modal and know about the event, you could post the event directly to the dialog. You'll need to figure out how to handle pointers in a shared manner, but if nothing complicated is going on, you might be able to use the QApplication::activeWindow() function.
As others already wrote, I believe this behavior is caused by the fact that the dialog starts its own event loop.
If you use Qt4, you can try using queued signal/slot connections as an alternative to posting events.