Copy from IntPtr (16 bit) array to managed ushort

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.

Tags:

C#

.Net