Search code examples
c#c++interoppure-virtual

How do I turn a C++ class into managed class and call the pure virtual function inside?


It looks likes this

#include <stdio.h>

#define __dllexport extern "C" __declspec(dllexport) 

class PureVirtual
{
public:
    virtual void Foo() = 0;
};

class ImplPureVirtual : public PureVirtual
{
public:
    void Foo()
    {
        printf("Moo");
    }
};

__dllexport PureVirtual* GetPV();

In implementation:

#include "ManagedClass.h"

PureVirtual* impl = new ImplPureVirtual;

__dllexport PureVirtual* GetPV()
{
    return impl;
}

It compiled as TestFoo.dll, Then in C#

class Program
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string strFileName);

    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string strProcName);

    static void Main(string[] args)
    {
        var ptrLib = LoadLibrary("TestFoo.dll");
        if (ptrLib != IntPtr.Zero)
        {
            var ptrAddr = GetProcAddress(ptrLib, "GetPV");
            if (ptrAddr != IntPtr.Zero)
                // Now we have the pointer object, what should I do next?
        }
        Console.ReadLine();
    }
}

I think it's a pretty good problem, that if a software company released their unmanaged API to the public(with only pure virtual method), and if we could control the wisdom of C++ abstractive and polymorphism, then we could make it into managed and have several benefit! Such as Garbage control, generics, and a wide choices of references and libraries.


Solution

  • You would also need to define an extern "C" function for each virtual member; managed code cannot call unmanaged C++ exports in an easy or portable way due to C++ name mangling. For example:

    __dllexport void PureVirtual_Foo(PureVirtual * pv)
    {
        pv->Foo();
    }
    

    Also, consider that you need to catch C++ exceptions in the extern "C" wrappers, because an uncaught exception can skip over managed stack frames, causing the CLR to get into a bad state.

    I would strongly suggest that you look into using SWIG. It is able to automatically generate these wrappers for you.


    Note that you do not need to use LoadLibrary() etc., you can just P/Invoke the function:

    [DllImport("TestFoo")]
    public static extern IntPtr GetPV();
    

    Likewise, to call the virtual method given my example wrapper:

    [DllImport("TestFoo")]
    public static extern void PureVirtual_Foo(IntPtr pv);
    

    Then you could call the virtual method like this:

    PureVirtual_Foo(GetPV());