[.net] Threading woes, STA COM calls on MTA application.

Started by
5 comments, last by Jonny_S 14 years, 1 month ago
Hi, I'm pretty new to this winforms lark so please excuse my stupidity. I'm using the .NET debugging api's (MdbgEng.dll, corapi.dll etc) which require the app to be run on an MTA thread. However I'm linking this debugging functionality to a WinForms GUi which is supposed to be run under an STA thread (I think?). So my problem is the nice COM dialogs I want to use on the GUI are bombing out. Is there any way around this? I hate threading! Thanks Jon
Advertisement
Create a separate thread to run your debugging commands on, and call SetApartmentState on it to change it to MTA. If you want to run GUI commands on that thread, you must use the Invoke or BeginInvoke methods on your WinForms objects.
That's what I've tried, basically I have a GUI at the front end, a "controller" class in the middle that handles events from both GUI and Debugger and obviously the debugger at the back end.
So the controller class creates a debugger thread (it's always done that) however when I set the apartment state to MTA it still seems to run as an STA thread.
What's even more odd is if I set the MTAThread attribute on the MainMethod and create a thread for the GUI which is STA then the debugger still falls over as if it's running as an STA thread...

Any clues? I know it's hard without code but it's for a university project so I can't ask for an answer as such, just pointers.
What makes you think it runs in STA? Are you setting the apartment state before calling Start on it? Have you checked GetApartmentState on the thread after starting it? You might check Thread.CurrentThread.GetApartmentState in the method that fails to make sure it's running on the thread you think it is.
Thanks for the advice kanato, I'm embarrassed I didn't think about that myself. My problem is that when the UI requests data from the Debugger (such as variable info or to add a breakpoint). The operation is carried out on the STA UI thread and not the MTA debugger thread. I know on the UI side you can ensure that the operation is running on the correct thread using InvokeRequired and Invoke/BeginInvoke. How do I do something similar on my Debugger thread?

Thanks

Jonathan

[edit]
The way around this that I see is the debugger has delegates for any operations coming from the UI that are called using BeginInvoke, is there any better way around this?

[Edited by - Jonny_S on February 18, 2010 3:24:26 PM]
Ah, yes. You can write your own Invoke and BeginInvoke methods to handle this sort of thing. A general way to do that sort of thing would be like this:

class DebuggerThreadInterface{    Thread myThread;    List<MethodToInvoke> methods = new List<MethodToInvoke>();    class MethodToInvoke    {        public Delegate Method;        public object[] Args;    }    // Check to see if the method being called is on the correct thread    public bool InvokeRequired { get { return Thread.CurrentThread != myThread; } }    public void BeginInvoke(Delegate method, params object[] args)    {        lock(methods)        { methods.Add( new MethodToInvoke { Method = method, Args = args } ); }    }    public void Invoke(Delegate method, params object[] args)    {        MethodToInvoke x = new MethodToInvoke { Method = method, Args = args } );        lock(methods) { methods.Add(x); }        bool executed = false;                while (!executed)        {            Thread.Sleep(10);            lock(methods) { executed = !methods.Contains(x); }        }    }    void ThreadMain()    {        while(shouldRunThread)        {            ExecuteMethods();                     // do important stuff, and maybe call Thread.Sleep        }    }    void ExecuteMethods()    {        lock(methods)        {            while (methods.Count > 0)            {                methods[0].Method.DynamicInvoke(args)                methods.RemoveAt(0);            }        }    }}


This assumes the MTA thread is run on the DebuggerThreadInterface.ThreadMain method, and that method runs in a loop that maybe checks stuff, sleeps when it needs to, so that it can check to see if methods have been added to the invoke list. Depending on your needs, you may benefit from an approach which is more tailored to your problem domain.

(Note: I wrote the above code off the top of my head and it's untested, and may not be the best thread handling code avaialble. Use at own risk :)
Thanks very much kanato, I'll take a look at your code and see if I can't work out a nice solution.

This topic is closed to new replies.

Advertisement