处理 IntPtr 数组
我想我已经很接近了,而且我敢打赌解决方案是愚蠢的。
我有一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当 data 为
void*
类型时,如何编写此代码:将其更改为
char*
或int*
类型。另外,使用
ref
而不是out
作为最后一个参数:这是更正的一个:
您必须相应地更改方法签名。
How can you write this where data is
void*
type:Change this to either type
char*
orint*
.Also, use
ref
instead ofout
for the last argument here:This is corrected one:
You've to change the method signature accordingly.
尝试更改
为
2 之间有细微的差别。
更新:
尝试:
Try changing
to
There is a subtle difference between the 2.
Update:
Try:
我认为你想要
的东西更像是
所以你将在
data
指向的任何内容中存储一个指针数组。I think that you want
to be something more like
So you'll be storing an array of pointers in whatever
data
is pointing to.当接收非托管数组时,运行时将不知道数组的长度,您需要使用 MarshalAsAttribute 与 SizeParamIndex 字段指定数组的长度。 此处有一个示例。
您也不需要将方法签名定义为数组的 ref IntPtr[],请使用 InAttribute 和 输出属性。
前任:
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.: