C
C#14mo ago
Eynix

❔ COM type library integration in C++ project

Hi everyone. I've made a dummy .net COM type library and I'm trying to integrate it in an equaly dummy C++ project. The project compile and link, but I have an _com_errorexception at runtime : Error in DLL. Here's the library code:
using System.Runtime.InteropServices;

namespace SomeClass
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface ComClass1Interface
{
}

[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ComClass1Events
{
}

[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(ComClass1Events))]
public class ComClass1 : ComClass1Interface
{
public static int Doubled(int i)
{
return i * 2;
}
}
}
using System.Runtime.InteropServices;

namespace SomeClass
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface ComClass1Interface
{
}

[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ComClass1Events
{
}

[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(ComClass1Events))]
public class ComClass1 : ComClass1Interface
{
public static int Doubled(int i)
{
return i * 2;
}
}
}
14 Replies
Eynix
Eynix14mo ago
and here's the C++ code:
#include <Windows.h>
#include <iostream>
#include <string>

#import "path\to\SomeClass.tlb" raw_interfaces_only

static std::string to_string(std::wstring const& s)
{
const int len = ::WideCharToMultiByte(CP_ACP, 0, s.data(), s.length(), NULL, 0, 0, NULL);
std::string str(len, '\0');
::WideCharToMultiByte(CP_ACP, 0, s.data(), s.length(), &str[0], len, 0, NULL);
return str;
}

int main()
{
CoInitialize(NULL);

try
{
SomeClass::ComClass1InterfacePtr object(__uuidof(SomeClass::ComClass1)); // Exception here
}
catch (_com_error const& e)
{
std::cout << to_string(e.ErrorMessage()) << std::endl; // "Error in DLL"
}

CoUninitialize();
}
#include <Windows.h>
#include <iostream>
#include <string>

#import "path\to\SomeClass.tlb" raw_interfaces_only

static std::string to_string(std::wstring const& s)
{
const int len = ::WideCharToMultiByte(CP_ACP, 0, s.data(), s.length(), NULL, 0, 0, NULL);
std::string str(len, '\0');
::WideCharToMultiByte(CP_ACP, 0, s.data(), s.length(), &str[0], len, 0, NULL);
return str;
}

int main()
{
CoInitialize(NULL);

try
{
SomeClass::ComClass1InterfacePtr object(__uuidof(SomeClass::ComClass1)); // Exception here
}
catch (_com_error const& e)
{
std::cout << to_string(e.ErrorMessage()) << std::endl; // "Error in DLL"
}

CoUninitialize();
}
I have no knowledge of either C# or .net, I am a C++ dev I'm completly lost
Eynix
Eynix14mo ago
yessir
Eynix
Eynix14mo ago
Eynix
Eynix14mo ago
and the dll seems registered; when it wasn't I had a "class not registered" exception this isn't the case anymore I've tryed to manually registered it using regasm, but it didn't change anything
RubyNovaDev
RubyNovaDev14mo ago
is COM your only option? because you could just write a C shim and make this infinitely easier
reflectronic
reflectronic14mo ago
can you send the Description of the _com_error instead ErrorMessage is going to give an unspecific message
Eynix
Eynix14mo ago
@RubyNova sadly yes. This is a library provided by a 3rd party. @reflectronic I've missed that apparently, I'll try to do that I've made a breakthrough yesterday. I figured that if I registered the dll manually (using regasm), I could in fact use the library. now, I'm trying to figure out how to write a manifest file so I don't have to register the dll. the _com_error Description() is NULL ok I just figured out what was going on apparently there's 2 ways to use COm interropt : by registering the dll or by using the dll as a "register free" component while the DLL was registered, my project was also configured (badly configured) to use it as a free component (as an isolated COM) and since I don't have a manifest file, it fails so here's what I've figured so far : There's at least 2 ways to use COM interrop DLL. 1. by registering the DLL, which requires admin rights 2. by directly using the DLL (with the #using instruction, which requires CLR enabled which means I'm limited to C++17 Is there any other way for me to use a COM dll in my (unmanaged) C++ project ?
reflectronic
reflectronic14mo ago
well, you can use reg-free by adding a manifest
reflectronic
reflectronic14mo ago
Tanveer Gani
C++ Team Blog
C++20 Support Comes To C++/CLI - C++ Team Blog
Details of C++20 support for C++/CLI introduced in VS 2022 17.6
Eynix
Eynix14mo ago
@reflectronic thank you yes, that's what I've tried in 2. problem is I use vs2019 and C++20 I can't downgrade to c++17 nor can I upgrade to vs2022 the manifest works great I managed to use a small COM lib I've made I have one last question on that topic : Let say the COM lib A uses lib B do I need to put lib B as a dependency of lib A in the manifest I generate for lib A ?
reflectronic
reflectronic14mo ago
the manifest is for COM classes that you want to activate in your process (technically you can have isolated manifests, but, the point stands). if lib A is loaded into your process and needs to activate COM classes in lib B, then lib B either needs to be registered or its classes need to be in your manifest if it’s just a regular library there’s no need. it’s strictly for COM classes so, if lib A and lib B are both .NET libraries, lib A probably uses lib B just through an assembly reference (not through COM). there would be no need for lib B to be in your manifest. just the classes you activate from your unmanaged app
Eynix
Eynix14mo ago
thank you very much
Accord
Accord14mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.