我想转换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或具有布局信息。”)。 我需要以某种方式得到这个数组RECTs的过度使用PostMessage的另一个应用程序,所以我真的需要一个指向这个数据。
什么是我选择这里?
更新 :这似乎是工作:
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)));
}
已更新再解决什么仲裁者评论。
StructureToPtr预计结构对象,和Foo不是结构上,它阵列,这就是为什么出现异常。
我可以建议你写周期(可悲的是,StructureToPtr没有与索引过载)结构:
long LongPtr = ptr.ToInt64(); // Must work both on x86 and x64
for (int I = 0; I < foo.Length; I++)
{
IntPtr RectPtr = new IntPtr(LongPtr);
Marshal.StructureToPtr(foo[I], RectPtr, false); // You do not need to erase struct in this case
LongPtr += Marshal.SizeOf(typeof(Rect));
}
另一种选择是编写结构四个整数,使用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);
}
而最后,你可以使用不安全的关键字,并直接与指针的工作。
仲裁者给你如何编组结构阵列的一个很好的答案。 对于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位的结构布局。
你可以尝试以下方法:
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
而且不要忘记你完成后释放一切。
我无法得到这个解决方案正常工作。 所以,我做了一些搜索,在这里给我工作的解决方案。
http://social.msdn.microsoft.com/Forums/en-US/clr/thread/dcfd6310-b03b-4552-b4c7-6c11c115eb45