问题描述
|
我正在尝试从C#应用程序(通过C ++ / CLI)调用C ++库。我遵循了这个问题的示例(针对我的特定应用)。我的应用程序的设置是:
Project1:C ++项目(我将其编译为DLL)
Project2:C ++项目(我的CLR包装器;仅上述示例中的头文件;引用Project1)
Project3:C#项目(引用Project2)
不幸的是,当我实际上去访问C#应用程序中的CLR包装器对象时,收到以下错误:
类型或名称空间名称\'YourClass \'
找不到(您是否错过了
使用指令或程序集
参考?)
我的项目设置是否有误,还是应该考虑其他事项? (不幸的是,由于专有原因,我无法发布代码,但这是一段非常简单的代码,可以轻松地遵循上述示例。)
更新:
因此,我完全按照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();
}
}
}
,好的,我现在觉得很蠢。
事实证明,我遇到的问题(几周前已经解决了-只是更新了这个答案)是我包含了头文件(有关此信息,请参见Chris的答案),但我没有实际上包含了CPP文件(除了包含头文件之外,该文件为空)。
完成此操作后,DLL将正确编译,并且可以从C#代码中调用C ++函数(使用C ++ / CLI)。
,克里斯向您展示了创建内部使用非托管代码的托管类的方法。您可以使用不安全的方法在C#中进行很多操作(几乎没有人可以做到)。
但是,也可以相反:直接从本机类型/函数使用.NET类型。
需要注意的是,任何托管指针都必须这样标记。为此,C ++ / CLI定义了一种特殊类型的smartpointergcroot<T>
(以某种方式模仿boost :: shared_pointer或std :: auto_ptr)。因此,要将托管字符串存储在C ++类中,请使用以下命令:
#include <string>
#include <vcclr.h>
using namespace System;
class CppClass {
public:
gcroot<String^> 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<Object^> 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<Object>(nullptr) ) {}
注意:最近几天,我都无法访问Windows计算机,因此我引用了内存