我是C,C ++和C ++ / CLI的初学者,我不太了解指针和内容,但我真的需要在C库周围创建一个.Net包装器。我尝试过使用SWIG,但它没有用,而且我被卡住了。我不想使用P / Invoke,因为涉及到一些嵌套结构,我读到P / Invoke并不是很好用。
所以无论如何,我有一个看起来像这样的C头:
// packer.h
typedef struct {
int left;
int top;
int right;
int bottom;
} frame_t;
typedef struct {
/* IN */
int width;
int height;
/* OUT */
frame_t view;
frame_t dest;
} image_t;
typedef struct {
int page_width;
int page_height;
int margin;
int nb_run;
} parameters_t;
int pack(image_t *images, int nb_images, parameters_t params);
在这里和那里使用各种教程和帮助位,我已经开始编写一个C ++ / CLI包装器:
// packer_cli.cpp
#include <windows.h>
#include <vcclr.h>
#include "../../packer/packer.h"
#using <System.dll>
#using <mscorlib.dll>
using namespace System;
namespace Packer {
// re-create the needed structs as managed classes
public ref class Frame {
public:
int Left, Top, Right, Bottom;
};
public ref class Image {
public:
int Width, Height;
Frame ^View, ^Dest;
Image() {
View = gcnew Frame();
Dest = gcnew Frame();
}
};
public ref class Parameters {
public:
int PageWidth, PageHeight, Margin, NbRun;
};
// wrap the main method in a class
public ref class Packer {
private:
int _nb_images;
public:
Packer(int nb_images) {
_nb_images = nb_images;
}
int Pack(array< Image^ >^ images, Parameters^ params) {
// create a native array of image_t to send to the C library
array< image_t * >^ nativeImages = gcnew array< image_t * >(_nb_images);
for(int i = 0; i < _nb_images; i++) {
image_t nativeImage;
nativeImage.width = images[i]->Width;
nativeImage.height = images[i]->Height;
nativeImages[i] = &nativeImage; // is this even how it should be done?
}
// HALP!
// create a native parameters_t to send to the C library
parameters_t nativeParams;
nativeParams.page_width = params->PageWidth;
nativeParams.page_height = params->PageHeight;
nativeParams.margin = params->Margin;
nativeParams.nb_run = params->NbRun;
// call the packing method
int result = pack(nativeImagesToPass, _nb_images, nativeParams);
// re-loop on images to get the values from native images, and assign them to managed images
for(int i = 0; i < _nb_images; i++) {
// TODO
}
return result;
}
};
}
我无法创建image_t的原生数组以发送到pack
函数。显然,我无法直接传递数组,但我无法找到转换它的方法。
使用pin_ptr
我收到此错误:
pin_ptr<image_t> nativeImagesToPass = &nativeImages[0];
//C2440: 'initialization' : cannot convert from 'cli::interior_ptr<Type>' to 'cli::pin_ptr<Type>'
使用Marshal::Copy
......好吧,我无法找到如何宣布我的东西:
System::Runtime::InteropServices::Marshal::Copy(IntPtr((void *)nativeImagesToPass ), nativeImages, 0, _nb_images);
// How do I declare the nativeImagesToPass variable to copy to?
// image_t nativeImagesToPass[_nb_images] yeilds a bunch of errors: C2057, C2466, C2082 and C2133
那么,如何将托管数组中的结构数组复制到非托管数组?或者可能有更好,更简单的解决方案?正如我所说,我对C / C ++几乎一无所知,所以我真的输了。
谢谢!
感谢@metacubed,我修改了Pack
方法:
int Pack(array< Image^ >^% images, Parameters^ params) {
// create a native array of image_t to send to the C library
image_t* nativeImages = new image_t[_nb_images];
for(int i = 0; i < _nb_images; i++) {
image_t nativeImage = images[i]->ToNative();
}
// call the packing method
int result = pack(nativeImages, _nb_images, params->ToNative());
// re-loop on images to get the values from native images, and assign them to managed images
for(int i = 0; i < _nb_images; i++) {
images[i]->View = gcnew Frame(nativeImages[i].view);
images[i]->Dest = gcnew Frame(nativeImages[i].dest);
}
delete[] nativeImages;
return result;
}
但现在我有这些构建错误(我不确定它们是否相关):
LNK2028: unresolved token (0A000028) "int __cdecl pack(struct image_t *,int,struct parameters_t)" (?pack@@$$FYAHPAUimage_t@@HUparameters_t@@@Z) referenced in the function "public: int __clrcall Packer::Packer::Pack(cli::array<class Packer::Image ^ >^,class Packer::Parameters ^)" (?Pack@Packer@1@$$FQ$AAMHA$CAP$01AP$AAVImage@1@P$AAVParameters@1@@Z)
LNK2019: unresolved external symbol "int __cdecl pack(struct image_t *,int,struct parameters_t)" (?pack@@$$FYAHPAUimage_t@@HUparameters_t@@@Z) referenced in the function "public: int __clrcall Packer::Packer::Pack(cli::array<class Packer::Image ^ >^,class Packer::Parameters ^)" (?Pack@Packer@1@$$FQ$AAMHA$CAP$01AP$AAVImage@1@P$AAVParameters@1@@Z)
我感觉距离目标太远了!
答案 0 :(得分:1)
使用C ++ / CLI的一个优点是您可以使用本机C ++构造。所以:
int Pack(array< Image^ >^ images, Parameters^ params)
{
// create a native array of image_t to send to the C library
image_t* arrNativeImages = new image_t[_nb_images];
for(int i = 0; i < _nb_images; i++)
{
arrNativeImages[i].width = images[i]->Width;
arrNativeImages[i].height = images[i]->Height;
}
...
int result = pack(parrNativeImages[0], _nb_images, nativeParams);
// Use OUT params from arrNativeImages[i]
...
// Finally don't forget to delete the created array...
delete[] arrNativeImages;
arrNativeImages = NULL;
}
就这么简单。还有其他方法可以将托管对象直接发送到本机代码,但是它们需要结构对齐以匹配托管和本机结构。但对于你的情况,这种方法似乎已经足够了。