简体   繁体   English

使用x86 / x64 C API的C#AnyCPU库-打包结构,调用和回调

[英]C# AnyCPU library using x86/x64 C API - packing structures, calls and callbacks

I`m searching and trying all sort of solutions for like two weeks now to make the following possible: port 32-bit libraries and C++/.NET wrappers to 64-bit (for C++) and AnyCpu (for .NET). 我正在搜索并尝试各种解决方案大约两个星期,以实现以下目的:将32位库和C ++ /。NET包装器移植到64位(对于C ++)和AnyCpu(对于.NET)。

There is: 有:

  • a C++ library which exposes a C-style interface further referred as "The Brain" (this is how we all call it) 一个C ++库,它公开了一个进一步称为“大脑”的C风格界面(这就是我们所有人所说的方式)
  • a second C++ library (DDC) which uses The Base is more like a wrapper for it, in the way that it packs a very nice interface 第二个使用The Base的C ++库(DDC)更像是它的包装器,因为它包装了一个非常漂亮的接口
  • a .NET library (DDN) which uses The Base and acts like a wrapper for C# and VB .NET库(DDN),该库使用The Base并充当C#和VB的包装器
  • a JAVA library (DDJ) [ not important, we have separate development to handle this ] JAVA库(DDJ)[不重要,我们有单独的开发来处理此问题]
  • a PYTHON library (DDP) [ not important neither ] PYTHON库(DDP)[都不重要]

The libraries are huge, in the way that there are thousands of structures and functions (interfacing with databases and with some various Ethernet devices). 这些库非常庞大,以至于有成千上万的结构和功能(与数据库以及某些各种以太网设备的接口)。 There is lots of functionality which I don`t even know why is kept in the code, but requirements are requirements and must be obeyed... 我什至不知道为什么很多功能都保留在代码中,但是需求是要求,必须遵守...

The entire driver and database connector had only 32-bit configurations. 整个驱动程序和数据库连接器只有32位配置。 There is no relevant documentation on anything inside and a lot of code had to be modified (not rewritten or refactored, but modified). 内部没有任何相关文档,必须修改很多代码(不重写或重构,而是修改)。

All the structures are aligned on 4 bytes, marshalling between .net and C API works ok on 32-bit. 所有结构都对齐为4个字节,.net和C API之间的编组可以在32位上正常工作。

The new requirement is to create AnyCPU .NET configuration which to use the 64-bit respectively 32-bit Base according to the system the VB/C# application runs on. 新要求是根据运行VB / C#应用程序的系统创建AnyCPU .NET配置,以使用64位或32位Base。

So far so good - DDC works nice with The Base. 到目前为止,一切都很好-DDC与The Base配合良好。 but when it comes to DDN - there is a whole lot of s### happening: the structures to be marshalled and unmarshalled with The Base have a pack on 4 bytes... Therefore, the alignment of the Base structures has been switched to 4 bytes for both 32-bit and 64-bit (was 4 respectively 8 bytes). 但是当涉及到DDN时-发生了很多s ###: 要与The Base一起编组和解组的结构有4个字节的压缩包...因此,Base结构的对齐方式已切换为32位和64位均为4个字节(分别为4个8个字节)。

My initial plan was with alignment on 4 and 8 bytes for 32-but respectively 64-bit configurations, but there is a lot of work to do in the .NET API interfacing with the Base C wrapper... the calls and callbacks are separated within different namespaces, each including the respective library, but the structures are a pain... 我最初的计划是针对32位(但分别为64位)配置对齐4和8个字节,但是.NET API与Base C包装器接口还有很多工作要做...调用和回调是分开的在不同的名称空间中,每个名称空间都包括各自的库,但是结构很麻烦...

The second plan was to align everything with either 4 or 8 but there are a lot of warnings regarding the packing of structures and unary operators... Besides those warnings, nothing works nice anymore. 第二个计划是使所有内容都与4或8对齐,但是关于结构和一元运算符打包的警告很多...除了这些警告之外,再也没有什么可行的了。 Heap corruptions, shutdown crashes etc.. 堆损坏,关机崩溃等。

A third solution would be to switch back to solution 1 and create structures with appropriate packs on both namespaces (the namespace interacting with 32-bit Base library and the namespace interacting with the 64-bit Base library) 第三种解决方案是切换回解决方案1,并在两个名称空间上创建具有适当包的结构(名称空间与32位基本库进行交互,而名称空间与64位基本库进行交互)

I would greatly appreciate any feedback. 我将不胜感激任何反馈。 Please do not hesitate to ask for more information if anything is unclear. 如果有任何不清楚的地方,请随时询问更多信息。

Thank you all! 谢谢你们!

In my experience is a very bad idea passing pointers from/to unmanaged code to managed code. 以我的经验,将指针从非托管代码传递到托管代码是一个非常糟糕的主意。 If you use callbacks the final result can be worst than expected. 如果使用回调,则最终结果可能比预期的更糟。 You must remember that .NET defragments the memory so the phisical addresses of the pointers may vary (so you can imagine the things that may happen). 您必须记住,.NET对内存进行碎片整理,因此指针的物理地址可能会有所不同(因此您可以想象可能发生的事情)。


Solution A: Make it simple, if you want to mix unmanaged with managed do it with C++ managed using unmanaged C (so, no any CPU solution). 解决方案A:如果您想将非托管与托管混合使用,可以将其与使用非托管C托管的C ++混合使用(因此,没有任何CPU解决方案)。 Oracle Data Access is an example of this solution. Oracle Data Access是此解决方案的示例。


Solution B: Split the solution in two projects, one managed and one unmanaged. 解决方案B:将解决方案分为两个项目,一个为托管项目,另一个为非托管项目。 Objects shared between layers must be in the unmanaged side. 层之间共享的对象必须在非托管端。 You must forget about callbacks between unmanaged and managed projects. 您必须忘记非托管项目和托管项目之间的回调。 This solution is used in SQLite drivers for .NET. 该解决方案用于.NET的SQLite驱动程序中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM