如何在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
相反,你必须使用本机样式(智能包装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
注意: 我在这些日子附近的任何地方都无法访问Windows机器,因此我引用了内存