2012-04-02 20 views
5

मैं एक 3 पार्टी सी पुस्तकालय के रूप में निम्नानुसार है जो अपने निर्यात विधि के में से एक है है के साथ आवंटित:बार-बार दोहराना Marshal.AllocHGlobal()

#define MAX_INDEX 8 
int GetStuff(IN char* index[MAX_INDEX], OUT char* buf, IN size_t size); 

पहला तर्क buf तर्क जहां विशिष्ट में संकेत के साथ से भर जाता है तारों को संग्रहित किया जाता है। आकार इंगित करता है कि प्रत्येक स्ट्रिंग को बफ बफर में कितनी देर तक होने की उम्मीद है। मेरे सी # पी/इस के लिए आह्वान विधि वर्तमान में इस तरह दिखता है:

[DllImport("Path/To/Dll", CharSet = CharSet.Ansi)] 
private static extern int GetStuff(IntPtr indecies, IntPtr buf, Int32 size); 

सी # पी/आह्वान विधि निजी क्योंकि मैं इसे एक सार्वजनिक "गेटर" विधि है जो स्मृति के आवंटन/आवंटन रद्द करने संभालती में कार्यक्षमता है लपेटकर कर रहा हूँ है कॉलर के लिए। जब मैं सी ++ में इस विधि का उपयोग करता हूं, तो वास्तव में पुनरावृत्ति काफी सरल है। मैं बस की तरह कुछ कार्य करें:

char* pIndecies[MAX_INDEX]; 
char* pBuffer = new char[MAX_INDEX * (256 + 1)]; // +1 for terminating NULL 

GetStuff(pIndecies, pBuffer, 256); 

// iterate over the items 
for(int i(0); i < MAX_INDEX; i++) { 
    if(pIndecies[i]) { 
     std::cout << "String for index: " << i << " " << pIndecies[i] << std::endl; 
    } 
} 
क्योंकि कैसे इन सी ++ में किया जाता है की

, मैंने तय कर लिया मैं शायद IntPtr वस्तुओं का उपयोग करना चाहिए और सिर्फ याद है कि मैं ढेर से की आवश्यकता होगी, मूल कोड में फोन का आवंटन, और जिस तरह से मैं सी ++ में करता हूं उस पर पुन: प्रयास करें। तब मुझे याद आया कि सी # में वर्ण यूनिकोड वर्ण हैं और ASCII वर्ण नहीं हैं। सी # में पुनरावृत्ति वही काम करेगी, भले ही मैंने पुनरावृत्ति को एक असुरक्षित कोड ब्लॉक में रखा हो? मेरी पहली सोचा निम्न करने के लिए था: "मैं कैसे क्या यह मूल कोड विधि रिटर्न से अधिक पुनरावृति चाहिए"

IntPtr pIndecies = Marshal.AllocHGlobal(MAX_INDEX * 4); // the size of a 32-pointer 
IntPtr pBuffer = Marshal.AllocHGlobal(MAX_INDEX * (256 + 1)); // should be the same 
NativeMethods.GetStuff(pIndecies, pBuffer, 256); 

unsafe { 
    char* pCStrings = (char*)pIndecies.ToPointer(); 
    for(int i = 0; i < MAX_INDEX; i++) { 
     if(pCStrings[i]) 
      string s = pCStrings[i]; 
    } 
} 

मेरा प्रश्न तो यह है क्या यह इस समारोह में मार्शल का सही तरीका है? क्या मुझे दूसरे तर्क के लिए स्ट्रिंगबिल्डर ऑब्जेक्ट का उपयोग करना चाहिए? एक बाधा समस्या यह है कि पहला तर्क GetStuff() विधि के पीछे एक संरचना का 1: 1 मैपिंग है। दूसरे बफर तर्क में जो कुछ आप देख रहे हैं उसे समझने के लिए प्रत्येक अनुक्रमणिका का मान महत्वपूर्ण है।

मैं किसी भी सुझाव की सराहना करता हूं।

धन्यवाद, एंडी

उत्तर

3

मुझे लगता है कि आप सही रास्ते पर हैं, लेकिन मैं असुरक्षित कोड का उपयोग किए बिना यह करना चाहते हैं। इस तरह:

[DllImport("Path/To/Dll", CharSet = CharSet.Ansi)] 
private static extern int GetStuff(IntPtr[] index, IntPtr buf, Int32 size); 
.... 
IntPtr[] index = new IntPtr[MAX_INDEX]; 
IntPtr pBuffer = Marshal.AllocHGlobal(MAX_INDEX * 256 + 1); 
try 
{ 
    int res = NativeMethods.GetStuff(index, pBuffer, 256); 
    // check res for errors? 
    foreach (IntPtr item in index) 
    { 
     if (item != IntPtr.Zero) 
      string s = Marshal.PtrToStrAnsi(item); 
    } 
} 
finally 
{ 
    Marshal.FreeHGlobal(pBuffer); 
} 

यह आपके सी ++ संस्करण का एक बहुत सीधा अनुवाद है।

+0

मुझे यह प्रस्ताव पसंद है और यह कुछ कोशिश करेगा जब कुछ हार्डवेयर मुक्त हो जाएंगे (यह तृतीय पक्ष लाइब्रेरी हार्डवेयर के खिलाफ काम करती है जो स्वयं और दो अन्य लोग साझा करते हैं)। अगर यह बिल फिट बैठता है तो मैं उत्तर के रूप में ध्वजांकित करना सुनिश्चित कर दूंगा। मुझे लगता है यह होगा। आप जानते हैं, मैंने IntPtr की सरणी बनाने के बारे में नहीं सोचा था। वह बहुत चिकना है। –

+0

समाधान के लिए बहुत बहुत धन्यवाद। फोरैच लूप में मैं आइटम की जांच नहीं कर सका। ज़ीरो और इसलिए सशर्त होना चाहिए (आइटम! = IntPtr.Zero)। मैंने कोड संपादित किया है लेकिन इसे सहकर्मी की समीक्षा करने की आवश्यकता है (एक बुद्धिमान सावधानी)। एक बार फिर धन्यवाद। –

+0

@AndrewFalanga वह समाधान ठीक है। इसका मतलब एक ही बात है। मुझे लगता है कि .NET 4 के साथ IntPtr में कुछ बदलाव हुए थे 4. क्या आप निम्न संस्करण पर हैं? –

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