2

我想我已经接近了,我敢打赌解决方案是愚蠢的。

我有一个 C++ 本机 DLL,在其中定义了以下函数:

DllExport bool __stdcall Open(const char* filePath, int *numFrames, void** data);
{
  //creates the list of arrays here... don't worry, lifetime is managed somewhere else

  //foreach item of the list:
  {
      BYTE* pByte = GetArray(i);

      //here's where my problem lives
      *(data + i * sizeofarray) = pByte;
  }
  *numFrames = total number of items in the list
  return true;
}

基本上,给定一个文件路径,此函数创建一个字节数组 (BYTE*) 列表,并应通过数据参数返回一个指针列表。每个指向不同的字节数组。

我想从 C# 传递一个 IntPtr 数组,并能够按顺序编组每个单独的数组。这是我正在使用的代码:

    [DllImport("mydll.dll",EntryPoint = "Open")]
    private static extern bool MyOpen(
      string filePath, out int numFrames, out IntPtr[] ptr);

    internal static bool Open(
      string filePath, out int numFrames, out Bitmap[] images)
    {
        var ptrList = new IntPtr[512];

        MyOpen(filePath, out numFrames, out ptrList);

        images = new Bitmap[numFrames];
        var len = 100; //for sake of simplicity
        for (int i=0; i<numFrames;i++)
        {
            var buffer = new byte[len];
            Marshal.Copy(ptrList[i], buffer, 0, len);

            images[i] = CreateBitmapFromBuffer(buffer, height, width);
        }

        return true;
    }

问题出在我的 C++ 代码中。当我分配 *(data + i * sizeofarray) = pByte; 它破坏了指针数组......我做错了什么?

更新: 刚开始创建一个新的解决方案来隔离概念,并且已经发现了一些非常奇怪的东西。看一看:

C# 代码

class Program
{
    [DllImport("ArrayProvider.dll")]
    private static extern bool Open(out int n, ref IntPtr[] ptr);


    static void Main(string[] args)
    {
        int n;

        var pList = new IntPtr[10];

        Program.Open(out n, ref pList);

        foreach (var p in pList)
        {
            Debug.WriteLine(p.ToInt32().ToString("X"));
        }
    }
}

C++ 代码

#include "stdafx.h"
#define DllExport   __declspec( dllexport )

extern "C" {

DllExport bool __stdcall Open(int *n, void** data)
{
return true;
}

}

在调用本机代码之前,pList 有 10 个 IntPtr.Zero 元素。从本地调用返回后,它只有一个......出了点问题......如果我将 void** 替换为 BYTE** 也会发生

4

4 回答 4

4

运行时接收非托管数组时会不知道数组的长度,需要结合使用MarshalAsAttributeSizeParamIndex字段来指定数组的长度。这里有一个例子。

您也不需要将方法签名定义为数组的 ref IntPtr[],使用InAttributeOutAttribute

前任:

private static extern bool Open(out int n,[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] [In,Out] IntPtr[] ptr);
于 2011-01-06T12:41:04.097 回答
2

尝试改变

out IntPtr[] ptr

ref IntPtr[] ptr

2之间有细微差别。

更新:

尝试:

data[i] = pByte
于 2011-01-06T06:43:37.390 回答
2

你怎么能在数据类型的地方写这个void*

 //you cannot do such pointer arithmetic on void* type.
 *(data + i * sizeofarray) = pByte; 

将此更改为 typechar*int*.

此外,在此处使用ref而不是out最后一个参数:

MyOpen(filePath, out numFrames, out ptrList); //wrong

这是更正一个:

MyOpen(filePath, out numFrames, ref ptrList); //correct

您必须相应地更改方法签名。

于 2011-01-06T06:44:57.427 回答
1

你想要

*(data + i * sizeofarray) = pByte;

变得更像

data[i] = pByte;

因此,您将在指向的任何data内容中存储一个指针数组。

于 2011-01-06T07:04:53.780 回答