注意:这篇文章代表我的询问问题#1。在两个问题中都会重复介绍块(所有文本,直到达到数字),因为它是回答问题可能需要的背景信息。
我有一个非托管C ++库,它包含几个“更高级别”库之间共有和共享的类和函数。我现在需要提供对C#/ .Net应用程序的公共库的访问。为此,我将使用C ++ / CLI包装类包装公共库。
公共库中包含的类可以是包含嵌套类定义和成员变量的复杂类,这些变量是其他类对象的集合。集合变量是用于管理集合的自定义列表类的typedef的实例。公共库还包括表示使用FLEX / BISON创建的自定义脚本文件语法的已解析结构的类。公共库和“更高级别”库都是以允许跨平台(Linux和GCC)编译和使用的方式编写的。我所做的任何改变都必须允许这样做。
C ++ / CLI包装器类首先只需要读取功能。但随着项目的进展,我最终还需要能够创建和修改对象。
我了解C ++ / CLI并为其他非托管C / C ++项目创建了几个包装器,并为这个公共库提供了抽象功能。所以我已经掌握了基础知识(以及一些高级知识)。
我有两个与执行此任务有关的问题,因为他们可以产生他们自己的讨论和解决方案,我将我的问题分成不同的帖子。我会在每篇文章中包含其他问题的链接。
如何在项目中构建文件?
非托管项目和C ++ / CLI项目之间的名称空间和类名称不会发生冲突。由于非托管项目使用类名称的“C”前缀而C ++ / CLI不使用。因此,非托管类CWidget
将变为Widget
。并且它们使用不同的根命名空间名称。
当涉及文件名时会出现问题。因为我的默认命名模式是对非托管和C ++ / CLI使用Widget.h
和Widget.cpp
。
项目当前已设置,项目的所有文件都位于项目文件夹的根目录中。头文件的包含仅作为标题的名称(例如#include "Widget.h"
)。为了适当地解析包含不同项目的文件,另一个项目的路径将添加到使用项目的Additional Include Directories
属性中。
如果我将Additional Include Directories
属性更改为解决方案的根(..\
)并将我的包含作为#include "Unmanaged\Widget.h
的非托管标头,我有一个新问题解析非托管标头中包含的标头。因此,使用该选项需要我将所有 include语句更改为其项目目录的前缀。我知道其他项目
重复文件名问题最明显/最快的解决方案是更改其中一个库的命名模式。因此,对于C ++ / CLI项目,不要使用Widget.h
和Widget.cpp
作为前缀或后缀m
(托管)或w
(包装器)。因此,C ++ / CLI文件将是mWidget.h
,wWidget.h
,WidgetM.h
或WidgetW.h
。然后我可以在整个过程中重复我现有的模式并保持良好状态。
但是有没有更好的方法来组织文件,以便我可以保留我的无/无后缀文件名,只需对现有代码进行最少的更改?
Wrapping an Unmanaged C++ Class Library with C++/CLI - Question 2 - Collections
答案 0 :(得分:3)
在包装非托管C ++ api时,我做了类似的事情。就我而言,即使是班级名称也是相同的。以下是我对项目的处理方式:
C:\Foo
C:\Foo\api
bar.h
)均以#include "api/bar.h"
Api::Bar
就我而言,花在项目上的大部分时间都是自动创建托管C ++文件。我手工做了几个,意识到用这样的方式做了多少时间,并开始自动化这个过程。
我的图书馆仍然是独立的。我有一个非托管DLL和一个托管DLL。我只是将非托管项目存储在托管项目下。
至于自动化,它将读取每个非托管的.h文件并创建我的托管.h文件,如下所示:
#include "api/bar.h"
行。#include
行。GetInner()
以获取非托管类指针。然后像这样创建托管的.cpp文件:
GetInner()
这适用于大多数类,只需要一点手动调整。它不起作用的一个领域是收集类。现在,我觉得我很幸运,因为每个集合类基本上都是std::vector
的包装器。我将所有托管版本都基于CollectionBase
,使用构造函数获取非托管集合类,以及具有以下签名的方法:
void ToFoo(Api::Foo& v);
因此,从非托管集合转到托管集合只是gcnew
,而另一种方式是:
Foo* foo; //most likely a function parameter, already assigned.
Api::Foo apifoo; //name just "api" + the name of the managed Foo.
foo->ToFoo(apifoo);
此类内容也构建在非集合类的.cpp类生成中。
ToFoo
的代码只是清除非托管集合,遍历托管集合并通过GetInner()
添加每个非托管项目。我的收藏品并不是那么大,所以这非常有效。
如果我不得不再次进行收集课程,我很可能不会立即将它们建立在CollectionBase
上。我更有可能将它们建立在List<T>
上,或者做一些与您在问题#2中发布的当前答案中讨论的内容类似的内容。我的代码是以.Net 1.1(没有泛型)开头的,所以当时CollectionBase
对我来说最有意义。
使用Regex手工卷制。由于库的编写非常一致,我能够读取整个文件,使用Regex删除注释和其他可能导致问题的内容(内联函数),然后只需读取每一行和Regex以找出其中的内容。我有类似所有集合的列表(知道何时进行上面的集合调用),异常类(string / std :: wstring)以及其他我不记得的事情。我将不得不看看它是否已成为我们新的源代码控制,因为该项目在几年前就被放弃了。