调用C ++从C#本地/非托管成员函数时,并没有出口成员函数
我有出口仅返回一个类的新实例(这里简化为简单的看)是C风格的工厂方法的非托管的DLL。
I have an unmanaged DLL that exports only a C style factory method that returns a new instance of a class (simplified here to look simple).
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
hello.cpp
#include "hello.h"
struct HelloWorldImpl : HelloWorld
{
void sayHello(){
int triv;
std::cout<<"Hello World!";
std::cin>>triv;
};
void release(){
this->HelloWorldImpl::~HelloWorldImpl();
};
HelloWorld* GetHW(){
HelloWorld* ptr = new HelloWorldImpl();
return ptr;
};
现在,我可以使用dllimport的访问GetHW(),但有没有访问成员函数的方式返回的'结构'...即sayHello的和释放的?
Now, I can use dllimport to access GetHW() but is there a way to access the member functions of the returned 'struct'... ie, sayHello and release?
我也坚持同样的问题。这个问题被问过一段时间。我要评论它的任何更好的解决方案,但没有得到任何答复呢。因此,重新张贴它
I was also stuck with the same problem. This question was asked a while before. I commented to it for any better solution but didn't get any reply yet. So, reposting it.
当我用Google搜索,能够找出两个解决方案
When i googled, able to find out two solutions.
解决方法1:公开所有在C风格对现有的dll的成员函数。 。我不能这样做,因为它是一个第三方的dll
Solution1: Expose all the member functions in the C-style for the existing dll. Which i cant do, as it is a 3rd party dll.
Solution2:写一个托管C ++ DLL暴露,后来可以用在本地C ++的dll,的功能,您C#DLL。在这里,许多类/函数都存在。这样,创建将采取的大部分时间。
Solution2: Write a managed C++ dll exposing the functionality of native C++ dll, which later can be used in your C# dll. Here many classes/functions are present. So, creating would take most of the time.
我得到从下方连结上述解决方案。
的如何马歇尔
i got the above solutions from the link below. How To Marshall
请让我知道是否还有比上述两种解决方案以外的任何更好的解决方案?
Please let me know if there is any better solution other than the above two solutions?
我对C ++的解决方案的源代码。但我虽然不碰C ++ DLL。如果有任何可能做到这一点在C#中,这将是巨大的。
i have the source code for C++ solution. But what i though was not to touch C++ dll. If there is any possibility to do it in C#, it would be great.
如果没有其他选择,我需要按照指定的两个解决方案中的任何一个。
If there is no alternative, i need to follow any one of the specified two solutions.
C ++代码使用抽象类是由Visual C ++编译器实现的方式。 http://blogs.msdn.com/b/oldnewthing /archive/2004/02/05/68017.aspx 。因为它是用于实现COM接口此存储器布局是固定。在内存中的结构的第一个成员将是一个指向包含你的方法函数指针一个虚函数表。因此,对于一个
The C++ code is using the way abstract classes are implemented by the Visual C++ compiler. http://blogs.msdn.com/b/oldnewthing/archive/2004/02/05/68017.aspx. This memory layout is "fixed" because it is used for implementing COM interfaces. The first member of the struct in memory will be a pointer to a vtable containing the function pointers of your methods. So for a
struct HelloWorldImpl : public HelloWorld
{
public:
int value1;
int value2;
}
在存储器中的真正的布局将是:
the "real" layout in memory would be:
struct HelloWorldImpl
{
HelloWorldVtbl *vtbl;
int value1;
int value2;
}
其中, VTBL
会是:
struct HelloWorldVtbl
{
void *sayHello;
void *release;
}
只是做一个完全反应的缘故,我写的例子这个签名:
Just for the sake of doing a complete response, I'm writing the example for this signatures:
struct HelloWorld {
public:
virtual int sayHello(int v1, int v2, int v3) = 0;
virtual void release() = 0;
};
C#代码:
C# code:
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetHW();
[StructLayout(LayoutKind.Sequential)]
struct HelloWorldVtbl
{
public IntPtr sayHello;
public IntPtr release;
}
您职能是无效Func键(无效)
或 INT Func键(INT,INT,INT)
,但实际上他们有一个隐藏的参数,这个
,所以你可以把它们写为:
Your functions are void Func(void)
or int Func(int, int, int)
, but in truth they have a hidden parameter, this
, so you can write them as:
int sayHello(HelloWorld*, int, int, int);
void release(HelloWorld*);
因此,在C#中的委托是
so in C# the delegate is
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int Int32MethodInt32Int32Int32(IntPtr ptr, int v1, int v2, int v3);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate void VoidMethodVoid(IntPtr ptr);
然后你可以使用
Then you can use
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);