不导出成员函数时,从C#调用C ++本机/非托管成员函数

我有一个非托管DLL,只导出一个C风格的工厂方法,它返回一个类的新实例(这里简化为简单)。

hello.h

#if defined(HWLIBRARY_EXPORT) // inside DLL # define HWAPI __declspec(dllexport) #else // outside DLL # define HWAPI __declspec(dllimport) #endif struct HelloWorld{ public: virtual void sayHello() = 0; virtual void release() = 0; }; extern "C" HWAPI HelloWorld* GetHW(); 

HELLO.CPP

 #include "hello.h" struct HelloWorldImpl : HelloWorld { void sayHello(){ int triv; std::cout<>triv; }; void release(){ this->HelloWorldImpl::~HelloWorldImpl(); }; HelloWorld* GetHW(){ HelloWorld* ptr = new HelloWorldImpl(); return ptr; }; 

现在,我可以使用dllimport访问GetHW()但是有没有办法访问返回的’struct’的成员函数…即sayHello和release?

我也遇到了同样的问题。 这个问题之前被问过一段时间。 我评论它是为了更好的解决方案,但还没有得到任何答复。 所以,重新发布它。

当我用Google搜索时,能够找到两个解决方案。

解决方案1:为现有的dll公开C风格的所有成员函数。 我不能这样做,因为它是第三方dll。

解决方案2:编写一个托管C ++ DLL,公开本机C ++ DLL的function,以后可以在C#dll中使用。 这里有许多类/function。 因此,创建将花费大部分时间。

我从以下链接获得了上述解决方案。 如何马歇​​尔

除上述两种解决方案外,请告诉我是否有更好的解决方案?

我有C ++解决方案的源代码。 但我不是要触及C ++ DLL。 如果有可能在C#中做到这一点,那就太好了。

如果没有替代方案,我需要遵循指定的两个解决方案中的任何一个。

C ++代码使用Visual C ++编译器实现抽象类的方式。 http://blogs.msdn.com/b/oldnewthing/archive/2004/02/05/68017.aspx 。 此内存布局是“固定的”,因为它用于实现COM接口。 内存中结构的第一个成员将是一个指向包含方法的函数指针的vtable的指针。 所以对于

 struct HelloWorldImpl : public HelloWorld { public: int value1; int value2; } 

内存中的“真实”布局是:

 struct HelloWorldImpl { HelloWorldVtbl *vtbl; int value1; int value2; } 

其中vtbl将是:

 struct HelloWorldVtbl { void *sayHello; void *release; } 

只是为了做一个完整的响应,我正在为这个签名编写示例:

 struct HelloWorld { public: virtual int sayHello(int v1, int v2, int v3) = 0; virtual void release() = 0; }; 

C#代码:

 [DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr GetHW(); [StructLayout(LayoutKind.Sequential)] struct HelloWorldVtbl { public IntPtr sayHello; public IntPtr release; } 

你的函数是void Func(void)int Func(int, int, int) ,但实际上它们有一个隐藏的参数,所以你可以把它们写成:

 int sayHello(HelloWorld*, int, int, int); void release(HelloWorld*); 

所以在C#代表是

 [UnmanagedFunctionPointer(CallingConvention.ThisCall)] public delegate int Int32MethodInt32Int32Int32(IntPtr ptr, int v1, int v2, int v3); [UnmanagedFunctionPointer(CallingConvention.ThisCall)] public delegate void VoidMethodVoid(IntPtr ptr); 

然后你可以使用

 IntPtr ptr = GetHW(); IntPtr vtbl = Marshal.ReadIntPtr(ptr, 0); HelloWorldVtblhw = (HelloWorldVtbl)Marshal.PtrToStructure(vtbl, typeof(HelloWorldVtbl)); Int32MethodInt32Int32Int32 sayHello = (Int32MethodInt32Int32Int32)Marshal.GetDelegateForFunctionPointer(hw.sayHello, typeof(Int32MethodInt32Int32Int32)); int res = sayHello(ptr, 1, 2, 3); Console.WriteLine(res); VoidMethodVoid release = (VoidMethodVoid)Marshal.GetDelegateForFunctionPointer(hw.release, typeof(VoidMethodVoid)); release(ptr);