简体   繁体   中英

How do I link to a native class in a C++/Cli mixed-mode dll

I have the following setup:

  • CSharp.dll, a C# dll
  • CppCli.dll, a Mixed-Mode C++/Cli dll.
  • Native.dll, a native C++ dll.

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:

  • You can expose managed classes as COM objects, very simple to do with the [ComVisible] attribute. Possible to do directly from C#, you don't need the C++/CLI wrapper. The usual disadvantage is that the client code has to use COM to instantiate the object and make calls on it, not the kind of code that programmers like to write.
  • You can host the CLR yourself, the most efficient and flexible solution. This magazine article gives an introduction, beware that it is dated.
  • The C++/CLI compiler gives you a way to give you an unmanaged exported function that can execute managed code. It auto-generates a stub that gets the CLR loaded and initialized, if necessary.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM