Copy from IntPtr array (16 bit) to ushort managed

I have an IntPtr called rawbits that points to a 10 MB data array, 16 bits. I need to return a ushort managed array. The following code works, but there is an additional BlockCopy that I would like to get rid of. Marshal. Mine does not support us. What can I do? (FYI: rawbits populated with a video card in 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 next question did not help. (compiler error).

C # Marshal.Copy Intptr for a 16-bit unsigned array

[BTW, the short array has unsigned 16-bit data in it. Marshall Kopi () does not follow the sign, and this is what I want. But I would rather not just pretend that short [] is a ushort [] symbol

+6
source share
2 answers

Option 1 - calling 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 good 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++; } } } 

It is required to enable the unsafe parameter in the project build properties.


Option 3 - reflection (just for fun, not used in production ):

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

 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 internal variables can be changed, this method is unreliable and should not be used, although this implementation is probably the closest to other overloads of the Marshal.Copy() method.

+7
source

It looks like you're stuck in doing an extra conversion yourself (short [] to ushort [], which you mostly do), or make a mem-copy yourself using an unsafe keyword.

There is a third option: create a custom structure.

 struct MyMagicalStruct { // todo: set SizeConst correct [MarshalAs(UnmanagedType.ByValArray, SizeConst=width*height)] public ushort[] Test123; } 

You will also need to use Marshal.PtrToStructure<MyMagicalStruct>(yourPtr) ..

0
source

Source: https://habr.com/ru/post/982713/


All Articles