Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将结构数组转换为IntPtr_C#_.net_Marshalling - Fatal编程技术网

C# 将结构数组转换为IntPtr

C# 将结构数组转换为IntPtr,c#,.net,marshalling,C#,.net,Marshalling,我正在尝试将RECT结构的数组(如下所示)转换为IntPtr,以便使用PostMessage将指针发送到另一个应用程序 [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; // lots of functions snipped here } //

我正在尝试将RECT结构的数组(如下所示)转换为IntPtr,以便使用PostMessage将指针发送到另一个应用程序

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;

    // lots of functions snipped here
}

// so we have something to send, in reality I have real data here
// also, the length of the array is not constant
RECT[] foo = new RECT[4]; 
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(foo[0]) * 4);
Marshal.StructureToPtr(foo, ptr, true); // -- FAILS
这在最后一行给出了ArgumentException(“指定的结构必须是可blittable或具有布局信息”)。我需要使用PostMessage将这个rect数组转到另一个应用程序,所以我真的需要一个指向这个数据的指针

我的选择是什么

更新:这似乎有效:

 IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Win32.RECT)) * foo.Length);
 IntPtr c = new IntPtr(result.ToInt32());
 for (i = 0; i < foo.Length; i++)
 {
     Marshal.StructureToPtr(foo[i], c, true);
     c = new IntPtr(c.ToInt32() + Marshal.SizeOf(typeof(Win32.RECT)));
 }
IntPtr result=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Win32.RECT))*foo.Length);
IntPtr c=newintptr(result.ToInt32());
对于(i=0;i

再次更新以修复仲裁人的评论。

您可以尝试以下操作:

 RECT[] rects = new RECT[ 4 ];
 IntPtr[] pointers = new IntPtr[4];
 IntPtr result =  Marshal.AllocHGlobal(IntPtr.Size * rects.Length);
 for (int i = 0; i < rects.Length; i++)
 {
     pointers[i] = Marshal.AllocHGlobal (IntPtr.Size);
     Marshal.StructureToPtr(rects[i], pointers[i], true);
     Marshal.WriteIntPtr(result, i * IntPtr.Size, pointers[i]);
 }
 // the array that you need is stored in result
RECT[]rects=新的RECT[4];
IntPtr[]指针=新的IntPtr[4];
IntPtr result=Marshal.AllocHGlobal(IntPtr.Size*rects.Length);
for(int i=0;i

不要忘记在完成后释放所有内容。

StructureToPtr需要struct对象,而foo不是structure,而是array,这就是异常发生的原因

我可以建议您在cycle中编写结构(遗憾的是,StructureToPtr没有索引重载):

long LongPtr=ptr.ToInt64();//必须同时在x86和x64上工作
for(int I=0;I
另一个选项是使用Marshal.WriteInt32将结构写入四个整数:

for (int I = 0; I < foo.Length; I++)
{
    int Base = I * sizeof(int) * 4;
    Marshal.WriteInt32(ptr, Base + 0, foo[I].Left);
    Marshal.WriteInt32(ptr, Base + sizeof(int), foo[I].Top);
    Marshal.WriteInt32(ptr, Base + sizeof(int) * 2, foo[I].Right);
    Marshal.WriteInt32(ptr, Base + sizeof(int) * 3, foo[I].Bottom);
}
for(int I=0;I

最后,您可以使用不安全的关键字,并直接使用指针。

Arbiter为您提供了一个关于如何封送结构数组的好答案。对于像这样的blittable结构,我个人会使用不安全的代码,而不是手动将每个元素封送到非托管内存中。大概是这样的:

RECT[] foo = new RECT[4];
unsafe
{
    fixed (RECT* pBuffer = foo)
    {
        //Do work with pointer
    }
}
或者可以使用GCHandle固定阵列

不幸的是,您说需要将此信息发送到另一个进程。如果您发布的邮件不是Windows提供自动封送处理的邮件之一,则您还有另一个问题。由于指针是相对于本地进程的,因此在远程进程中没有任何意义,使用此指针发布消息将导致意外行为,包括可能的程序崩溃。因此,您需要做的是将RECT数组写入另一个进程的内存,而不是您自己的内存。要做到这一点,您需要使用OpenProcess获取进程的句柄,VitualAllocEx在另一个进程中分配内存,然后WriteProcessMemory将数组写入另一个进程的虚拟内存


不幸的是,如果您要从32位进程转换为32位进程,或者从64位进程转换为64位进程,事情非常简单,但是从32位进程转换为64位进程,事情可能会变得有点棘手。VirtualAllocEx和WriteProcessMemory在32到64之间实际上不受支持。您可以尝试强制VirtualAllocEx将其内存分配到64位内存空间的底部4GB,从而使生成的指针对32位进程API调用有效,然后使用该指针进行写入,从而获得成功。此外,两种进程类型之间可能存在结构大小和打包差异。使用RECT没有问题,但可能需要手动将其他一些存在打包或对齐问题的结构逐字段写入64位进程,以便与64位结构布局匹配。

我无法使此解决方案工作。所以,我做了一些搜索,这里给出的解决方案对我有用


除了这是指向矩形的指针数组,而不是矩形数组。为每个指针[i]分配指针大小的内存块,然后将16个字节(sizeof(RECT))封送到该点。这种类型的溢出会导致灾难。您发布的是什么消息会自动对4个矩形的数组进行跨进程封送处理?我试图告诉DLL(由于它是64位的,所以托管在另一个进程中)忽略屏幕的某些区域。它不一定是4个矩形。根据您的更新,您没有分配足够的空间(intptr.size而不是Marshal.SizeOf(typeof(RECT)))。在x64机器上,指针算法可能会失败,请看我的答案。实际上,指针算法不会失败,因为这段代码中的可执行文件严格来说是32位的,并且永远不会变成64位。:)但你对分配的看法是正确的。
RECT[] foo = new RECT[4];
unsafe
{
    fixed (RECT* pBuffer = foo)
    {
        //Do work with pointer
    }
}