Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
呼叫C++;未导出成员函数时,来自C#的本机/非托管成员函数_C#_C++_Interop - Fatal编程技术网

呼叫C++;未导出成员函数时,来自C#的本机/非托管成员函数

呼叫C++;未导出成员函数时,来自C#的本机/非托管成员函数,c#,c++,interop,C#,C++,Interop,我有一个非托管DLL,它只导出一个C风格的工厂方法,该方法返回一个类的新实例(这里简化为看起来简单) 你好,h #if defined(HWLIBRARY_EXPORT) // inside DLL # define HWAPI __declspec(dllexport) #else // outside DLL # define HWAPI __declspec(dllimport) #endif struct HelloWorld{ public: virtu

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

你好,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();
你好,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;
};
#包括“hello.h”
结构HelloWorldImpl:HelloWorld
{
void sayHello(){
int triv;
std::couttriv;
};
无效释放(){
这->HelloWorldImpl::~HelloWorldImpl();
};
HelloWorld*GetHW(){
HelloWorld*ptr=新的HelloWorldImpl();
返回ptr;
};
现在,我可以使用dllimport来访问GetHW(),但是有没有办法访问返回的“struct”的成员函数…例如,sayHello和release

我也遇到了同样的问题。这个问题之前有人问过。我对它发表了评论以寻求更好的解决方案,但还没有得到任何答复。因此,重新发布它

当我在谷歌上搜索时,我发现了两个解决方案

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

解决方案2:编写一个托管C++ DLL,公开了本机C++ DLL的功能,稍后可以在C语言的DLL中使用。这里有许多类/函数。因此,创建将占用大部分时间。 我从下面的链接中得到了上述解决方案。

请告诉我除了上述两种解决方案之外,还有没有更好的解决方案

我有C++解决方案的源代码,但我不想触摸C++的DLL。如果有可能在C语言中做,那就太好了。


<> P>如果没有其他选择,我需要遵循任何一个指定的两个解决方案。

< P> C++代码是使用VisualC++编译器实现抽象类的方式。这个内存布局是“固定的”因为它用于实现COM接口。内存中结构的第一个成员将是指向包含方法的函数指针的vtable的指针

struct HelloWorldImpl : public HelloWorld
{
   public:
    int value1;
    int value2;
}
内存中的“真实”布局是:

struct HelloWorldImpl
{
    HelloWorldVtbl *vtbl;
    int value1;
    int value2;
}
struct HelloWorldVtbl
{
    void *sayHello;
    void *release;
}
其中
vtbl
将是:

struct HelloWorldImpl
{
    HelloWorldVtbl *vtbl;
    int value1;
    int value2;
}
struct HelloWorldVtbl
{
    void *sayHello;
    void *release;
}
为了做一个完整的回答,我正在为以下签名编写示例:

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

您的函数是
void Func(void)
int Func(int,int,int)
,但实际上它们有一个隐藏参数,
this
,因此您可以将它们写成:

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);

<> > C++代码使用VisualC++编译器实现抽象类的方法。这个内存布局是固定的,因为它用于实现COM接口。内存中的第一个成员将是指向包含方法指针的VTABLE的指针。因此,对于

struct HelloWorldImpl : public HelloWorld
{
   public:
    int value1;
    int value2;
}
内存中的“真实”布局是:

struct HelloWorldImpl
{
    HelloWorldVtbl *vtbl;
    int value1;
    int value2;
}
struct HelloWorldVtbl
{
    void *sayHello;
    void *release;
}
其中
vtbl
将是:

struct HelloWorldImpl
{
    HelloWorldVtbl *vtbl;
    int value1;
    int value2;
}
struct HelloWorldVtbl
{
    void *sayHello;
    void *release;
}
为了做一个完整的回答,我正在为以下签名编写示例:

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

您的函数是
void Func(void)
int Func(int,int,int)
,但实际上它们有一个隐藏参数,
this
,因此您可以将它们写成:

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);

看一看你正在用这段代码重新发明COM。但是它不兼容COM,所以不能直接从C#程序中使用。正确地使用C++/CLI包装器是必需的。看一看你正在用这段代码重新发明COM。但是它不兼容COM,所以不能直接从C#程序中使用。需要C++/CLI包装器来完成it正确。非常感谢您给出详细的答案。我将尝试实现同样的答案。:@chandrakanth注意
this->HelloWorldImpl::~HelloWorldImpl()
将泄漏内存:参见示例。您应该
删除此项;
非常感谢您给出了详细的答案。我将尝试实现相同的功能。:@chandrakanth注意
此->HelloWorldImpl::~HelloWorldImpl()将泄漏内存:参见示例。您应该
删除此项;