Monday, September 7, 2009

C# COM issue : "the application has called an interface that was marshalled for a different thread”

Hello people. I bled a little on something, so I thought I might share and save you some pain:

When calling code in a com class (for example, when using an external dll written in some other language (vb, for example), the implicit threading can be an issue)

VB by default uses STA threading (Single thread apartment), which loosely means that the application runs in one thread.
If you use the above class in C#, which by default uses MTA (Multi thread Apartment), You get an error : “the application has called an interface that was marshalled for a different thread” .

SO:

When you use such a dll in c#, you need to add the [STAThread] directive above your main program.cs file as follows:

namespace MYIDXApp
{
  class TimeServer
  {
    [STAThread]
    static void Main(string[] args)
    {
    }
  }
}


Furthermore:
There is a “feature” in c# that even though you specify that the main thread runs under STAThread, any timer events happen as MTAThread.

Thus, for a timer event, you must launch a new thread under STAThread as follows:

void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
  timer.Stop();

  //Classes.IDX_PI_Processing oProcessing = new Classes.IDX_PI_Processing(config);   // these have now been moved to a new thread due to the issue
  //oProcessing.ProcessPIQueue();
  Thread t = new Thread(new ThreadStart(StartNewStaThread));
  t.SetApartmentState(ApartmentState.STA); // this has to be done BEFORE the thread   //starts, else it is too late
  t.Start();
  t.Join();

  timer.Start();
}

private void RunProcessingClass()
{
  Classes.IDX_PI_Processing oProcessing = new Classes.IDX_PI_Processing(config);
  oProcessing.ProcessPIQueue();
}


for further reading:
http://www.developer.com/net/cplus/print.php/2202491

No comments:

Post a Comment