I am a complete beginner at C, C++ and C++/CLI, and I don't understand much about the pointers and stuff, but I really need to create a .Net wrapper around a C library. I have tried using SWIG, but it doesn't work and I'm stuck. I'd rather not use P/Invoke because there are a few nested structs involved, and I read that P/Invoke isn't great with these.
So anyway, I have a C header looking like this:
// 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);
Using various tutorials and help bits here and there, I have started writing a C++/CLI wrapper around this:
// 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;
}
};
}
I have trouble creating a native array of image_t to send to the pack
function. I can't pass the array directly, obviously, but I can't find the way to convert it.
With pin_ptr
I get this error:
pin_ptr<image_t> nativeImagesToPass = &nativeImages[0];
//C2440: 'initialization' : cannot convert from 'cli::interior_ptr<Type>' to 'cli::pin_ptr<Type>'
And with Marshal::Copy
... well, I can't find how to declare my stuff:
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
So, how do I copy an array of structs from a managed array to an unmanaged one? Or maybe there's a better, simpler solution? As I said, I know pretty much nothing about C/C++ so I'm really lost.
Thanks!
Update
Thanks to @metacubed, I have modified the Pack
method such:
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;
}
but now I have these build errors (I'm not sure they're related):
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)
I feel so close and yet so far from the goal!