2015-02-18 3 views
6

प्रबंधित करने के लिए IntPtr (16 बिट) सरणी से कॉपी करें मेरे पास एक इंटप्राट है जिसे कच्चे बिट कहा जाता है, जो 10 एमबी सरणी डेटा, 16 बिट मानों को इंगित करता है। मुझे उस से एक प्रबंधित ushort सरणी वापस करने की जरूरत है। निम्नलिखित कोड काम करता है लेकिन एक अतिरिक्त ब्लॉककॉपी है जिसे मैं छुटकारा पाना चाहता हूं। मार्शल.कॉपी ushort का समर्थन नहीं करता है। मैं क्या कर सकता हूँ? (FYI: rawbits अप्रबंधित स्मृति में एक वीडियो framegrabber कार्ड द्वारा भरा जाता है)प्रबंधित यूहॉर्ट

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; 
} 

निम्नलिखित प्रश्न मदद नहीं की में दिए गए सुझाव। (कंपाइलर त्रुटि)।

C# Marshal.Copy Intptr to 16 bit managed unsigned integer array

[Btw, लघु सरणी उस में अहस्ताक्षरित 16 बिट डेटा होता है। मार्शल.कॉपी() संकेत का सम्मान नहीं करता है, और यही वह है जो मैं चाहता हूं। लेकिन मैं सिर्फ इतना नहीं दिखाता कि छोटा [] एक यूहॉर्ट है []]

उत्तर

7

विकल्प 1 - फोन 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(); 
    } 
} 

पोर्टेबल नहीं है, लेकिन अच्छा प्रदर्शन किया है।


विकल्प 2 - unsafe और संकेत:

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++; 
     } 
    } 
} 

आवश्यक है unsafe विकल्प परियोजना में सक्षम होने के लिए गुण का निर्माण।


विकल्प 3 - प्रतिबिंब (सिर्फ मनोरंजन के लिए, उत्पादन में उपयोग न करें):

Marshal वर्ग आंतरिक रूप से सभी Copy(IntPtr, <array>, int, int) भार के (कम से कम .NET 4.5 में) के लिए CopyToManaged(IntPtr, object, int, int) विधि का उपयोग करता। प्रतिबिंब का उपयोग करते हुए हम सीधे कि विधि कॉल कर सकते हैं:

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); 
} 

Marshal के बाद से वर्ग internals बदला जा सकता है, इस विधि अविश्वसनीय है और नहीं किया जाना चाहिए, हालांकि इस कार्यान्वयन शायद अन्य Marshal.Copy() विधि भार के सबसे करीब है।

+0

सरणी को एक पॉइंटर –

+0

'फिक्स्ड' में कनवर्ट करते समय आपको 'निश्चित' का उपयोग करना चाहिए, सामान्य 'कॉपी ()' विधि बनाने के लिए उपयोग नहीं किया जा सकता क्योंकि 'निश्चित (टी * पीआरटी = सरणी)' संकलित नहीं होगा। इसकी अनुमति देने के लिए कोई सामान्य बाधा नहीं है। 'GCHandle' का उपयोग करते समय भी 'निश्चित' के लिए 'असुरक्षित' विकल्प की आवश्यकता होती है। – max

+0

महान उत्तर। प्रदर्शन के क्रम में रैंकिंग के रूप में कोई अंतर्ज्ञान? [ऐसा नहीं है कि मैं सामान्य मोड में प्रबंधित स्थान पर यह रूपांतरण करता हूं, लेकिन डीबग के लिए 25 एफपीएस यातायात को मेजबान में बदलने के लिए उपयोगी है, इसे प्रोसेसिंग के लिए जीपीयू को भेजने के बजाय)। –

0

ऐसा लगता है कि आप या तो अतिरिक्त रूपांतरण स्वयं कर रहे हैं (लघु [] से ushort [], जिसे आप मूल रूप से पहले से करते हैं), या असुरक्षित कीवर्ड के माध्यम से स्वयं को याद करते हैं।

तीसरा विकल्प है: कस्टम संरचना बनाएं।

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

तुम भी Marshal.PtrToStructure<MyMagicalStruct>(yourPtr) उपयोग करने के लिए होगा ..

संबंधित मुद्दे