从C#导入C ++类方法

时间:2014-04-02 16:34:54

标签: c# c++ import interop pinvoke

我可以通过

从C#调用C ++包装器类
[DllImport("SomeDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void M();

我在C ++代码中的位置

extern "C" { __declspec(dllexport) BSTR GroupTerm(); }
void M() { /* Do Stuff */ }

这很有效,但由于多种原因,我想在方法中包含方法M

class SomeClass {
public: 
    void M();
}

我尝试过做

class SomeClass {
public:
   void __declspec(dllexport) M();
}

其中

void __declspec(dllexport) SomeClass::M() { /* Do Stuff */ }

但是C#代码(使用上面声明的导入的C#代码)找不到入口点并抛出异常。 我的问题是,如何导出此方法M() [这是SomeClass的公共成员,以便与C#的interop / pinvoke一起使用?

感谢您的时间。

3 个答案:

答案 0 :(得分:2)

有几种方法,都有不同的好处。

更简单的一个是为你的C ++类制作一个C-wrapper(我太懒了,不能放入装饰,你应该自己做)。

class SomeClass {
public: 
  void M();
};

void* MakeSomeClass() {return new SomeClass();}
void DestroySomeClassHandle(void* handle) { delete (SomeClass*)handle;}
void M(void* handle) { ((SomeClass*)handle)->M();}

然后像往常一样导入C函数。

这样做的好处是你不必做任何你目前不熟悉的事情。更多的东西(Matlab,Python,ect)有类似于PInvoke的东西,所以这使你的代码更具跨语言可用性。

缺点是这是超级错误,你扔掉了很多类型的安全。

更好的方法(imho)是为类

制作C ++ / CLI包装器
public ref class ManageSomeClass
{
public:
  ManageSomeClass() {myclass_ = new SomeClass();}
  !ManageSomeClass() { if (myclass) {delete myclass; myclass_ = NULL;} }
  ~ManageSomeClass() { this->!ManageSomeClass(); }
  void M() { myclass_->M();}
private:
  SomeClass* myclass_;
};

我使用SomeClass作为显示析构函数终结符的指针,但它不需要是指针。它可能是一个完整的实例。最重要的是,它将被编译成.NET类(在dll中),您可以将其导入到C#代码中。然后呼叫是:

//c# code
ManageSomeClass msc = new ManageSomeClass();
msc.M();

上行是从托管到非托管的灵活性。缺点是你突然维持另一个界面。如果你有继承/多态,你的包装器必须镜像该结构。这也是维持的噩梦。

编辑:另一个缺点是你必须学习C ++ / CLI,它是(kindof)和C ++的扩展,也是(kindof)一种完全不同的语言。

最后一种方法是通过COM接口。 http://msdn.microsoft.com/en-us/library/aa645736%28v=vs.71%29.aspx。您可以在C#中使用在C ++中使用的相同COM导入调用(有一些细微差别)来实例化和调用COM类。但是你需要学习COM(我从未做过),然后以COM投诉方式实现你的课程。但是你有一个COM接口,可以在整个Windows上导入。

答案 1 :(得分:1)

假设该方法是静态的,您有几个选择:

  1. 使用Dependency Walker之类的工具查找导入函数的名称。使用EntryPoint DllImport参数找到它。
  2. 使用.def文件导出该函数。然后,您可以完全控制导出的名称。
  3. 将方法包装在非成员函数中并导出该方法。
  4. 坦率地说,选项3是我要选择的。

    当您使用成员函数时,您需要导出接受实例指针作为其第一个参数的函数。而且您可能必须导出实例化对象的函数。

    那说,并回应您的意见,其他可能更好的解决方案是:

    1. 早期绑定COM,或
    2. C ++ / CLI包装器。

答案 2 :(得分:1)

另一种方法(除了@MadScienceDreams和@DavidHeffernan所说的)是将您的C ++代码转换为Windows运行时DLL,然后它可以在您的C#代码中使用。请参阅此处了解详细信息和示例:Creating Windows Runtime Components in C++

摘自链接:

  

文章介绍了如何使用C ++创建Windows运行时组件,   这是一个可以从构建的Windows应用商店应用程序调用的DLL   使用JavaScript或C#,Visual Basic或C ++

...

  

通常,在编写C ++组件代码时,请使用常规C ++   库和内置类型,但在抽象二进制接口除外   (ABI)边界,您将数据传入另一个的代码   .winmd包。在那里,使用Windows运行时类型和特殊   Visual C ++支持创建和操作它们的语法   类型。此外,在Visual C ++代码中,使用类型,如   委托和事件来实现可以从您的事件中触发的事件   组件并在JavaScript,Visual Basic或C#中处理。

以下是“使用C ++创建Windows运行时组件”的sample code