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[]
]
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With