We have a .NET DLL that contains several COM classes and objects that partner companies can use. We currently use regasm
to register the COM classes in the registry. This has worked for years.
We now want to get rid of the COM registration and use side by side assemblies. I am currently trying to make this transition, but I seem to fail on the finish line. We deliver a sample application in C++ that uses our COM classes, and I try to get it to run without COM registration.
.NET DLL
In our .NET DLL, I have a class like this:
namespace MyNamespace
{
[ComVisible(true)]
[Guid("ef828ade-b459-4446-80db-956715588601")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MyVendor.MyClass")]
public partial class MyClass
{
}
}
Application assembly
The C++ sample application that shall work with this COM class has a manifest like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="x86"
publicKeyToken="6595b64144ccf1df"
language="*" />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="MyComDll.X"
version="1.0.0.0" />
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"
uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
DLL assembly
And the .NET DLL itself has a manifest to expose the COM class to the outside world:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"
name="MyComDll.X"
version="1.0.0.0" />
<file name="MyComDll.dll">
<comClass description="MyVendor.MyClass"
clsid="{ef828ade-b459-4446-80db-956715588601}"
progid="MyVendor.MyClass.1"
threadingModel="Both">
<progid>MyVendor.MyClass</progid>
</comClass>
</file>
</assembly>
Using COM
I obviously use proxy names in my code samples above, but I made sure the all names in the original code are valid.
In our sample C++ code, we are getting the CLSID and creating the instance of the class this way:
HRESULT hr = CLSIDFromProgID(OLESTR("MyVendor.MyClass"), &clsid);
hr = CoCreateInstance(clsid, nullptr, CLSCTX_SERVER, IID_IDispatch, (void**)(&_pMyClass));
What goes wrong
I use some debug output to check the GUID that was returned from CLSIDFromProgID()
and to check the return value. If the COM class is registered using regasm
, the return value is S_OK
and clsid
is the same GUID that I specified in my .NET DLL for the class.
However, if I remove the COM registration and use the side by side assemblies with manifests as shown above, I also get the S_OK
return value, but the GUID is something entirely different, and therefore I cannot create an instance of this class. I have not found the GUID I get from CLSIDFromProgID()
anywhere - neither in the registry nor in my development solution.
Do you have any idea what I made have done wrong?
S_OK
from CLSIDFromProgID()
, so I know the ProgID is found - it just delivers the wrong CLSID.StringFromCLSID()
to compare the CLSID that was found by `CLSIDFromProgID().First of all, I want to thank Joseph Willcoxson and Remy Lebeau for pushing me in the right direction!
I had a couple of minor issues in my manifests that I could resolve one after another. The big mistake I made was taking the assumption that a CLSID that I get from CLSIDFromProgID is the same as the one I specified in my .NET COM class. After it was pointed out that is not necessarily the case, I did not waste any further time and checked why calling CoCreateInstance failed. It turned several iterations of online research and testing to figure out the mistakes I made.
As Joseph pointed out, I should have used clrClass instead of comClass. I made mistakes configuring the clrClass. For instance, I used the same name for "name" that I used for "progId", but the "name" in a clrClass is the full namespace + class name.