6

I can't figure out how does the Copy(IntPtr[], Int32, IntPtr, Int32) method works. I though it could copy the data contained in multiple IntPtrs into a single IntPtr (as MSDN states) but apparently it doesn't work as I expected:

IntPtr[] ptrArray = new IntPtr[]
{
    Marshal.AllocHGlobal(1),
    Marshal.AllocHGlobal(2)
 };

 Marshal.WriteByte(ptrArray[0], 0, 0xC1);

 // Allocate the total size.
 IntPtr ptr = Marshal.AllocHGlobal(3);

 Marshal.Copy(ptrArray, 0, ptr, ptrArray.Length);

 // I expect to read 0xC1 but Value is always random!!
 byte value = Marshal.ReadByte(ptr, 0);

Does someone know if I'm using this method for something that it is not its purpose?

mainvoid
  • 347
  • 1
  • 4
  • 17
  • IntPtr ptr = Marshal.AllocHGlobal(3 * sizeof(IntPtr)); – Guillaume Nov 27 '14 at 09:52
  • Do keep in mind what you are copying. You are only copying the pointer values, not the values that the pointers are pointing to. Arbitrarily, Marshal.ReadByte(Marshal.ReadIntPtr(ptr), 0) gives you that byte back. But surely isn't what you had in mind. – Hans Passant Nov 27 '14 at 10:26

1 Answers1

2
    static void Main(string[] args)
    {
        IntPtr[] ptrArray = new IntPtr[]
        {
            Marshal.AllocHGlobal(1),
            Marshal.AllocHGlobal(2)
        };

        Marshal.WriteByte(ptrArray[0], 0, 100);

        int size = Marshal.SizeOf(typeof(IntPtr)) * ptrArray.Length;
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.Copy(ptrArray, 0, ptr, ptrArray.Length);

        // Now we have native pointer ptr, which points to two pointers,
        // each of thme points to its own memory (size 1 and 2).

        // Let's read first IntPtr from ptr:
        IntPtr p = Marshal.ReadIntPtr(ptr);

        // Now let's read byte from p:
        byte b = Marshal.ReadByte(p);

        Console.WriteLine((int)b);    // prints 100

        // To do: release all IntPtr
    }

Read explanations in the comments.

Alex F
  • 42,307
  • 41
  • 144
  • 212
  • If that is right then I find the comment on [Marshal.Copy Method (IntPtrArray, Int32, IntPtr, Int32)](http://msdn.microsoft.com/en-us/library/vstudio/ms146638%28v=vs.100%29.aspx) : _Copies data from a one-dimensional, managed IntPtr array to an unmanaged memory pointer_ rather misleading as not the data but the pointers are copied..!? - Also: This does not create a contiguous memory area, so to access a random byte will be a hassle, right, or there some magic at work? – TaW Nov 27 '14 at 10:11
  • This means, that this method copies pointers to unmanaged memory area. Each pointer may point to some other memory. If you want to have an array which contains two other unmanaged arrays, allocate 3 bytes (in your case) and apply `Marshal.Copy Method (IntPtr,Byte[], Int32, Int32)` twice. – Alex F Nov 27 '14 at 10:37
  • Correction: you need to read every `IntPtr` to 2 managed `byte` arrays first: `Marshal.Copy Method (IntPtr,Byte[], Int32, Int32)`, then copy from them to 3-byte unmanaged block, applying twice `Marshal.Copy Method (Byte[], Int32, IntPtr, Int32)`. Or use CopyMemory API (direct copy between two unmanaged memory blocks). – Alex F Nov 27 '14 at 10:51