Copy from IntPtr (16 bit) array to managed ushort

.net, c#

Solution

Option 1 - call `CopyMemory`:

[DllImport("kernel32.dll", SetLastError = false)]
static extern void CopyMemory(IntPtr destination, IntPtr source, UIntPtr length);

public static void Copy<T>(IntPtr source, T[] destination, int startIndex, int length)
    where T : struct
{
    var gch = GCHandle.Alloc(destination, GCHandleType.Pinned);
    try
    {
        var targetPtr = Marshal.UnsafeAddrOfPinnedArrayElement(destination, startIndex);
        var bytesToCopy = Marshal.SizeOf(typeof(T)) * length;

        CopyMemory(targetPtr, source, (UIntPtr)bytesToCopy);
    }
    finally
    {
        gch.Free();
    }
}

Not portable, but has nice performance.

Option 2 - `unsafe` and pointers:

public static void Copy(IntPtr source, ushort[] destination, int startIndex, int length)
{
    unsafe
    {
        var sourcePtr = (ushort*)source;
        for(int i = startIndex; i < startIndex + length; ++i)
        {
            destination[i] = *sourcePtr++;
        }
    }
}

Requires `unsafe` option to be enabled in project build properties.

Option 3 - reflection (just for fun, don't use in production):

`Marshal` class internally uses `CopyToManaged(IntPtr, object, int, int)` method for all `Copy(IntPtr, <array>, int, int)` overloads (at least in .NET 4.5). Using reflection we can call that method directly:

private static readonly Action<IntPtr, object, int, int> _copyToManaged =
    GetCopyToManagedMethod();

private static Action<IntPtr, object, int, int> GetCopyToManagedMethod()
{
    var method = typeof(Marshal).GetMethod("CopyToManaged",
        System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
    return (Action<IntPtr, object, int, int>)method.CreateDelegate(
        typeof(Action<IntPtr, object, int, int>), null);
}

public static void Copy<T>(IntPtr source, T[] destination, int startIndex, int length)
    where T : struct
{
    _copyToManaged(source, destination, startIndex, length);
}

Since `Marshal` class internals can be changed, this method is unreliable and should not be used, though this implementation is probably the closest to other `Marshal.Copy()` method overloads.

Problem

I have a `IntPtr` called rawbits, which points to a 10MB array of data, 16 bit values. I need to return a managed `ushort` array from that. The following code works but there is an extra `BlockCopy` I would like to get rid of. `Marshal.Copy` does not support `ushort`. What can I do? (FYI: the rawbits is filled in by a video framegrabber card into unmanaged memory) ``` public const int width = 2056; public const int height = 2048; public const int depth = 2; public System.IntPtr rawbits; public ushort[] bits() { ushort[] output = new ushort[width * height]; short[] temp = new short[width * height]; Marshal.Copy(rawbits, temp, 0, width * height); System.Buffer.BlockCopy(temp, 0, output, 0, width * height * depth); return output; } ``` The suggestions given in the following question did not help. (compiler error). C# Marshal.Copy Intptr to 16 bit managed unsigned integer array [BTW, the short array does have unsigned 16 bit data in it. The `Marshal.Copy()` does not respect the sign, and that is what I want. But I would rather not just pretend that the `short[]` is a `ushort[]` ]

Original source

Related problems