In my app, I read/parse data that takes some time. While that process is going on I want to display a message on screen indicating the process going on. I beileve I got to use Thread for it, but don't get an idea how to use and implement it.The calling method may throw exception or so.
Any idea/tip on how to achieve the task. Any help is highly appreciated.
Thanks
I'll assume that you're using .Net.
You should use the BackgroundWorker component.
Perform your operation in its DoWork event (which runs on a background thread), call ReportProgress to post messages for the UI, and handle ProgressChanged and RunWorkerCompleted to update the UI.
Related
I am fixing a MFC applivation written in C++. It is a GUI and it communicates with an external module connected to the PC via USB.
I want to avoid using a separate thread. Is there a way I can add things to the mainloop so that it runs continously rather than being event based?
I want the mainloop to make a call to a function runCommStack() in every loop.
Some possible approaches:
You can use CWnd::SetTimer to set a timer.
You can override CWinApp::OnIdle (called by CWinApp::Run).
You can override CWinApp:Run, copying and modifying the original MFC's CWinApp:Run. This definitely is not the easiest solution.
You can create a background thread.
It depends on the requirements of runCommStack(). Is this function running long times? Then you probably won't want to run it in the GUI thread. Does runCommStack need to get called every n milliseconds? Then it might also be better to run it in it's own thread. In other cases you can just use the timer or OnIdle approach.
Regarding solution 1: as Tim pointed out WM_TIMER messages are low priority messages and will not be passed to the application while other higher-priority messages are in the message queue. See also Determine priority of a window message.
With solution 2 you should remind that OnIdle will only be called if no window message is available. So this is quite the same as solution 1 (in fact a little worse).
Also keep in mind that solutions 2 and 3 might result in your runCommStack not getting called if a dialog's DoModal() is called or if a message box is displayed. This is because during MessageBox() the control is not returned to CWinApp::Run().
I'ld implement solution 1 or 4.
When there are no messages (like keys, mouse, repaint) arriving the main loop suspends the program, waiting for the next message. So the idea of adding a call to the main loop will give you very erratic operation. For example, minimizing your window will stop all the USB communication.
Using SetTimer and calling your runCommStack function in a WM_TIMER handler will probably be much more satisfactory.
You can use idle processing with CWinApp::OnIdle; this will work if reading your USB device takes only a short amount of time, otherwise the user interface will be blocked during long reads.
But using a separate thread is definitely a better method.
I have a DirectShow filter written in Delphi 6 using the DSPACK component library. It is a push source video filter that receives its source frames from an external cooperating process that I also wrote.
When the worker thread that calls my Filters' FillBuffer() call is created and ran, when the graph starts up, the first thing I do from that worker thread is create a hidden window using AllocateHWND() to process WM_COPYDATA messages that contain the externally generated frames. Right before the thread is destroyed I destroy the hidden window. In other words the hidden window is created and destroyed in the execution context of the worker thread that calls FillBuffer(). My intention is to let FillBuffer() block as it waits for a WM_COPYDATA or a WM_QUIT message. The external cooperating process will submit frames to my filter using a WM_COPYDATA message and the handle to my hidden windows' WndProcc(). I will post a WM_QUIT message in my override of the pin's Inactive() method (thanks for that tip #RomanR), to unblock the FillBuffer() call before the filter is shut down.
My question is, is it safe to call PeekMessage() or GetMessage() from the FillBuffer() call given this scenario? Or are there potential pitfalls that may arise from this occurring in the context of a DirectShow graph executing? Also, do you see any flaws in my overall approach here that I need to consider?
Safe, but not so reasonable too. FillBuffer is being called on a background worker thread which is typically have no windows on it. It would be perhaps only your window which you are going to implement message loop for. And the window is here only for the purpose of receiving WM_COPYDATA messages. It sounds like it can work out, but you would perhaps could do much easier without helper windows by passing your data between applications via named file mappings and events. In case of video (you have audio, right?) you would also be able to appreciate a smaller performance overhead.
I developed a class (in C#) for sending and receiving messages over network. It creates a new thread (listener thread) which waits till a new message arrives then raises an event.
The problem is the event is raised in the listener thread and when I want to use this class in a wpf application, a run-time error occurs trying to handle the event
The error is:The calling thread cannot access this object because a different thread owns it.
Is there any proper way to deal with this situation when the event raises in the mentioned class?
You've got to be on the UI thread to update UI objects. You can use the window's Dispatcher to execute code there:
this.Dispatcher.Invoke(new Action(() =>
{
// Code that updates UI here
}));
BackgroundWorker explicitly supports marshaling to the UI thread. You have to use it though, call its ReportProgress() method. While optimized for reporting progress, you don't have to use it for that. There's an overload that accepts an object, you can pass anything you want. The event handler gets it as the e.UserState value. From there, you could use that object directly or use it to re-raise another set of events.
Do beware thread-safety requirements for that object. The worker keeps running and is not in any way synchronized with the execution of the ProgressChanged event handler. So it should no longer update the object. Best to create a new instance of it after calling ReportProgress().
Does anyone know where is the best place to forward thread messages to child controls?
Basically, app has to catch registered thread messages in range msg_frst...msg_last and forward them to active frame/view.
There are 3 overload points in MFC, or so it seems:
DefWndProc
OnWndMessage
PreTranslateMessage
Which is the correct one to override?
A message posted with PostThreadMessage() has a NULL window handle. So forget about any of the window methods, DispatchMessage() isn't going to deliver them. All you got is CWinThread::PreTranslateMessage().
But there's a big hazard here, this isn't going to be called anymore when any code in that thread start pumping its own message loop. Your messages now fall in the bit bucket because other code is now calling Peek/GetMessage(). That's a lot more likely then you think, MessageBox() is enough. Or the COM modal loop. Etcetera.
You can only safely use PostThreadMessage() to send messages to a thread that does not create any windows of its own. The workaround is simple enough, provide the thread with a window handle so it can call PostMessage() instead. That could be a hidden window, dedicated to handling these messages for example.
I'm implementing my app as a drag source. When I call DoDragDrop (Win32 call, not MFC) it enters into a modal loop and I don't get repaint messages in my main window until DoDragDrop returns. Unfortunately if I do a drop in the shell (a file) and the filename is already there the shell asks if I want to replace the file. But since me app is blocked because DoDragDrop hasn't returned it isn't repainting and looks 'frozen'.
Any clues ?
Have you tried a timer? I ran into the same problem with DoDragDrop() and other blocking calls like SHFileOperation() and solved it using a call to SetTimer().
EDIT: If you want more control over DoDragDrop() then a worker thread works well. You can try calling DoDragDrop() in the worker thread, as someone suggested, but I couldn't get the mouse capture to work properly. An easier solution is to call DoDragDrop() in the main thread and have the worker thread periodically post a WM_USER message to the main thread's queue. DoDragDrop() will then retrieve the message and dispatch it to your window's WndProc(), at which time you can perform idle processing for as long as the queue remains empty. If you give the worker thread a lower priority than the main thread, then it will execute and post the WM_USER message as soon as the main thread becomes idle (i.e., as soon as DoDragDrop() finishes processing all user input and calls MsgWaitForMultipleObjects() internally). This method is better than the SetTimer() method because it gives your application full control over the CPU. You don't have to wait up to 10ms (the minimum frequency that SetTimer() allows) after returning from your WM_TIMER handler returns before the next WM_TIMER message arrives.
I suggest running the drag-and-drop operation on a different thread. That way, DoDragDrop() will block the message loop in the new thread rather than the message loop in your UI thread. If you take this approach, you should also consider (off the top of my head):
Any code that might be run from both your main thread and your drag-and-drop thread will need to be re-entrant. As a corollary, you will need to protect any data structures used by both your main thread and your drag-and-drop thread. If your application is already multi-threaded, you should be familiar with these concerns.
You should think about what happens if your user never responds to the shell's dialog box. Can he continue to interact with your UI? Can he invalidate the data that would have been 'dropped' in the pending operation? Can he quit your application?
Seems like the real answer is to implement IAsyncOperation in my data object.