Search code examples
c#.netcomappdomain

Multiple usages of ComImportAttribute in a single AppDomain


I have two libraries, as separate DLL's. These libraries don't ever reference each other directly, but there is a chance that they can exist in the same AppDomain.

This isn't an issue (it seems) until the use of ComImport[...] conflicts.

library1.file1.cs

namespace AudioSwitcher.AudioApi.CoreAudio.Interfaces
{
    [ComImport]
    [Guid(ComIIds.DEVICE_ENUMERATOR_CID)] //BCDE0395-E52F-467C-8E3D-C4579291692E
    internal class MultimediaDeviceEnumeratorComObject
    {
    }
}

library2.file2.cs

namespace AudioSwitcher.AudioApi.Hooking.ComObjects
{
    [ComImport]
    [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
    internal class MultimediaDeviceEnumeratorComObject
    {
    }
}

library2.somefile.cs

public void GetObject()
{
    //throws unable to cast exception
    var enumerator = new MultimediaDeviceEnumeratorComObject();
}

Exception:

Unable to cast object of type 'AudioSwitcher.AudioApi.CoreAudio.Interfaces.MultimediaDeviceEnumeratorComObject' to type 'AudioSwitcher.AudioApi.Hooking.ComObjects.MultimediaDeviceEnumeratorComObject'.

It seems that the first usage of ComImport "fixes" itself, and any request to create an object with that CLSID in the future returns that first used type.

This seems like a huge oversight, and could cause unexpected issues when interfacing a third party library from different places in code.

Does anyone know of a way to resolve this issue? I have a work around by creating an unknown instance, and casting it directly to an implemented interface. But it seems hacky.

Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E"))) as IMultimediaDeviceEnumerator;

EDIT: Source (if it helps): https://github.com/xenolightning/AudioSwitcher

The current working problem is in the AudioSession branch


Solution

  • I ended up not using ComImport and creating a ComObject "Factory" instead. Code for said factory is below. It allows loading of the same com type in different namespaces without any conflicts.

    internal static class ComObjectFactory
    {
    
        public static IMultimediaDeviceEnumerator GetDeviceEnumerator()
        {
            return Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(ComIIds.DEVICE_ENUMERATOR_CID))) as IMultimediaDeviceEnumerator;
        }
    
    }