Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

COM and thread safety

I need to integrate an ASP.NET MVC website with a 3rd party COM application. The code looks something like this:

Type type = Type.GetTypeFromProgID(progID);
dynamic obj = Activator.CreateInstance(type);
if (!obj.DBOpenedStatus)
{
    obj.InitApplicationContext();
    //do stuff with other COM objects
}

The problem is that after a while I start getting COMExceptions most probably because I never close that context using obj.ReleaseApplicationContext(). So I'm thinking about writing a wrapper implementing IDisposable so that I can initialize the context in the constructor and release it when it's disposed. But then I would need a lock so that another thread would not close the context while the current thread is still working. The code would look like this:

lock (_locker)
{
    using (MyComContextWrapper comContext = new MyComContextWrapper())
    {
        //do stuff with other COM objects
    }
}

I know very little about thread safety so what I'm asking you is the following:

  1. Is there anything wrong with my approach?
  2. Is there anything else I should consider (like deadlocks or something else)?
  3. Would you recommend a different approach?

Edit 1:
I looked up the progID of the COM class in the registry and found that ThreadingModel=Apartment so the COM application uses a Single-Threaded Apartment type.

Edit 2:
The COM application uses a system to generate ids for objects so that when these objects are persisted in the database they already have an Id. This system involves writing some information in the registry. After a while something goes wrong with this system and I start getting violation of primary key constraint errors.

Edit 3:
I sometimes get a System.ArgumentNullException: Value cannot be null. Parameter name: type at Activator.CreateInstance(Type type). Could this be because I'm trying to create a new STA object from another thread?

Edit 4:
Someone asked me to post the full the full stack of the COMExceptions, but I'm afraid this will make my question too localized and useless for anyone else but me. Furthermore, I actually found the cause of the problem: there were some very rare cases when the context was not initialised before using some com objects and this messed up the system, but the errors only showed up at a later time. So I made sure that the context is always initialized prior to using any com object and the problem went away.

I'm still interested in an answer about thread safety and my proposed solution. Or maybe the question should be closed as too localized?

like image 556
david.s Avatar asked Dec 02 '12 12:12

david.s


1 Answers

You shouldn't need to use a lock around your objects as the whole purpose of COM Threading is making your life easier and automatic (once you understand its use, and if the registry is correct) in multi-threading environments.

In standard managed .NET scenarios, you don't need to do anything specific either, even releasing the COM object should be done automatically by the garbage collector. So you shouldn't need a using pattern.

That being said, it may be possible that the underlying unmanaged COM object works better when it's released once used, or maybe your application can't really wait for the GC to happen for some reason (because of a hi usage for example). In these scenarios, you can use Marshal.ReleaseComObject or Marshal.FinalReleaseComObject to force the release of the COM object once used, and wraps it using a wrapper object.

like image 74
Simon Mourier Avatar answered Oct 28 '22 00:10

Simon Mourier