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[]` ]