0

I am working at WinForm Application which works fine with COM Object because it use single thread .But my system is also using progressBar which load data from COM Object ,here problem starts

  • GUI freezed during loading data (data getting from COM Object ) .

  • To Solve this problem ,i tried to use BackgroundWork which solved problem of freezed GUI .But Later i found BackgroundWork use Threadpool by default which create error in COM Object class because of Multithread .I had also tried this code create single ,but still not working

           Thread thread = new Thread(() => 
            {
                 Firmware_update_access();//it consumes Com Object
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
    

    COM component is dll which which creates exception when i try to run under new thread included (thread.SetApartmentState(ApartmentState.STA) .Exception is System.InvalidCastException: HRESULT: 0x80004002 (E_NOINTERFACE)). My Question is how we can create new a STA thread(other than UI thread) which should able use to COM object .

3
  • 1
    You provide nowhere near enough details in your question. You don't say what COM component, what does it do, or what error you're getting. "Not working" is not enough information. Commented Jul 28, 2017 at 14:16
  • COM component is dll which which create exception when i try to run under new thread included (thread.SetApartmentState(ApartmentState.STA) .Exception is System.InvalidCastException: HRESULT: 0x80004002 (E_NOINTERFACE)).' Commented Jul 28, 2017 at 15:42
  • DLL are from vigo software which helps to reads data from hardware Commented Jul 28, 2017 at 15:46

1 Answer 1

1

So, create, access and dispose you managed COM wrapper (RCW) in ONE dedicated background thread, i.e. all the COM wrapper access is done in the thread callback method.

Data or method calls have to be marshalled from/to the UI thread.

Update:

Depending on your performance and other requirements, you have two choices:

  1. Encapsulate the object creation, one or more consecutive method calls (RCW usage) and the object disposal in one thread call. So you can use the thread pool (e.g. Task.Factory.StartNew()) for every COM server call. You only have to ensure, that only one thread accesses the COM server at the same time, otherwise the threading issue occurs.
  2. Encapsulate the object creation, all method calls (RCW usage) and the object disposal in ONE dedicated background thread. You have to create a signalling mechanism to perform the COM server calls. A simple example is to use an enumeration for the different methods to be called, a queue and an event to wake-up the thread if there is a pending method call.

Example for choice 1:

Task.Factory.StartNew(() =>
{
  MyRCWType objServer = null;

  try
  {
    objServer = new MyRCWType(); // create COM wrapper object
    objServer.MyMethodCall1();
    objServer.MyMethodCall2();
  }
  catch(Exception ex)
  {
    // Handle exception
  }
  finally
  {
    if(objServer != null)
    {
      while(Marshal.ReleaseComObject(objDA) > 0); // dispose COM wrapper object
    }
  }
});

Example for choice 2:

private enum MethodCallEnum { None, Method1, Method2 };
private Queue<MethodCallEnum> _queue = new Queue<MethodCallEnum>();
private AutoResetEvent _evtQueue = new AutoResetEvent(false);
private object _syncRoot = new object();

private Thread _myRCWWorker;
private void CancellationTokenSource _cancelSource = new CancellationTokenSource();

// maybe in your main form
protected override void OnLoad(EventArgs e)
{  
  base.OnLoad(e);

  // create one and only background thread for RCW access
  _myRCWWorker = new Thread(() => DoRCWWork(_cancelSource.Token, _evtQueue));
  _myRCWWorker.IsBackground = true;
  _myRCWWorker.Start();
}

private void CallMethod1()
{
  Enqueue(MethodCallEnum.Method1);
}

private void Enqueue(MethodCallEnum m)
{
  lock(_syncRoot)
  {
    _queue.Enqueue(m);
  }
  _evtQueue.Set(); // signal new method call
}

private MethodCallEnum Dequeue()
{
  MethodCallEnum m = MethodCallEnum.None;

  lock(_syncRoot)
  {
    if(_queue.Count > 0)
      m = _queue.Dequeue();
  }      
  return m;
}

private void DoRCWWork(CancellationToken cancelToken, WaitHandle evtQueue)
{
  MyRCWType objServer = null;
  int waitResult;

  try
  {
    objServer = new MyRCWType(); // create COM wrapper object

    while (!cancelToken.IsCancellationRequested)
    {
      if(evtQueue.WaitOne(200))
      {
        MethodCallEnum m = Dequeue();
        switch(m)
        {
          case MethodCallEnum.Method1:
            objServer.MyMethodCall1();
          break;

          case MethodCallEnum.Method2:
            objServer.MyMethodCall2();
          break;
        }
      }
    }
  }
  catch(Exception ex)
  {
    // Handle exception
  }
  finally
  {
    if(objServer != null)
    {
      while(Marshal.ReleaseComObject(objDA) > 0); // dispose COM wrapper object
    }
  }
}

This is only a very simple example to show the program flow. You can trigger COM server calls from any thread by calling the Enqueue() method, but the COM server is accessed only from the dedicated thread.

Sign up to request clarification or add additional context in comments.

10 Comments

I don't have very good knowledge about marshaling .Would you Please give example of code or references .
My Com Object is STA .But i want use it in MTA by thread .I had tried to STA =thread.SetApartmentState(ApartmentState.STA); .But does't works
I had also read this learn.microsoft.com/en-us/dotnet/framework/interop/… . But i did not able manged this problem
@ KBO Thanks a lot for your efforts and time for help me
@ KBO .But my problem is still same ,Sytem creates same error which it creates when i had tried to create Object in new thread UI thread(without message loop) System.InvalidCastException: The 'COM. Object Com' object object can not be converted to the VigoOle.VigoStd interface. This action failed because QueryInterface called COM component of the interface with IID '{DBF5A8E4-1D0B-11D0-B597-0020AF38E834}' failed due to the following errors: Such an interface is not supported (Except from HRESULT: 0x80004002 (E_NOINTERFACE)) .
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.