Copy from IntPtr (16 bit) array to managed ushort

匿名 (未验证) 提交于 2019-12-03 08:46:08

问题:

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

回答1:

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.



回答2:

Seems like you're stuck with either doing the extra conversion yourself (short[] to ushort[], the one you basically do already), or doing the mem copy yourself through unsafe keyword.

There's third option: create custom struct.

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

You'd also have to use Marshal.PtrToStructure<MyMagicalStruct>(yourPtr)..



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!