I have the following setup:
The native project declares
class Native
{
public:
virtual void Add(int a);
};
which is implemented in the mixed mode project:
class Mixed : public Native
{
public:
virtual void Add(int a);
ICSharpInterface^ MakeManaged();
};
Since the base class is defined in Native, I can pass my implementation to other code in native. But now I want to test this class.
If I use #pragma make_public(Mixed);
it will only make a struct public, without any functions visible to the outside.
If I try to link to the mixed-mode dll from another mixed-mode dll, I get linker errors because it's a native class and the mixed-mode dll generates no .lib to link against.
And if I try to __declspec(dllexport)
the class, the Visual Studio complains because the interface exposes managed stuff.
So my question is:
How do I instantiate (link to) this class in my tests? I would be happy with any solution that shows how to create an instance where I can call its public interface on, doesn't matter if from C++, C++/Cli or from C#.
You are missing an important step, you haven't yet considered how a native program is going to create an instance of the Mixed object. Which is non-trivial, it does require getting the CLR loaded and initialized so it can execute managed code. Keep in mind that the client code does not do this automatically, it doesn't know beans about the CLR, it only knows about Native.dll. There are three basic ways to get this done:
Focusing a bit on the last bullet, since that's what you probably like, what you need here is a factory function, one that creates an instance of the Mixed class and returns a Native* back to the caller. So it can call ptr->Add() and invoke Mixed::Add(). That can look like this:
extern "C" __declspec(dllexport)
Native* CreateObject() {
return new Mixed;
}
Also gets you the import .lib that you can link in your native project. Do beware the disadvantages, they are significant. It is not exactly fast since the stub must check if the CLR is initialized yet and make the native-to-managed transition. The error reporting is extremely lousy since you have no decent way to diagnose exceptions that are thrown in the C# code. And memory management is an issue, the caller has to be able to successfully destroy the returned object which requires all modules to use the exact same CRT. The kind of problems that COM solves.
The exact same technique is available in C# as well by using an IL rewriter. Gieseke's unmanaged exports template is popular.