将托管C ++数组传入非托管C和从非托管C传递

时间:2014-07-03 08:18:23

标签: c++-cli

我是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)

我感觉距离目标太远了!

1 个答案:

答案 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;
    }

就这么简单。还有其他方法可以将托管对象直接发送到本机代码,但是它们需要结构对齐以匹配托管和本机结构。但对于你的情况,这种方法似乎已经足够了。