将托管C ++数组传递到非托管C [英] Passing managed C++ arrays to and from unmanaged C

查看:231
本文介绍了将托管C ++数组传递到非托管C的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一个完整的初学者在C,C + +和C + + / CLI,我不太了解指针和东西,但我真的需要创建一个.Net包装在一个C库。我试过使用SWIG,但它不工作,我被卡住了。我宁愿不使用P / Invoke,因为有一些嵌套的结构体,我读到P / Invoke不是很好用这些。



我有一个C头像这样:

  // packer.h 
typedef struct {
int剩下;
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 ++ / :

  // packer_cli.cpp 
#include< windows.h>
#include< vcclr.h>
#include../../packer/packer.h
#using< System.dll>
#using< mscorlib.dll>

使用命名空间System;

namespace Packer {
//重新创建所需的结构作为托管类
public ref class Frame {
public:
int Left,Top,右,底;
};
public ref class Image {
public:
int Width,Height;
Frame ^ View,^ Dest;
Image(){
View = gcnew Frame();
Dest = gcnew Frame();
}
};
public ref class参数{
public:
int PageWidth,PageHeight,Margin,NbRun;
};

//在类中包装main方法
public ref class Packer {
private:
int _nb_images;
public:
Packer(int nb_images){
_nb_images = nb_images;
}
int Pack(array< Image ^> ^ images,Parameters ^ params){
//创建一个本地数组的image_t发送到C库
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; //这是甚么应该怎么办?
}

// HALP!

//创建一个本地的parameters_t发送到C库
parameter_t nativeParams;
nativeParams.page_width = params-> PageWidth;
nativeParams.page_height = params-> PageHeight;
nativeParams.margin = params-> Margin;
nativeParams.nb_run = params-> NbRun;

//调用打包方法
int result = pack(nativeImagesToPass,_nb_images,nativeParams);

//在图像上重新循环以从本地图像获取值,并将它们分配给托管图像
for(int i = 0; i <_nb_images; i ++){
// TODO
}

返回结果;
}
};
}



我在创建一个本地数组的image_t发送到 pack 函数。我不能直接传递数组,显然,但我找不到转换它的方式。



使用 pin_ptr 我得到这个错误:

  pin_ptr< image_t> nativeImagesToPass =& nativeImages [0]; 
// C2440:'initialization':无法从'cli :: interior_ptr< Type>'转换为'cli :: pin_ptr< Type>'

Marshal :: Copy ...好吧,我找不到如何声明我的东西: p>

 系统:: Runtime :: InteropServices :: Marshal :: Copy(IntPtr((void *)nativeImagesToPass),nativeImages,0,_nb_images ); 
//如何声明要复制到的nativeImagesToPass变量?
// image_t nativeImagesToPass [_nb_images]列出一堆错误:C2057,C2466,C2082和C2133

那么,如何将结构体数组从受管阵列复制到非管理阵列?或者有一个更好,更简单的解决方案?正如我所说,我几乎不知道C / C ++,所以我真的迷路了。



谢谢!



< h1>更新

由于@metacubed,我已修改 Pack 方法,例如:

  int Pack(array< Image ^> ^%images,Parameters ^ params){
//创建一个要发送的image_t的本机数组到C库
image_t * nativeImages = new image_t [_nb_images];
for(int i = 0; i <_nb_images; i ++){
image_t nativeImage = images [i] - > ToNative
}

//调用打包方法
int result = pack(nativeImages,_nb_images,params-> ToNative());

//在图像上重新循环以从本地图像获取值,并将它们分配给托管图像
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;

返回结果;
}

但现在我有这些构建错误相关):

  LNK2028:未解析的标记(0A000028)int __cdecl pack(struct image_t *,int,struct parameters_t)在函数public:int __clrcall Packer :: Packer :: Pack(cli :: array< class Packer :: Image ^> ^,class Packer)中引用的@ pack $$ FYAUPAUimage_t @@ HUparameters_t @ :参数^)(?Pack @ Packer @ 1 @ $$ FQ $ AAMHA $ CAP $ 01AP $ AAVImage @ 1 @ P $ AAVParameters @ 1 @@ Z)
LNK2019:未解析的外部符号int __cdecl pack在函数public:int __clrcall Packer :: Packer :: Pack(cli :: array< class Packer)中引用的struct image_t *,int,struct parameters_t)(?pack @@ $$ FYAHPAUimage_t @@ HUparameters_t @ :: Image ^> ^,Packer :: Parameters ^)(?Pack @ Packer @ 1 @ $$ FQ $ AAMHA $ CAP $ 01AP $ AAVImage @ 1 @ P $ AAVParameters @ 1 @@ Z)


h2_lin>解决方案

使用C ++ / CLI的一个优点是你可以使用本地C ++结构。所以:

  int Pack(array< Image ^> ^ images,Parameters ^ params)
{
//创建一个本地数组的image_t发送到C库
image_t * arrNativeImages = new image_t [_nb_images];
for(int i = 0; i <_nb_images; i ++)
{
arrNativeImages [i] .width = images [i] - &
arrNativeImages [i] .height = images [i] - > Height;
}

...

int result = pack(parrNativeImages [0],_nb_images,nativeParams);

//使用OUT params from arrNativeImages [i]
...

//最后不要忘记删除创建的数组...
delete [] arrNativeImages;
arrNativeImages = NULL;
}

这很简单。还有其他方法来直接将托管对象发送到本地代码,但是他们需要结构对齐以在托管结构和本地结构之间进行匹配。但对于你的情况,这种方法似乎够了。


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!

解决方案

One of the advantages of using C++/CLI is that you can just use native C++ constructs. So:

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

It's that simple. There are other ways to directly send the managed objects into native code, but they need the struct alignments to match across the managed and native structs. But for your case, this method seems quite enough.

这篇关于将托管C ++数组传递到非托管C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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