मैं byte[]एक विधि में एक पारित करने के लिए IntPtrसी # में एक पैरामीटर लेता है , क्या यह संभव है और कैसे?
GCHandleविधि एक आकर्षण की तरह काम करती है ... fixedविधि भी । : पी :))
मैं byte[]एक विधि में एक पारित करने के लिए IntPtrसी # में एक पैरामीटर लेता है , क्या यह संभव है और कैसे?
GCHandleविधि एक आकर्षण की तरह काम करती है ... fixedविधि भी । : पी :))
जवाबों:
किसी सरणी में IntPtr प्राप्त करने के बारे में निश्चित नहीं है, लेकिन आप Mashal.Cl का उपयोग करके अप्रबंधित कोड के साथ उपयोग के लिए डेटा की प्रतिलिपि बना सकते हैं:
IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
// Call unmanaged code
Marshal.FreeHGlobal(unmanagedPointer);
वैकल्पिक रूप से आप एक संपत्ति के साथ एक संरचना की घोषणा कर सकते हैं और फिर मार्शल का उपयोग कर सकते हैं। PtrToStructure, लेकिन यह अभी भी अप्रबंधित स्मृति को आवंटित करने की आवश्यकता होगी।
संपादित करें: इसके अलावा, जैसा कि टायलिस ने बताया, यदि आप असुरक्षित कोड आपके लिए एक विकल्प हैं, तो आप निश्चित का भी उपयोग कर सकते हैं
Marshal.Copyउस अधिभार के साथ एक शुरुआत सूचकांक की आवश्यकता होती है। कॉल होना चाहिएMarshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
दूसरा रास्ता,
GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
// Do your stuff...
pinnedArray.Free();
यह काम करना चाहिए लेकिन असुरक्षित संदर्भ में उपयोग किया जाना चाहिए:
byte[] buffer = new byte[255];
fixed (byte* p = buffer)
{
IntPtr ptr = (IntPtr)p;
// do you stuff here
}
सावधान, आपको निर्धारित ब्लॉक में सूचक का उपयोग करना होगा! एक बार जब आप निर्धारित ब्लॉक में नहीं होते हैं, तो जीसी ऑब्जेक्ट को स्थानांतरित कर सकता है।
आप Marshal.UnsafeAddrOfPinnedArrayElement(array, 0)सरणी में मेमोरी पॉइंटर प्राप्त करने के लिए उपयोग कर सकते हैं ।
यहां @ user65157 के उत्तर (उस के लिए +1, BTW) पर एक ट्विस्ट है:
मैंने पिन की गई वस्तु के लिए एक आइडीएसोपॉली रैपर बनाया:
class AutoPinner : IDisposable
{
GCHandle _pinnedArray;
public AutoPinner(Object obj)
{
_pinnedArray = GCHandle.Alloc(obj, GCHandleType.Pinned);
}
public static implicit operator IntPtr(AutoPinner ap)
{
return ap._pinnedArray.AddrOfPinnedObject();
}
public void Dispose()
{
_pinnedArray.Free();
}
}
फिर इसे इस तरह उपयोग करें:
using (AutoPinner ap = new AutoPinner(MyManagedObject))
{
UnmanagedIntPtr = ap; // Use the operator to retrieve the IntPtr
//do your stuff
}
मैंने इसे फ्री () कॉल करने की भूल न करने का एक अच्छा तरीका पाया :)
मार्शल। कोपी काम करता है लेकिन धीमी गति से होता है। तेजी से लूप में बाइट्स को कॉपी करना है। यहां तक कि तेजी से बाइट सरणी को एक उल्टी सरणी में डालना है, बाइट सरणी में फिट होने के लिए उतने ही उल्टे कॉपी करें, फिर संभावित शेष 7 बाइट्स को कॉपी करें (निशान जो 8 बाइट्स संरेखित नहीं है)। सबसे तेज बाइट सरणी को एक निश्चित विवरण में पिन करना है जैसा कि टायलिस के उत्तर में प्रस्तावित है।
IntPtr GetIntPtr(Byte[] byteBuf)
{
IntPtr ptr = Marshal.AllocHGlobal(byteBuf.Length);
for (int i = 0; i < byteBuf.Length; i++)
{
Marshal.WriteByte(ptr, i, byteBuf[i]);
}
return ptr;
}
कुछ मामलों में आप Int32 के मामले में एक Int32 प्रकार (या Int64) का उपयोग कर सकते हैं। यदि आप कर सकते हैं, तो एक और उपयोगी वर्ग BitConverter है। आप जो चाहते हैं, उसके लिए आप BitConverter.ToInt32 का उपयोग कर सकते हैं।
Int32एक संकेतक के रूप में सही और सुरक्षित रूप से उपयोग कर सकते हैं । यह सालों पहले किया गया एक बुरा अभ्यास था और यह सभी प्रकार के पोर्टिंग मुद्दों को जन्म देता है। यहां तक कि एक Int64सुरक्षित भी नहीं है क्योंकि पहले से ही 128-बिट आर्किटेक्चर हैं और सूचक आकार में वृद्धि होगी। पॉइंटर्स को केवल पॉइंटर्स के रूप में दर्शाया जाना चाहिए।
int/ longसंकेत के लिए है जब उपयोग की गई भाषा (उदाहरण के VB6 के लिए) उनमें से कोई अवधारणा नहीं है। C # पॉइंटर्स को सपोर्ट करता है और है IntPtr- इसमें intपॉइंटर की जगह कभी भी इस्तेमाल करने की कोई जरूरत नहीं है । यदि आप अपने चेतावनियों में संभावित चेतावनियों और संभावित मुद्दों की व्याख्या जोड़ते हैं तो मैं अपना -1 हटा दूंगा।