Multithreaded message pumping without second form - c#

I have a C# application which uses a COM component. This COM component require a message pump (Application.Run()) to do its processing. This means it's been stuck on the main thread. But I recently discovered that it's possible to start another Application.Run on another thread which gets its own ApplicationContext.
So I want to host the COM component on its own thread inside it's own Application.Run(), but I can't figure out how to get things started on the new thread without creating a UI form.
The WindowsFormsSynchronizationContext I need to communicate with the thread doesn't get created until Application.Run(). But once Application.Run() is called, I can't figure out how to get at the SynchronizationContext. If I could just raise a single event on that thread, I could use that to bootstrap the whole thing (create the COM object, etc.), but there doesn't seem to be anywhere to hook into the new event loop without a form.
I've tried all kinds of convoluted things, like installing a message filter (no messages get raised on the new thread), copying the execution context into another thread and trying to retrieve the SynchronizationContext from there (it refuses to copy the ExecutionContext of an already running thread), retrieving Thread.CurrentContext before starting Application.Run() and then calling DoCallbBack() (the DoCallback ends up on the original thread), etc. Nothing I've tried works.

Bryce,
You might be able to adapt this snippet from Anders Hejlsberg's talk about "The Future of C#". It's a little class that adds a message pump to a thread so that he can open windows using a REPL loop, and they will have a message pump attached to them.
The code looks like this:
using System.Windows.Forms;
using System.Threading;
class UserInterfaceThread()
{
static Form window;
public UserInterfaceThread()
{
var thread = new Thread(() => {
window = new Form();
var handle = window.Handle;
Application.Run();
});
thread.Start();
}
public void Run(Action action)
{
window.Invoke(action);
}
}
The discussion relating to this code occurs at 1 hour 5 minutes into Anders' talk, if you want to review it.

Related

creating new windows in a threadsafe manner

I am using signalR to push messages up to server and down to specific clients.
When I send a message, the receiving client is sent a ReceiveMessage function call from my signalR server, which maps to a static class function in my app. The static class then tries to do new Chat() (my messaging window class) to open a message window on the receiving side.
This throws calling thread must be STA, because many UI components require this.
I have worked with delegates before on simple form elements (like changing a textbox), but I don't understand how to apply that in this situation. When I read about Invoke, it is called on a form object of some sort, which does not exist in my situation?
TLDR; how do I create and show a new instance of a form from a static class function call
Use the current GUI's thread dispatcher. Then call invoke. Par example:
Application.Current.Dispatcher.Invoke(() => {
var win = new Window();
win.show();
});
Easiest: make use of App.MainWindow.Dispatcher to perform the create on the GUI thread:
App.MainWindow.Dispatcher.BeginInvoke((Action)(() => { new Chat(); }));
Harder: create a new STA thread, and create the new Window on it.
The latter option is harder because you'll have multiple GUI threads and need to ensure you keep track of operations so the right thread is used in each case. Unless you have a specific reason to have multiple GUI threads stick with the easy option.
You have to invoke your code in the UI thread. To do this you need a reference to the syncronization context.
Suppose you invoked the following code from UI thread:
SynchronizationContext syncContext = SynchronizationContext.Current;
Hereby you got a reference to the context.
Then in the callback method(after receiving a message in the background thread(not UI)) you can do the following:
syncContext.Post((state) =>
{
Window w = new Window();
}, ...);
The code in lambda expression is executed on behalf of UI thread.
As far as I know this is what actually happens behind the scene in both "Control.Invoke" and "Dispatcher.Invoked" approaches.

DirectShow/WPF Threading issue

I am writing an app using WPF and DirectShow and have run into a sticky issue. My application utilizes DS through static methods Start() and Stop() in a static class written using DirectShowNet (a C# wrapper class for DS). I have a Windows Forms panel in my WPF window (via a WindowsFormsHost object) that I need the graph to render to. Here is the general flow of the app: The Start() method builds the graph and starts it; I pass the handle of my windows form panel and render to it using the IVideoWindow interface. Start() returns and the graph runs in the background. At some point, Stop() is called; this method stops the graph and destroys it.
Everything works fine as long as I call Start() and Stop() from the same thread. However, I will need to call them from different threads in my app. When this is the case, I get an exception in the part of code that destroys the graph (specifically, when I am attempting to enumerate the filters). I discovered that I need to use a Multithreaded Apartment when working with DirectShow. This is easy with a Windows Forms app; I just throw a [MTAThread] on my main method and everything works.
For my WPF app, this is apparently not an option. My workaround has been to launch new MTA threads when I need to call Start() and Stop(). This gets rid of the exception, but has introduced another problem. When the Start() method returns, the video disappears from the render panel. If I put a Sleep at the end of the Start() method, the video will be visible until the Sleep ends. In addition, I have verified that the graph continues to run after the video disappears. Does anyone have any advice as to how to proceed? Thanks.
Kevin
Which exception is thrown? I'm guessing something along the likes of: "The calling thread cannot access this object because a different thread owns it."
When this is the case, use a correct dispatcher to do your calls, as explained here.
FYI, Windows Forms doesn't support a MTAThread main thread. If it worked, then you just got lucky.
I believe you should be able to invoke DS objects from STA threads just fine - though I'm not that familiar with DS, it sounds like you're using windowless mode and it seems to me that it would work best with STA.
In that case, why not always call Start/Stop from your main thread? If another thread needs to tell the main thread to stop or start, then just have it queue a task to a TaskScheduler.FromCurrentSynchronizationContext to run it on the main thread.
Ok, so I've encountered a problem not too dissimilar before, but not with WPF, so take the following (very hacky) suggestion with a pinch of salt.
The following method basically creates an entirely separate application thread to run directshow commands in, but tells direct show to use the handle of the windows forms control hosted in your WPF application.
So, first we need a dummy WinForms form that we can use to invoke calls on, but that is never going to get rendered:
/// <summary>
/// Just a dummy invisible form.
/// </summary>
private class DummyForm : Form
{
protected override void SetVisibleCore(bool value)
{
//just override here, make sure that the form will never become visible
if (!IsHandleCreated)
{
CreateHandle();
}
value = false;
base.SetVisibleCore(value);
}
}
Next step is to create a thread that we can put a message loop on:
//this will need to be a class level variable, since all the directshow
//calls will get invoked on this form
DummyForm dumbForm;
Thread separateThread;
private void CreateDummyForm()
{
ManualResetEvent reset = new ManualResetEvent(false);
//create our thread
separateThread = new Thread((ThreadStart)
delegate
{
//we need a dummy form to invoke on
dumbForm = new DummyForm();
//signal the calling method that it can continue
reset.Set();
//now kick off the message loop
Application.Run(dumbForm);
});
//set the apartment state of this new thread to MTA
separateThread.SetApartmentState(ApartmentState.MTA);
separateThread.IsBackground = true;
separateThread.Start();
//we need to wait for the windowing thread to have initialised before we can
//say that initialisation is finished
reset.WaitOne();
//wait for the form handle to be created, since this won't happen until the form
//loads inside Application.Run
while (!dumbForm.IsHandleCreated)
{
Thread.Sleep(0);
}
}
So, once the dummy form (and its thread) have been created, you can invoke calls on the MTA
application thread like so:
/// <summary>
/// Blank delegate, used to represent any Invoke or BeginInvoke target method.
/// </summary>
public delegate void InvokeHandler();
//i'm assuming here that DSComponent is a class that all your directshow
//code is in, and externalControl is the WinForms control you have embedded in
//your application.
dumbForm.Invoke(new InvokeHandler(delegate
{
//maybe something like this?
DSComponent.Start(externalControl);
}));
//and to stop it...
dumbForm.Invoke(new InvokeHandler(delegate
{
DSComponent.Stop();
}));
Then, when you're all done with the Directshow stuff, shutdown your separate application thread like so:
//to end the separate thread and application loop,
//just close your invisible form
dumbForm.Close();
Advantage of this approach is that you neatly sandbox directshow into a separate thread. Disadvantage is the context switch of the Invoke calls, plus the overhead of having another application thread. You may have some fun shoehorning this into your current architecture, but it should help.
Let me know how you get on, I am intrigued as to how well this works.

Having trouble creating a form on a second thread

I'm writing a plug-in for another application through C#.NET. Some of the processes my plug-in must perform are rather time consuming so I want to take advantage of multiple threads so I can show the user a progress bar of how the current task if progressing rather then the whole thing just hanging.
Typically the UI for something like this would be created in the main thread, and a secondary thread would be created to do the work, such as through the BackGroundWorker class. However, in my case the work must be done in the main thread because the application I'm writing the plug-in for isn't to happy with threads other then the thread it created for the plug-in accessing it.
So instead I'm creating a second thread to create my UI in (a WinForms Form), which then communicates back to the main thread to do any real work.
I'm able to create my Form in the main thread just fine, yet when I try to instantiate my form in the second thread I get an InvalidOperationException. This occurs in the designer file for the form where the name property of a column in a list view is being set.
Here are the details of the exception.
System.InvalidOperationException was caught
Message=ColumnInfo cannot be set.
Source=System.Windows.Forms
StackTrace:
at System.Windows.Forms.ListView.SetColumnInfo(Int32 mask, ColumnHeader ch)
at System.Windows.Forms.ColumnHeader.set_Text(String value)
at QA.Revit.RevitQAForm.InitializeComponent() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitQAForm.Designer.cs:line 758
at QA.Revit.RevitQAForm..ctor() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitQAForm.cs:line 34
at QA.Revit.RevitQAToolApp.FormMethod() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitModelCheckerCmd.cs:line 99
InnerException:
Update
I seemed to have gotten this working now by changing the ApartmentState of the secondary UI thread to STA. Although I'm totaly new to this multithreading stuff and have no idea what ApartmentState or STA means.
Here's my code.
//property used to store a reference to the form
internal RevitQAForm RevitQAForm { get; set; }
//monitor object that when pulsed shows the form
public static readonly Object showFormLock = new object();
//this method is called by the parent app when it starts
public Autodesk.Revit.UI.Result OnStartup(Autodesk.Revit.UI.UIControlledApplication application)
{
//this creates the form UI Thread
_formThread = new System.Threading.Thread(new System.Threading.ThreadStart(FormMethod));
_formThread.Name = "Form Thread";
_formThread.SetApartmentState(System.Threading.ApartmentState.STA);
_formThread.Start();
//returns that the plug-in startup succeeded
return Autodesk.Revit.UI.Result.Succeeded;
}
//the method is started on the second thread
private void FormMethod()
{
try
{
//creates the form
RevitQAForm = new RevitQAForm();
lock (showFormLock)
{
while (true)
{
//waits for a pulse
System.Threading.Monitor.Wait(showFormLock);
RevitQAForm.ShowDialog();
}
}
}
catch (System.Threading.ThreadAbortException)
{
//disposes the form if the thread is aborted
RevitQAForm.Dispose();
}
}
//this is called when the user request the form be shown
public void ShowForm()
{
lock (showFormLock)
{
System.Threading.Monitor.Pulse(showFormLock);
}
}
//this is called when the program closes
public Autodesk.Revit.UI.Result OnShutdown(Autodesk.Revit.UI.UIControlledApplication application)
{
//aborts the form thread
formThread.Abort();
return Autodesk.Revit.UI.Result.Succeeded;
}
Like I said this seems to work now. I'm able to start the app with my plug-in and show the form repeatedly. The form is also disposed when I close the program.
Yet now I'm trying to figure out how this form can communicate back to the main thread. The form will need to be able to trigger the main thread to start processing, the main thread will then need to be able to periodically report it's progress back to the form thread. At any point the form thread should be able to tell the main thread to cancel processing. Finally the main thread will need to notify the form when the processing is complete.
Any one have any tips on how I could do this?
This won't work. All forms need to use the underlying message pump in Windows, and to do that they need to be on the original thread.
To trigger the processing in main thread, you can use any WaitHandle derived class such as say ManualResetEvent/AutoResetEvent - essentially, Main thread will wait on to the wait handle and form thread can signal the event to start processing.
For communicating progress back from main thread to your UI/Form thread, you can use events or delegates. The simplest way would be to declare the process update delegate, instantiate it with some form's method. Then main thread can invoke it - which will essentially run the method within your form class (on main thread). Within this method, you must need to marshall call to your form's thread using Invoke method the form.
Try to call method, which uses
System.Windows.Forms.ListView.SetColumnInfo(Int32 mask, ColumnHeader ch)
by using method Invoke.

How do I communicate between multiple threads?

I'm writing a plug-in for another program which uses the native program to open a series of files to extract some data from. One problem I am having is the process takes a long time and I want to keep the user interface from hanging. Plus I also want to give the user the ability to cancel the process before it completes. In the past I've used a background worker for this type of thing, but in this case I don't think a BackgroundWorker will work.
To create a plug-in through the API I am using one can create a custom command by inheriting from an IAPICommand interface. This interface includes an Execute(Application app) method. The class is then instantiated and the Execute() method is called by the program when the user evokes the custom command in the program.
The Execute() method is passed a reference to the current Application object when it is called, and it is this application object that is used to open the files to extract data from. However, the application instance is not able to open a document when requested by a thread other the the original Execute() thread.
So typically the UI would exist on the main thread, and the time consuming data extraction would be performed on a secondary thread. However, in this case the data extraction must be performed on the main thread, and I need to create a secondary thread for the UI.
Here's a stripped down version of the code.
class MyCommand:IAPICommand
{
public void Execute(Application app) // method from IAPICommand
{
Thread threadTwo= new Thread(ShowFormMethod);
threadTwo.Start();
}
public void ProcessWidget(Widget w, Application app)
{
//uses an App to work some magic on C
//app must be called from the original thread that called ExecuteCommand()
}
//method to open custom form on a seperatethread
public void ShowFormMethod()
{
MyForm form = new MyForm();
form.ShowDialog();
}
}
Here is a flow chart that shows how I think this should ultimately work.
alt text http://dl.dropbox.com/u/113068/SOMLibThreadingDiagram.jpg
Does this diagram make any sense, and if so am I even taking the correct approach to solve this problem?
Once the main thread starts the UI thread I want it to wait for the user to either select widgets to process, or end the command by closing the form (the red figures on the diagram). How can I make the main thread wait, and how do I trigger it to continue either with processing or to continue to the end when the UI thread ends? I was thinking I could have the main thread wait on a Monitor lock. The UI thread would then populate a static list of Widgets to be processed, and then pulse the main thread to trigger the processing. The UI thread would also pulse the Main thread when the form is closed, and the main thread would know to continue to the end of the command if it was ever pulsed when the list of widgets to process was empty.
How do I allow the main thread to communicate the progress or completion of widget processing back to the UI thread (yellow arrows in the diagram)? Do I just used the BeginInvoke() method of the Form to do this?
How do I allow the UI thread to cancel the widget processing (green arrow in the diagram)? I think I could just setup a static Boolean flag that is checked before each widget is processed?
It's generally a bad idea to have multiple threads in your application that each create forms. It isn't impossible to make this work, but it's much harder than you think it will be because forms that are in a parent-child relationship send messages to each other, and when they do, the one sending the message blocks until the one receiving handles it.
Mix this in with the message passing or synchronization between threads that you are doing explicitly, and it's easy to end up with deadlocks. So, in general, you are better off making sure that you reserve your main thread for your user interface, and do all processing in other threads that have no UI.
If you conform to that design, then the background threads can use Control.BeginInvoke to pass messages to the UI thread without having to wait for the messages to be processed.
In addition to the other answers, I recommend that you use a callback method from ProcessWidget to pass progress back to the calling thread. To prematurely stop the worker thread, you can use the callback to return a halt signal to your worker thread if it updates the caller often enough. Or use a separate callback method to periodically check for go/no-go. Or set a (gasp!) global static flag that the worker periodically checks. Or call Thread.Abort on the worker thread and have it catch the ThreadAbortException to clean up any resources.
I assume that the host application is a WinForms app.
You need to save the SynchronizationContext from the original thread in your Execute method, then call its Send method to execute code on the host's UI thread.
For example:
class MyCommand:IAPICommand
{
SynchronzationContext hostContext;
public void Execute(Application app) // method from IAPICommand
{
hostContext = SynchronzationContext.Current;
Thread threadTwo = new Thread(ShowFormMethod);
threadTwo.Start();
}
public void ProcessWidget(Widget w, Application app)
{
//uses an App to work some magic on C
//app must be called from the original thread that called ExecuteCommand()
SomeType someData = null;
hostContext.Send(delegate { someData = app.SomeMethod(); }, null);
}
}
If you look at Java swing, it is a nice example of how to do this:
1) A main thread is responsible for handling all UI requests. This removes any race conditions from the app.
2) Any time any "work" is to be done, spawn a thread (or a thread pool) and do the work. Thus the main thread is not held up except for a few microseconds and the UI is completely responsive while whatever is going on.
3) In all languages there has to be a thread interrupt mechanism. In java you invoke .interrupt() on the thread, and the current running thread gets a InterruptedException thrown wherever it is executing. You job is to catch that exception, figure out if you are really interrupted (read javadocs for this part) and if you are just let yourself die (return out of the run method).
1 + 2 = unobtrusive client interaction
3 = killing threads
An alternative to 3 (if 3 is too complex) is to give the thread a method .kill(); the method sets a kill flag. When you are reading a buffer from the hard drive in a loop, check if the kill flag is set, if it is then break out of the loop, close handlers, and return out of the run method.
Edit: sorry forgot to mention progress report:
Your thread should have a publicly exposed thread-safe method of getting the "progress report" or rather a data structure containing information about progress. Your UI thread should periodically (say every .5 seconds) check the thread's progress report and update the UI's progress bar. And by UI thread checking I mean your widget that shows the progress makes a request to re-render with the latest information on a timer, until done.

C# Thread Pool Cross-Thread Communication

The Scenario
I have a windows forms application containing a MAINFORM with a listbox on it. The MAINFORM also has a THREAD POOL that creates new threads and fires them off to do lots of different bits of processing. Whilst each of these different worker threads is doing its job, I want to report this progress back to my MAINFORM, however, I can't because it requires Cross-Thread communication.
Progress
So far all of the tutorials etc. that I have seen relating to this topic involve custom(ish) threading implementations, whereas I literally have a fairly basic(ish) standard THREAD POOL implementation. Since I don't want to really modify any of my code (since the application runs like a beast with no quarms) - I'm after some advice as to how I can go about doing this cross-thread communication. ALTERNATIVELY - How to implement a different "LOGTOSCREEN" method altogether (obviously still bearing in mind the cross-thread communication thing).
WARNING:
I use this website at work, where we are locked down to IE6 only, and the javascript thus fails, meaning I cannot click accept on any answers during work, and thus my acceptance rate is low. I can't do anything about it I'm afraid, sorry.
EDIT:
I DO NOT HAVE INSTALL RIGHTS ON MY COMPUTER AT WORK.
I do have firefox but the proxy at work fails when using this site on firefox.
And no, funnily enough, I don't have the internet at home, I literally just moved to this city and the flat is a new build, so the address hasn't been registered with the post office, and thus the phone company cannot find the address on their system till they send a surveyor out, smarty pants.
FURTHER EDIT:
I DO NOT WANT TO CHANGE MY THREADING IMPLEMENTATION. AT ALL! - Accept to enable cross-thread communication....why would a backgroundworker help here!?
CODE RELATED EDIT:
Does it make a difference that when my THREAD POOL executes the new threads, it creates a new instance of a class and calls the entire thing on that new thread........i.e. your code example doesn't quite fit....i think?
Use the BackgroundWorker class in .NET and use the ProgressChanged and RunWorkerCompleted events to communicate back to your UI thread
Edit:
Sounds like you don't like BackgroundWorker, or just don't want to refactor. In that case, you have to check the InvokeRequired property on your form or one of your controls and if it is true, then you have to call Control.Invoke to force your UI update logic to occur on your main thread.
here is an example:
private void MyThreadFunction()
{
if (!InvokeRequired)
{
myLabel.Text = "You pushed the button!";
}
else
{
Invoke(new ThreadStart(MyThreadFunction));
}
}
You can use any delegate type to pass to Invoke, because it takes optional parameters that can be passed to your delegate when it is invoked on the main thread.
You could do something like this:
class MyForm : Form
{
private Label label = new Label();
private void DoWork()
{
// Do work ... Not in UI thread
// Update label... In UI thread
this.Invoke(new MethodInvoker(() => label.Text = "New Text!"));
}
}
The DoWork method it's the one running in your worker threads. You could check if an invoke is required using InvokeRequired property, but the assumption is that your code is running on worker threads so the invoke will always be required.
You can do this using delegate object.
So you would create a callback method in your MAIN form and let your CHILD forms call this method using delegates when they are done processing.
Try using Control.BeginInvoke to queue your update to the UI on the UI thread.

Categories

Resources