如何在C#应用程序中使用C ++ / CLI

我试图从我的C#应用​​程序(通过C ++ / CLI)调用我的C ++库。 我按照这个问题的例子(针对我的具体应用)。 我的应用程序的设置是:

  • Project1:C ++项目(我将其编译为DLL)
  • Project2:C ++项目(我的CLR包装器;只是上面示例中的头文件;引用Project1)
  • Project3:C#项目(参考Project2)

不幸的是,当我真的去访问我的C#应用​​程序中的CLR包装器对象时,我收到以下错误:

找不到类型或命名空间名称’YourClass’(您是否缺少using指令或程序集引用?)

我是否错误地设置了项目,或者是否还有其他我需要研究的内容? (不幸的是,我不能出于专有原因发布代码,但这是一个非常简单的代码,很容易遵循上面的例子。)

更新:

所以我完全按照Chris的说法做了(请参阅下面的答案),但我仍然收到来自我的C#应用​​程序的消息“找不到类型或命名空间名称’MyProgram’(您是否缺少using指令或程序集)参考?)。这是我的代码的(模拟)。

  • Project1 – 这是我的C ++应用程序。 它编译/工作。 我在其他地方用过它。 (我从这个版本中获取了一个DLL。)
  • Project2 – 这是我的包装器的代码。

MyWrapper.h

#pragma once #include "myorigapp.h" using namespace System; namespace MyProgram { public ref class MyWrapper { private: myorigapp* NativePtr; public: MyWrapper() { NativePtr = new myorigapp(); } ~MyWrapper() { delete NativePtr; NativePtr = NULL; } void dostuff() { NativePtr->dostuff(); } } } 
  • Project3 – 这是我的C#应用​​程序。

Program.cs中

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyProgram; namespace Testing { class Program { static void Main(string[] args) { MyWrapper p = new MyWrapper(); p.dostuff(); } } } 

Project3引用引用Project1的Project2。 一切都没有错误构建(除了上面在using MyProgram线的C#代码中描述的错误)。

仅仅包含纯C ++应用程序的头文件就不够好了。 您需要在Project2中使用托管对象包装非托管对象(即public ref class YourClassDotNet

 #include "YourHeader.h" namespace MyManagedWrapper { public ref class YourClassDotNet { private: YourClass* ptr; public: YourClassDotNet() { ptr = new YourClass(); } ~YourClassDotNet() { this->!YourClassDotNet(); } !YourClassDotNet() { delete ptr; ptr = NULL; } void SomeMethod() { ptr->SomeMethod(); } } } 

好吧,我现在感到愚蠢。

事实certificate,我所遇到的问题(几周前我解决了 – 只是更新了这个答案)是因为我已经包含了头文件(请参阅Chris的答案),但我实际上没有包括CPP文件(除了包含头文件之外是空的)。

一旦我这样做,DLL编译正确,我可以从我的C#代码调用C ++函数(使用C ++ / CLI)。

Chris向您展示了创建使用非托管代码的托管类的方法。 你可以在C#中使用不安全的东西(很少有人这么做)。

但是,反过来也是可能的:直接从本机类型/函数使用.NET类型。

需要注意的是,任何托管指针都必须标记为这样。 为此,C ++ / CLI定义了一种特殊类型的smartpointer gcroot (在某种程度上模仿boost :: shared_pointer或std :: auto_ptr)。 因此,要在C ++类中存储托管字符串,请使用以下命令:

 #include  #include  using namespace System; class CppClass { public: gcroot str; // can use str as if it were String^ CppClass(const std::string& text) : str(gcnew String(text.c_str())) {} }; int main() { CppClass c("hello"); c.str = gcnew String("bye"); Console::WriteLine( c.str ); // no cast required } 

请注意(如果这些天没有修复),您将遇到托管null和C / C ++ NULL之间不匹配的摩擦。 您无法像预期的那样轻松打字:

 gcroot the_thing; ... if (the_thing != nullptr) ... } 

相反,你必须使用本机样式(智能包装gcroot处理这个)

 gcroot< Object^ > the_thing; if ( the_thing != NULL ) {} // or equivalently... if ( the_thing ) {} // not too sure anymore, but I thought the following is also possible: if ( the_thing != gcroot(nullptr) ) {} 

注意: 我在这些日子附近的任何地方都无法访问Windows机器,因此我引用了内存