Question

Brief:

How can I create two references in a .NET project to two ummanaged COM components that are identical except for their CLSID? They have the same ProgID, and the same Type Lib.

The Type Lib is what Visual Studio complains about when I attempt to create the second reference:

A reference to 'XXX Type Library' could not be added. A reference to this type library already exists. You must remove the reference 'XXX' before adding this one.

Thanks in advance.


Detailed:

I am creating a WPF application that provides integration with another application. The other application is a bit unusual in that its versions install as separate applications. Users can have multiple versions of the application running side by side on their computer.

My single WPF application is supposed to allow users to select the version of this other application they would like to work with. The other application has an unmanaged COM DLL for each version installed that I use to create the integration between my WPF app and this other application.

My WPF application has been working fine with the first version of the other application using a reference to the unmanaged COM component of version 1. The trouble starts when I try to reference the COM component of the second version.

I get the following error when I use “Add Reference” on the WPF project: A reference to 'XXX Type Library' could not be added. A reference to this type library already exists. You must remove the reference 'XXX' before adding this one.

An examination of the registry indicates that the only differences in the registry information for the two versions of the COM component are the CLSD and the path to the actual DLL. The ProgID and the TypeLib values are the same across both components.

As the versions of the other application are really treated as separate applications I would prefer the COM components to be installed as different applications and I’m working with company on the next release.

For now I’m stuck trying to get version 2 integrated into my WPF application. I’ve seen many posts about extern alias and how to manually edit the project file to introduce aliases, but they all seem to start with managed assemblies and not unmanaged COM components. The contents of the project file are different for referenced unmanaged COM components and as I can’t create the second reference, adding an aliases tag to the references in the project files doesn’t help me.

I’ve seen people talking about using System.Addin and reflection but I wanted to confirm there isn’t a more straightforward approach before investigating more complex approaches.

Thanks for reading this far!


Following CasperOne's advise I did the following:

  1. Ran the following using Visual Studio Command Prompt: tlbimp "c:\xxx1.dll" /out:"c:\NETxxx1.dll"
  2. Ran the following using Visual Studio Command Prompt: tlbimp "c:\xxx2.dll" /out:"c:\NETxxx2.dll"
  3. Added both newly created DLLs (Interop's I guess) as references to my test project. I used the 'Browse" tab to find them.
  4. I added code that pretty much followed casperOne's code sample.

I had a bit of a panic about what name to use for my COM interface. In the case of the COM object I'm using, there is one main interface object, and all other objects that I use from that COM object are instantiated from within that main interface object (I.E. I make calls like: Foo x = y.GetNewFoo();).

using X1 = NETXXX1; using X2 = NETXXX2; Guid clsid1 = new Guid("xxx..."); Type type1 = Type.GetTypeFromCLSID(clsid1); X1.IApplication a1 = (X1.IApplication)Activator.CreateInstance(type1); X1.FooList f1 =a1.GetFooList(); Guid clsid2 = new Guid("yyy..."); Type type2 = Type.GetTypeFromCLSID(clsid2); X2.IApplication a2 = (X2.IApplication)Activator.CreateInstance(type2); X2.FooList f2 = a2.GetFooList(); foreach(X1.Foo f in f1) Console.WriteLine(f.Name); Console.WriteLine("*****"); foreach(X2.Foo f in f2) Console.WriteLine(f.Name);

Was it helpful?

Solution

In this scenario, I would recommend against adding the reference through the "Add References" dialog in Visual Studio.

Instead, use the Type Library importer to generate the reference from the command line, and then set a reference to that in your project normally (it will be a .NET assembly).

Once you've done that, you'll have two sets of types, the set of interfaces that the two classes implement, as well as one of the class definitions of the implementation of those interfaces.

Instead of using the constructor to create this class, you would use the GetTypeFromCLSID method on the Type class to get the .NET Type for the COM object.

Then, you would use that Type in a call to Activator.CreateInstance (since all COM objects have default constructors, this will work) and cast the result to the interface definition, like so:

// The CLSID of the implementation you want to use.
Guid clsid = ...;

// Get the type.
Type type = Type.GetTypeFromCLSID(clsid);

// Create and cast to your interface.
var i = (IMyComInterface) Activator.CreateInstance(type);

When Activator.CreateInstance comes across a type that is a COM object, it creates a System.__ComObject (the root of all COM interop instances) which the CLR has support for (like calling IUnkown::QueryInterface when casting, like in the above code).

Also, if you are up for it, you could define the interfaces in your code, and then cast to those, you don't necessarily need the Type Library importer to generate them.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top