结束语非托管C ++类库用C ++ / CLI - 问题1 - 项目/ code组织 [英] Wrapping an Unmanaged C++ Class Library with C++/CLI - Question 1 - Project/Code Organization

查看:238
本文介绍了结束语非托管C ++类库用C ++ / CLI - 问题1 - 项目/ code组织的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:这篇文章再presents问题#我的查询1。引入块(直到数量也达到了所有的文本)中被重复这两个问题,因为这是可能需要回答的问题的背景资料。


介绍到问题

我有++库,其中包含类和函数是共同的,并在几个更上一层楼库共享的托管C。我现在需要提供给C#/。NET应用程序访问的公用库。要做到这一点,我将不得不换用C ++ / CLI的包装类的公用库。

中包含的公共库类可以是包含嵌套类的定义和成员变量是其它类对象的集合复杂的类。集合变量是一个自定义列表类用于管理集合类型定义的实例。公共图书馆还包括重新present使用FLEX /野牛创建一个自定义的脚本文件语法的分析结构类。公共库和更高层次的库都写在一个时尚,允许跨平台(Linux和GCC)编译和使用。我所做的任何更改仍然必须考虑到这一点。

在C ++ / CLI的包装类起初只需要读取能力。但随着项目的推进,我最终需要能够创建和修改的对象也是如此。

我知道C ++ / CLI和创造一些包装对于其他非托管的C / C ++项目,以及提供抽象的功能,同样的公共库。所以我的基础知识(和一些先进的知识)了。

我有相关的执行这项任务两个问题,因为它们既能产卵自己的讨论和解决方案,我分裂我的问题到不同的岗位。我将包括链接到每个岗位的另一个问题。


实际问题

  1. 我如何在项目中构建我的文件?

    • 非托管和C ++ / CLI的项目不会冲突之间的命名空间和类名。由于非托管项目采用CpreFIX的类名,而C ++ / CLI没有。因此,非托管类 CWidget 将成为刚刚控件。他们使用不同的根命名空间的名称。

    • 这个问题来当文件名都在关注。作为我的默认命名模式是使用 Widget.h Widget.cpp 这两个非托管C ++ / CLI。

    • 该项目目前的设置,其中该项目的所有文件都在项目文件夹的根目录。包含头文件的完成作为标题(如的#includeWidget.h)的只是名字。并妥善解决包括对不同项目的文件,其他项目的路径将被添加到附加包含目录的使用项目的属性。

    • 如果我改变我的附加包含目录属性为解决方案的根目录(<$ C C $> .. \ ),并尽我包括对于#include不受管理的\ Widget.h 非托管的标题为,我已经包含在非托管头解析头的一个新的问题,所以使用选择要求我改变的所有的包含语句preFIX他们的项目目录。我知道其他项目

    • 最明显的/最快的解决了重复文件名的问题是改变了命名模式的图书馆之一。而不是使用 Widget.h Widget.cpp 来preFIX所以对于C ++ / CLI的项目,或后缀 M (管理)或者是W (包装)。因此,C ++ / CLI文件将 mWidget.h wWidget.h WidgetM。 ^ h WidgetW.h 。然后,我可能只是重复我的现有格局和整个好。

    • 但是,有没有更好的方式来组织文件,这样我可以用最少的改变现有的code让我的pre型/后缀少的文件名?

  2. <一个href="http://stackoverflow.com/questions/4819801/wrapping-an-unmanaged-c-class-library-with-c-cli-collections">Wrapping非托管C ++类库用C ++ / CLI - 问题2 - 集合

解决方案

我已经包装非托管C ++ API时的情形非常类似的东西。在我的情况下,即使类名是相同的。以下是我与我的项目:

  • 在我的C ++ / CLI的解决办法是在 C:\富
  • 的unamanaged C ++ API是在 C:\富\ API
  • 在每个.h文件中( bar.h )开始使用的#includeAPI / bar.h
  • 在非托管类的所有使用是通过 API ::酒吧

在我的情况下,大部分的时间花在该项目上自动创建的托管C ++文件。我做了一对夫妇的手,意识到这将多少时间做的一切的方式,并开始自动化过程。

我的图书馆依然独立。我有一个非托管的dll和一个托管的DLL。我只是存储在管理的一个非托管的项目。

对于自动化,它会读取每个非托管的.h文件,并创建我的管理.h文件中是这样的:

  • 加入我的的#includeAPI / bar.h行。
  • 复制所有的#include 行。
  • 加入我的管理空间。
  • 复制的类作为托管类,包括基类。
  • 添加受保护的指针非托管类。
  • 添加功能 GetInner(),以获得非托管类的指针。
  • 添加一个终结,删除非托管类。
  • 在添加多种功能,当一个函数有默认参数。

然后创建管理.cpp文件是这样的:

  • 填写的大部分功能与调用非托管函数
  • 使用 GetInner()一类被列入作为一个函数paramters任何时候
  • 请marshal_as为字符串和std :: wstrings之间转换

这工作,为广大的类,只有一点点手动调整。在一个领域,它没有工作,是与集合类。现在,我想我是幸运的,因为每一个集合类基本上是围绕的std ::矢量的包装。我根据 Col​​lectionBase的我所有的管理版本,使用构造采取非托管的集合类,并具有以下签名的方法:

 无效ToFoo(API ::美孚和放大器; 5);
 

因此​​,从非托管集合到一个托管集合只是一个 gcnew ,和走另一条路是:

 富* foo的; //最有可能的一个函数的参数,已经分配。
阿比::富apifoo; //名称只是API+的管理富的名字。
foo-&GT; ToFoo(apifoo);
 

这样的事情也被内置到的.cpp类生成的非集合类。

在$ C $下 ToFoo 只想清除非托管的集合,遍历管理的集合,并添加每个非托管项目,通过 GetInner( )。我的收藏并没有那么大,所以这个工作得很好。

如果我不得不一次又一次地做集合类,我很可能不会基地他们在 Col​​lectionBase的现在。我会更容易立足它们名单,其中,T&GT; 或做类似于在发布到你的问题#2目前的答案被讨论的东西。我的code的启动与.net 1.1(无仿制药),所以在那个时候, Col​​lectionBase的做了最有意义的我。

这是手卷使用正则表达式。由于库写得非常一致,我能够读取整个文件中,使用正则表达式来删除注释和其他的东西,可能会导致问题(内联函数),那么就阅读每一行和正则表达式来弄清楚它是什么。我像所有集合的列表(知道什么时候做上述集合调用),非正常类(串/的std :: wstring的),其他的事情我不记得。我将不得不看它是否做了它成我们新的源代码控制,因为该项目是在几年前放弃了。

Note: This post represents Question #1 of my inquiry. The introduction block (all text until the numbers are reached) is repeated in both questions as it is background information that may be needed to answer the question.


Introduction to Question

I have an unmanaged C++ library that contains classes and functions that are common to and shared among several "higher level" libraries. I now have need to provide access to the common library to C#/.Net applications. To do this, I will have to wrap the common library with C++/CLI wrapper classes.

The classes contained in the common library can be complex classes containing nested class definitions and member variables that are collections of other class objects. The collection variables are instances of typedefs of a custom list class for managing the collection. The common library also includes classes that represent the parsed structure of a custom script file syntax created using FLEX/BISON. The common library and the "higher level" libraries are all written in a fashion that allows for cross platform (Linux and GCC) compiling and usage. Any changes I make must still allow for this.

The C++/CLI wrapper classes at first need only read capability. But as the project advances, I'll eventually need to be able to create and modify the objects as well.

I know C++/CLI and have created several wrappers for other unmanaged C/C++ projects as well as providing abstracted functionality to this same common library. So I have the basics (and some advanced knowledge) already.

I have two questions related to performing this task and since they could both spawn their own discussions and solutions, I'm splitting my questions into separate posts. I'll include the link to the other question in each post.


Actual Questions

  1. How do I structure my files within the project?

    • The namespace and class names between the unmanaged and C++/CLI projects will not conflict. As the unmanaged project uses the "C" prefix for class names while the C++/CLI does not. So unmanaged class CWidget will become just Widget. And they use different root namespace names.

    • The issue comes when file names are concerned. As my default naming pattern would be to use Widget.h and Widget.cpp for both unmanaged and C++/CLI.

    • The projects are currently setup where all files of the project are in the root of the project folder. Includes for header files are done as just the name of the header (e.g. #include "Widget.h"). And to appropriately resolve includes for files of a different project, the path of the other project is added to the Additional Include Directories property of the using project.

    • If I change my Additional Include Directories property to be the root of the solution (..\) and do my include for the unmanaged header as #include "Unmanaged\Widget.h, I have a new issue of resolving headers included in the unmanaged header. So using that option would require I change all include statements to prefix their project directory. I know other projects

    • The most obvious/quickest solution to the issue of duplicate file names is to change the naming pattern for one of the libraries. So for the C++/CLI project, instead of using Widget.h and Widget.cpp to prefix or suffix m (managed) or w (wrapper). So the C++/CLI files would be mWidget.h, wWidget.h, WidgetM.h, or WidgetW.h. Then I could just repeat my existing pattern throughout and be good.

    • But is there a better way to organize the files so that I could keep my pre-/suffix-less file names with minimal changes to existing code?

  2. Wrapping an Unmanaged C++ Class Library with C++/CLI - Question 2 - Collections

解决方案

I have done something very similar when wrapping an unmanaged C++ api. In my case, even the class names were identical. Here's what I did with my project:

  • My C++/CLI solution was at C:\Foo
  • The unamanaged C++ api was at C:\Foo\api
  • Every .h file (bar.h) started with #include "api/bar.h"
  • All usage of unmanaged classes was via Api::Bar

In my case, the majority of time spent on the project was on automating the creation of the managed C++ files. I did a couple by hand, realized how much time it would take to do everything that way, and started automating the process.

My libraries were still separate. I had one unmanaged dll and one managed dll. I just stored the unmanaged project under the managed one.

As for the automation, it would read each unmanaged .h file and create my managed .h file like this:

  • Add my #include "api/bar.h" line.
  • Copy all #include lines.
  • Add my managed namespace.
  • Duplicate the class as a managed class, including the base class.
  • Add a protected pointer to the unmanaged class.
  • Add a function GetInner() to get the unmanaged class pointer.
  • Add a finalizer to delete the unmanaged class.
  • Add multiple functions when a function had default parameters.

Then create the managed .cpp files like this:

  • Fill in most functions with calls to the unmanaged functions
  • Use GetInner() any time a class was included as a function paramters
  • Do marshal_as to convert between strings and std::wstrings

This worked for the majority of the classes with only a little manual tweaking. The one area where it didn't work was with collection classes. Now, I think I was lucky, as every collection class was basically a wrapper around std::vector. I based all my managed versions on CollectionBase, with a constructor taking the unmanaged collection class, and a method with the following signature:

void ToFoo(Api::Foo& v);

So to go from an unmanaged collection to a managed collection was just a gcnew, and to go the other way was:

Foo* foo; //most likely a function parameter, already assigned.
Api::Foo apifoo; //name just "api" + the name of the managed Foo.
foo->ToFoo(apifoo);

This sort of thing was also built into the .cpp class generation for the non-collection classes.

The code for ToFoo would just clear the unmanaged collection, iterate through the managed collection and add each unmanaged item, via GetInner(). My collections weren't that big, so this worked perfectly well.

If I had to do the collection classes over again, I most likely wouldn't base them on CollectionBase now. I'd be much more likely to base them on List<T> or do something similar to what was discussed in the current answers posted to your question #2. My code was started with .Net 1.1 (no generics), so at that time, CollectionBase made the most sense to me.

It was hand-rolled using Regex. As the library was written very consistently, I was able to read in the entire file, use Regex to remove comments and other things that might cause problems (inline functions), then just read each line and Regex to figure out what was in it. I had things like a list of all the collections (to know when to do the collection calls above), abnormal classes (string/std::wstring), and other things I'm not remembering. I'm going to have to see if it made it into our new source control, as the project was abandoned a couple years ago.

这篇关于结束语非托管C ++类库用C ++ / CLI - 问题1 - 项目/ code组织的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆