编译为托管的C++代码.NET(C++/CLI),否则作为本机C++



我有一个在Linux上编译的C++库,希望在Visual Studio中编译相同的代码(与.NET兼容的代码)。

我已经在Visual Studio中成功编译了相同的本机代码(不涉及图形)。不过,我想公开一些类。NET。我可以为某个非托管类编写一个托管包装器——如果我花了我没有的时间。然而,对于一些简单的类,似乎在的开头使用指令

#ifdef _MSC_VER
public ref class myclass
#else
class myclass
#endif 

可以做到这一点。代码在visualstudio中编译为托管代码,在其他情况下编译为本机代码。但是,有些涉及指针的类在编译时会返回错误。我知道"*"是非托管指针,"^"是托管指针。我可以定义吗

#ifdef _MSC_VER
#define POINTER ^
#else
#define POINTER *
#endif 

这是经常被修改的研究代码。编写包装器会很耗时,而且每次修改本机类时都需要修改包装器。因此,我更喜欢使用上面的条件语句(但我希望使用尽可能少的条件语句)。是否有编写本机C++和C++/CLI之间最大兼容代码的教程。

提前感谢

C++/CLI ref指针与*指针不同。不存在1对1的等价性。ref^指针指的是CLR中定义的"引用类型"(而不是"值类型")对象,它们可以用gcnew实例化。Gcnew非常重要,因为它告诉封送处理程序要创建的对象处于垃圾回收中,因此这些类型不能与本机代码一起使用,需要封送它们。但是,为了实际通过引用传递某些内容,例如,为了能够写回函数中传递的参数,您还需要使用%。。。所以Form ^myForm,如果被传递以获得返回值,则需要编写Form ^%myForm。

对您来说,最好的做法是编写一个包装器并使用混合汇编范式。

我不确定来自Linux C++代码,但要在Windows中从go一词开始做到这一点,你需要创建一个MFC C++库(或可执行文件),然后手动打开公共语言运行库,并手动向项目添加AssemblyInfo.cpp和app.manifest文件。

从那里开始,在您的代码中,有一个#pragma,用于定义代码的哪些部分是哪个。

对于运行本机或托管上下文之外的代码,您需要编写:

#pragma unmanaged

它告诉编译将此后的所有内容都视为非托管代码。

要为同一文件中的一段代码重新打开托管代码:

#pragma managed

等等。

事实上,您可能需要编写一个包装器。它不一定是一个完整的包装。。。也许只是一个入口点,返回你试图做的任何事情的最终结果。。。以及任何需要完成的唯一编程,都应该在混合汇编二进制文件中完成。NET类型,这些类型只针对最客观的任务公开。

我结束了对头文件的定义,该头文件允许我在托管(在Visual Studio下)或非托管模式下编译。

我必须做的另一个更改是删除类定义中的所有对象实例。例如,我必须将所有"string"对象更改为指针"string*"(然后还更改声明赋值等),这样它就可以编译为非托管代码和托管代码。

#ifndef COMMONHEADER_H_
#define COMMONHEADER_H_
#ifdef _MSC_VER
#define CLASS public ref class
#define POINTER ^
#define NEW gcnew
#define ARRAY(A, B) array<A ^> ^ B
#define VECTOR(A, B) array<A> ^ B
#define NEWARRAY(A, SIZE) gcnew array<A ^>(SIZE)
#define NULLPTR nullptr
#else
#define CLASS class
#define POINTER *
#define NEW new
#define ARRAY(A, B) A * * B
#define VECTOR(A, B) vector<A> * B
#define NEWARRAY(A, SIZE) new A*[SIZE];
#define NULLPTR NULL
#endif
#endif /* COMMONHEADER_H_ */

然后我继续在我的类定义中使用这些。我用POINTER替换了所有对象指针"*",用"new"替换了所有"new"实例,等等…

CLASS myclass
{
public:
MyObject POINTER obj1;
ARRAY(MyObject, objArray);
...

在某些情况下,我还必须为我的一些函数编写一个包装器。例如,下面要重载接受托管字符串的函数,并将其传递给接受非托管字符串作为输入的函数。

#ifdef _MSC_VER
bool saveToTxtFile(array<unsigned char>^ file) { pin_ptr<unsigned char> tmp = &file[0]; return saveToTxtFile((char *)tmp); }
#endif

或以下内容,以将非托管数据数组作为托管数据数组返回。

#ifdef _MSC_VER
array<double> ^ getValues() {
array<double> ^tmpArray = gcnew array<double>(numberOfSamples);
for (int ind1 = 0; ind1 < numberOfSamples; ind1++) tmpArray[ind1] = data[ind1];
return tmpArray;
}
#endif

我知道写一个完整的包装器比使用这个技巧更优雅,从长远来看可能更健壮。然而,我有大约2000行代码,这为我节省了很多时间,而不必为我的30个对象编写包装器。此外,通过这种方式,我不必维护包装器,以防更改类,也不需要将类的数量增加一倍。最后一个优点是,当我的代码被编译为托管代码时,我的所有对象都由垃圾收集器处理。

所以,总的来说,这不是最优雅的解决方案,但它是可能的,而且是有效的。

相关内容

最新更新