处理 IntPtr 数组

发布于 2024-10-10 18:12:20 字数 2195 浏览 2 评论 0原文

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

我有一个 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 元素。从本机调用返回后,它只有一个...出了问题...如果我用 BYTE** 替换 void** 也会发生这种情况

I think I'm close and I bet the solution is something stupid.

I have a C++ native DLL where I define the following function:

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

Basically, given a file path, this function creates a list of byte arrays (BYTE*) and should return a list of pointers via the data param. Each pointing to a different byte array.

I want to pass an array of IntPtr from C# and be able to marshal each individual array in order. Here's the code I'm using:

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

Problem is in my C++ code. When I assign *(data + i * sizeofarray) = pByte; it corrupts the array of pointers... what am I doing wrong?

UPDATE:
Just started to create a new solution to isolate concepts and already found something very weird. Take a look:

C# code

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++ code

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

extern "C" {

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

}

Before the call to native code, pList has 10 IntPtr.Zero elements. After returning from native call, it has only one... something wrong... and it also happens if I replace void** by BYTE**

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

温折酒 2024-10-17 18:12:21

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

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

How can you write this where data is void* type:

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

Change this to either type char* or int*.

Also, use ref instead of out for the last argument here:

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

This is corrected one:

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

You've to change the method signature accordingly.

神经大条 2024-10-17 18:12:21

尝试更改

out IntPtr[] ptr

ref IntPtr[] ptr

2 之间有细微的差别。

更新:

尝试:

data[i] = pByte

Try changing

out IntPtr[] ptr

to

ref IntPtr[] ptr

There is a subtle difference between the 2.

Update:

Try:

data[i] = pByte
情深已缘浅 2024-10-17 18:12:21

认为你想要

*(data + i * sizeofarray) = pByte;

的东西更像是

data[i] = pByte;

所以你将在data指向的任何内容中存储一个指针数组。

I think that you want

*(data + i * sizeofarray) = pByte;

to be something more like

data[i] = pByte;

So you'll be storing an array of pointers in whatever data is pointing to.

土豪 2024-10-17 18:12:20

当接收非托管数组时,运行时将不知道数组的长度,您需要使用 MarshalAsAttributeSizeParamIndex 字段指定数组的长度。 此处有一个示例。

您也不需要将方法签名定义为数组的 ref IntPtr[],请使用 InAttribute输出属性

前任:

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

The runtime will have no clue to the length of the array when receiving unmanaged arrays, you need to use the MarshalAsAttribute in conjunction with the SizeParamIndex field to specify the length of the array. There's an example of this here.

You also don't need to define the method signature as ref IntPtr[] for the array, use the InAttribute and OutAttribute.

E.x.:

private static extern bool Open(out int n,[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] [In,Out] IntPtr[] ptr);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文