【问题标题】:Dealing with array of IntPtr处理 IntPtr 数组
【发布时间】:2011-01-06 06:27:33
【问题描述】:

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

我有一个 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** 也会发生这种情况

【问题讨论】:

  • 我不确定*(data + i * sizeofarray) 是否有意义,即使datachar*(或指向void 以外的任何内容的指针) - 但我并不清楚这是什么确切应该存储在data 指向的任何地方。

标签: c# c++ interop native intptr


【解决方案1】:

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

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

例如:

private static extern bool Open(out int n,[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] [In,Out] IntPtr[] ptr);

【讨论】:

  • 我正要发布答案并看到了你的答案...用“[In, Out]”替换“ref”就可以了。
【解决方案2】:

如果 datavoid*,你怎么写这个:

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

将其更改为char*int*

另外,这里的最后一个参数使用ref 而不是out

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

这是更正的一个:

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

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

【讨论】:

  • numFrames 不需要 ref。我怀疑将 void* 更改为其他内容会有所不同。
  • @leppie : 如果使用void* 类型,指针算术有什么意义?
  • 我认为这就是我的困惑所在。我决定使用 void** 因为我的 GetArray 返回一个 BYTE*...我可以简单地将 void** 替换为 BYTE** 吗?
  • @Nawaz:void* 的大小是众所周知的,但既然你这么说,我怀疑data[i] = pByte 就足够了。
  • @Padu:这样更好。因为这样,编译器就可以知道指针指向的每个元素的大小。
【解决方案3】:

尝试改变

out IntPtr[] ptr

ref IntPtr[] ptr

两者之间有细微的差别。

更新:

试试:

data[i] = pByte

【讨论】:

  • 从非托管返回时已更改但仍存在访问冲突
  • 更多细节...在 AV 之后,如果我选择“中断”,我的 ptrList 的长度为 1 而不是 512...
  • 对不起,我没有看到更新...试过了,仍然有一个 AV。我放弃。问题一定出在其他地方。我将制作一个简单的演示解决方案来隔离问题,一旦我弄清楚了,我会回到我的生产代码。
【解决方案4】:

认为你想要

*(data + i * sizeofarray) = pByte;

变得更像

data[i] = pByte;

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

【讨论】:

  • 我会试试的。每个数据元素都指向一个 BYTE*,其中包含图像的原始单色字节
  • 再来一次祝你好运吗?我已经说过两次了:)
猜你喜欢
  • 2015-01-25
  • 1970-01-01
  • 2013-07-22
  • 2011-10-08
  • 2015-09-29
  • 1970-01-01
  • 1970-01-01
  • 2013-04-05
  • 1970-01-01
相关资源
最近更新 更多