R
Reverend
What I thought would be a simple task has turned out to be touch (for me).
I have a COM ActiveX component from a 3d party vendor that I need to include
in one of our office applications. I have never worked with COM or ActiveX
objects in a C# program and my knowledge of the two technologies is very
limited.
The problem I'm experiencing is that my COM object is created on the
[STAThread] Main thread my application is started on. This makes the COM
object happy as it requires a STA thread. I then have events coming in from
various worker Threads from other parts of the application. These threads
are MTA and any attempts to work with the COM object result in a
InvalidActiveXStateException - this I understand is due to the fact we are
on a MTA thread.
The gist of the problem is that I need to marshal my ThreadPool invoked
events onto the original thread the COM object was created on. I have
experimented with using the SynchronizationContext class to store the
context that the COM object was created on, then marshal my events into that
context. The problem is System.Threading.SynchronizationContext.Current is
null in the Main() function.
As soon as I ran into trouble I backed off and started with a very simple
test application:
using System;
using System.Threading;
namespace ThreadContextTest
{
static class Program
{
private static FakeCOMObjectThatRequiresSTA _comObject;
[STAThread]
static void Main()
{
// Create the COM object
_comObject = new FakeCOMObjectThatRequiresSTA();
LogOperationContext("COM object created");
System.Threading.ThreadPool.QueueUserWorkItem(
new System.Threading.WaitCallback(OnDoSomething));
}
static void OnDoSomething(object state)
{
LogOperationContext("Event received");
try
{
// Try to work with the COM object
//
// This is where I need to get execution onto the thread
// that created the COM object.
_comObject.DoSomething();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static void LogOperationContext(string operation)
{
Console.WriteLine(String.Format(
"{0} on {1} thread {2}",
operation,
Thread.CurrentThread.GetApartmentState().ToString(),
Thread.CurrentThread.ManagedThreadId));
}
}
class FakeCOMObjectThatRequiresSTA
{
public FakeCOMObjectThatRequiresSTA()
{
CheckApartmentStateThrowIfNotSTA();
}
public void DoSomething()
{
CheckApartmentStateThrowIfNotSTA();
}
private void CheckApartmentStateThrowIfNotSTA()
{
if (Thread.CurrentThread.GetApartmentState()
!= ApartmentState.STA)
{
throw new Exception("Must be invoked in STA thread");
}
}
}
}
I would really appreciate any suggestion anyone might have. I will keep
reading and researching these new technologies, but a hint in the right
diretion would be awesome.
Thanks for reading!
I have a COM ActiveX component from a 3d party vendor that I need to include
in one of our office applications. I have never worked with COM or ActiveX
objects in a C# program and my knowledge of the two technologies is very
limited.
The problem I'm experiencing is that my COM object is created on the
[STAThread] Main thread my application is started on. This makes the COM
object happy as it requires a STA thread. I then have events coming in from
various worker Threads from other parts of the application. These threads
are MTA and any attempts to work with the COM object result in a
InvalidActiveXStateException - this I understand is due to the fact we are
on a MTA thread.
The gist of the problem is that I need to marshal my ThreadPool invoked
events onto the original thread the COM object was created on. I have
experimented with using the SynchronizationContext class to store the
context that the COM object was created on, then marshal my events into that
context. The problem is System.Threading.SynchronizationContext.Current is
null in the Main() function.
As soon as I ran into trouble I backed off and started with a very simple
test application:
using System;
using System.Threading;
namespace ThreadContextTest
{
static class Program
{
private static FakeCOMObjectThatRequiresSTA _comObject;
[STAThread]
static void Main()
{
// Create the COM object
_comObject = new FakeCOMObjectThatRequiresSTA();
LogOperationContext("COM object created");
System.Threading.ThreadPool.QueueUserWorkItem(
new System.Threading.WaitCallback(OnDoSomething));
}
static void OnDoSomething(object state)
{
LogOperationContext("Event received");
try
{
// Try to work with the COM object
//
// This is where I need to get execution onto the thread
// that created the COM object.
_comObject.DoSomething();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static void LogOperationContext(string operation)
{
Console.WriteLine(String.Format(
"{0} on {1} thread {2}",
operation,
Thread.CurrentThread.GetApartmentState().ToString(),
Thread.CurrentThread.ManagedThreadId));
}
}
class FakeCOMObjectThatRequiresSTA
{
public FakeCOMObjectThatRequiresSTA()
{
CheckApartmentStateThrowIfNotSTA();
}
public void DoSomething()
{
CheckApartmentStateThrowIfNotSTA();
}
private void CheckApartmentStateThrowIfNotSTA()
{
if (Thread.CurrentThread.GetApartmentState()
!= ApartmentState.STA)
{
throw new Exception("Must be invoked in STA thread");
}
}
}
}
I would really appreciate any suggestion anyone might have. I will keep
reading and researching these new technologies, but a hint in the right
diretion would be awesome.
Thanks for reading!