I am trying to call a .NET 4.0 dll from unmanaged C++ code.
I followed the instructions in this Code Project article by Atul Mani.
I built the .NET dll, and followed all the steps up to and including registering it with regasm.
Next, I created an unmanaged C++ project and added this line at the start of the .cpp file:
#import "D:\PathToMyCSharpProject\bin\Debug\com.DeviceServices.tlb" rename ("EOF","adoEOF") no_namespace named_guids raw_interfaces_only
When I built the C++ project, a .tlh file was created in D:\MyCPlusPlusProject\Debug.
Next, I added the code suggested by the CodeProject article, which tries to create a pointer to an object from the C# library.
CoInitialize(NULL); //Initialize all COM Components
// <namespace>::<InterfaceName>
MyCSharpNamespace::IMyCSharpInterfacePtr pMyCSharpInterfacePtr;
"MyCSharpNamespace" is the namespace that I used in the C# project.
When I build the C++ project, I now get a compile error:
Error 2 error C2653: 'MyCSharpNamespace' : is not a class or namespace name
Also other errors because it doesn't recognise IMyCSharpInterfactPtr.
So, I looked into the .tlh file, and the contents are as follows:
// Created by Microsoft (R) C/C++ Compiler Version 10.00.40219.01 (6478e0c7).
//
// MyCPlusPlusProjectPath\debug\com.deviceservices.tlh
//
// C++ source equivalent of Win32 type library MyCSharpProjectPath\bin\Debug\com.DeviceServices.tlb
// compiler-generated file created 05/27/14 at 11:52:16 - DO NOT EDIT!
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
//
// Forward references and typedefs
//
struct __declspec(uuid("961b3c24-98f2-400e-8bea-ab357a18d851"))
/* LIBID */ __MyCSharpProject;
//
// Named GUID constants initializations
//
extern "C" const GUID __declspec(selectany) LIBID_MyCSharpProject =
{0x961b3c24,0x98f2,0x400e,{0x8b,0xea,0xab,0x35,0x7a,0x18,0xd8,0x51}};
#pragma pack(pop)
I searched on the internet to find out what should be in the .tlh file, and found the #import page at msdn.
It says that the contents of the .tlh file should include smart pointer declarations (i.e. IMyCSharpProjectInterfacePtr) and typeinfo declarations, that are not present in my .tlh file.
MyCSharpProject declares a public interface, includes a generated GUID, builds correctly, and all the steps that I followed from the article appeared to be successful.
So, my question is, can someone suggest why these definitions aren't present in my .tlh file that should be there?
A .tlh file cannot be wrong, it is auto-generated from the type library of your COM server. An obvious flaw is that it is rather empty, you don't see any declarations at all.
The problem is with that Codeproject.com article, par for the course in such projects is that it is missing an essential step, doesn't explain what is really going on and often uses very bad practices. In order for a .NET type to be usable from a COM client, you have to be explicit about making it visible to COM clients. Add this attribute to every type that you want to export:
[ComVisible(true)]
Apply it to both the interface and the class.
Using the [Guid] attribute, like the author proposes, is very dangerous. It is okay to leave it in place while you are developing the library, it helps avoid registry pollution and lets you skip the Regasm step (not always), but it is pretty important to remove it again before you ship the library. A rock-hard rule in COM is that a modification to an interface requires a new guid, an essential DLL Hell counter-measure. You automatically get a new one when you leave it up to the CLR to auto-generate one.
Registering the assembly in the GAC is also best avoided while you are developing, it causes too many accidents with leaving a stale copy of the assembly in the GAC. Use the /codebase
option in the Regasm command so this is not needed. You can ignore the warning you get.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With