如何将结构数组转换为IntPtr?

时间:2014-04-22 08:22:15

标签: c# pinvoke

C ++函数原型是;

/************************************************************************
parameters[in]: 
    void *handle,
    char *jpeg_buf,
    jpeg_buf jpeg_buf
parameters[out]:
    listSize:   result list size, max <= 1000;
    list:       result
************************************************************************/

int getInfo(void *handle,unsigned char* jpeg_buf, unsigned int jpeg_len, int& list_size, Info *info_list);

C ++类型;

typedef struct
{
    int dot_x;
    int dot_y;
} Attr;


typedef struct
{
    int left;
    int top;
    int right;
    int bottom;
} Rect_S;


typedef struct
{
    Rect_S rect;
    Attr attr;
} Info;

C#DLL导入;

[DllImport("sample.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int getInfo(IntPtr handle, byte[] jpeg_buf, uint jpeg_len, out int listSize, out IntPtr List);

结构在C#中;

internal struct Attr
    {
        public int dot_x;
        public int dot_y;
    };

    internal struct Rect_S
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    };

    internal struct Info
    {
        public Rect_S rect;
        public Attr attr;
    };

C#GetInfo函数;

public Info[] getInfo(byte[] scan0)
    {
        Info[] retVal = null;
        IntPtr structPtr = IntPtr.Zero;
        int size;

        int ret = EFEngine.getInfo(this.Engine, scan0, (uint)scan0.Length, out size, out structPtr);

        if (ret >= 0)
        {
            retVal = new Info[size];
            int sizePointerInfo = Marshal.SizeOf(new EFaceInfo());
            for (int i = 0; i < size; i++)
            {
                retVal[i] = (Info)Marshal.PtrToStructure(new IntPtr(structPtr.ToInt64() + (i * sizePointerInfo)), typeof(Info));
            }
        }

        return retVal;
    }

我收到错误“附加信息:尝试读取或写入受保护的内存。这通常表示其他内存已损坏。”当调用“Marshal.PtrToStructure”时。

有什么不对?

C ++测试代码;

int getInfoTest(void *handle, unsigned char* jpeg_buf, unsigned int jpeg_len, int& list_size, FaceInfo *face_rect_list)
{
    int nSizeNum = 0;
    Info* List = new Info[32];
    int nRet = getInfo(handle, jpeg_buf, jpeg_len, nSizeNum, List);
    if (nRet != 0)
    {
        fprintf(stderr, "error: getInfo failed\n");
    }
    delete[] List;
    delete[] jpeg_buf;

    return nRet;
}

1 个答案:

答案 0 :(得分:0)

正如您在上一个问题中所发生的那样,问题中提供的信息不完整。当我试图向你解释时,C ++原型并没有完全指定C ++函数的语义。正如我之前向您解释的那样,您应该包含那些语义,或至少一些示例C ++代码来调用该函数。

但是,问题很可能是最终参数。期望调用者分配内存并将其地址传递给函数。它看起来非常像这个最终参数实际上是一个数组。根据这个假设,p / invoke声明应该是:

[DllImport("sample.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int getInfo(IntPtr handle, byte[] jpeg_buf, 
    uint jpeg_len, ref int listSize, [Out] Info[] List);

您可以像这样调用函数:

int listSize = ...; // you have to somehow work out what to put here
Info[] List = new Info[listSize];
int retval = getInfo(handle, jpeg_buf, jpeg_len, ref listSize, List);
// check retval

当然,由于列表大小参数是通过引用传递的,这表明该函数可以告诉您需要多大的数组。所以呼叫序列也许应该是:

int listSize = 0;
int retval = getInfo(handle, jpeg_buf, jpeg_len, ref listSize, null);
// check retval
Info[] List = new Info[listSize];
int retval = getInfo(handle, jpeg_buf, jpeg_len, ref listSize, List);
// check retval