2010-04-12 18 views
6

के बीच इस प्रकार मैं एक DLL जो एक डिकोडिंग समारोह प्रदान की है:पूर्व आवंटित स्मृति HostApp और DLL

function MyDecode (Source: PChar; SourceLen: Integer; var Dest: PChar; DestLen: Integer): Boolean; stdcall; 

HostApp कॉल "MyDecode", और स्रोत, SourceLen और डेस्ट मापदंडों में स्थानांतरित, डीएलएल ने डेस्ट और डेस्टलेन को डीकोड किया। समस्या यह है: होस्ट ऐप को डीकोडेड डेस्ट लम्बाई को जानना असंभव है, और इसलिए यह नहीं पता होगा कि डेस्ट की स्मृति को पूर्व-आवंटित कैसे किया जाए।

मुझे पता है कि दो कार्यों में "MyDecode" विभाजित कर सकते हैं:

function GetDecodeLen (Source: PChar; SourceLen: Integer): Integer; stdcall; // Return the Dest's length 
function MyDecodeLen (Source: PChar; SourceLen: Integer; var Dest: PChar): Boolean; stdcall; 

लेकिन, मेरे डिकोडिंग प्रक्रिया बहुत जटिल है, इसलिए यदि दो कार्यों में विभाजित दक्षता को प्रभावित करेगा।

क्या कोई बेहतर समाधान है?


हाँ अलेक्जेंडर, यह एक अच्छा समाधान हो सकता है। HostApp कोड:

//... 
MyDecode(....) 
try 
    // Use or copy Dest data 
finally 
    FreeDecodeResult(...) 
end; 

DLL कोड:

function MyDecode(...): Boolean; 
begin 
    // time-consuming calculate 

    // Allocate memory 
    GetMem(Dest, Size); 
    // or New()? 
    // or HeapAlloc()? 
end; 

procedure FreeDecodeResult(Dest: PChar); 
begin 
    FreeMem(Dest); 
    // or Dispose(Dest); ? 
    // or HeapFree(Dest); ? 
end; 

शायद मैं सूचक को उसके गंतव्य के प्रकार बदलना चाहिए।

मेमोरी विधि बेहतर आवंटित कौन सा है? GetMem/New, या HeapAlloc?

+0

आप किस समस्या को हल करने की कोशिश कर रहे हैं: 1) अग्रिम आवंटित राशि का आकलन कैसे करें; 2) कॉलर और कैली के बीच गतिशील स्मृति प्रबंधन का समन्वय कैसे करें? –

+0

मार्सेलो के लिए: 1) कॉलर अग्रिम आवंटित राशि को नहीं समझ सकता है। 2) हां। – Leo

+0

> मेमोरी विधि को बेहतर आवंटित कौन सा है? आपके मामले में इससे कोई फर्क नहीं पड़ता। विधि का प्रयोग करें, जिसे आप परिचित हैं (मैं GetMem/FreeMem पसंद करता हूं)। – Alex

उत्तर

8

आप अन्य माध्यम से दो दिनचर्या में "MyDecode" विभाजित कर सकते हैं:

function MyDecode(Source: PChar; SourceLen: Integer; out Dest: PChar; out DestSize: Integer): Boolean; stdcall; 
procedure FreeDecodeResult(Dest: PChar); stdcall; 

अर्थात - आप कॉलर से ऐसा करने के बजाय माईडेकोड में मेमोरी आवंटित करते हैं।

+0

नोट, कि आप FreeDecodeResult को लागू नहीं कर सकते हैं, अगर आप कॉलर और कैली दोनों के लिए कुछ सामान्य आवंटकों का उपयोग करेंगे। उदाहरण के लिए, यदि आप GetMem के बजाय LocalAlloc के माध्यम से स्मृति आवंटित करते हैं। फिर कॉलर को FreeDecodeResult के बजाय LocalFree को कॉल करना चाहिए। – Alex

5

आप उसी तकनीक का उपयोग कर सकते हैं जो अधिकांश विंडोज एपीआई उपयोग करता है, यानी, यदि आपका बफर पर्याप्त बड़ा नहीं है, तो फ़ंक्शन आवश्यक बफर का आकार देता है। इस तरह, आप कॉलिंग फ़ंक्शन से सही आकार के बफर को आवंटित कर सकते हैं।

function MyDecode (Source: PChar; SourceLen: Integer; Dest: PChar; var Len: Integer): Boolean; stdcall; 

procedure SomeProc; 
var iSourceLen, iLenNeeded : Integer; 
    pSource, pDest : Pointer; 
begin 
    MyDecode(pSource, iSourceLen, nil, iLenNeeded); 
    GetMem(pDest,iLenNeeded); 
    try 
    MyDecode(pSource, iSourceLen,pDest, iLenNeeded); 
    finally 
    FreeMem(pDest); 
    end; 
end; 

संपादित: mghie द्वारा सुझाव दिया गया है। चूंकि पैरामीटर पीसीएचएआर है, यह माना जाएगा कि माइडेकोड द्वारा लौटाया गया ILenNeeded विंडोज एपीआई द्वारा मानक (ज्यादातर?) मानक के रूप में आवश्यक टीसीएचएआर की संख्या होगी।

function SomeProc(sEncode : String) : string; 
var iLenNeeded : Integer; 
begin 
    MyDecode(PChar(sEncode), Length(sEncode), nil, iLenNeeded); 
    SetLength(Result, iLenNeeded); //if iLenNeeded include a null-terminating character, you can use (iLenNeeded - 1) instead 
    if not MyDecode(PChar(sEncode), Length(sEncode), PChar(Result), iLenNeeded) then 
    SetLength(Result, 0); 
end; 
+0

+1, लेकिन इसमें भ्रम के लिए कुछ संभावित क्षमता है, क्योंकि 'लेन' का अर्थ या तो बफर लंबाई या स्ट्रिंग लम्बाई हो सकता है। सुरक्षित पक्ष पर रहने के लिए मैं स्ट्रिंग पर 'GetMem() 'लेकिन' SetLength()' का उपयोग नहीं करता, यह पीछे के शून्य चरित्र का ख्याल रखेगा। दक्षता के संबंध में: यदि डीएलएल डीकोडेड डेटा को 'थ्रेडवर' में कैश करता है तो इसे कम कुशल नहीं होना चाहिए। – mghie

+0

माईडेकोड के सटीक कार्यान्वयन के आधार पर, पीचर का उपयोग करना सबसे अच्छा विचार नहीं हो सकता है ... लेकिन मैं इसे संपादित करूँगा और वैकल्पिक उपयोग दिखाऊंगा। –

+0

हां, मुझे पता है कि यह विंडोज एपीआई समाधान है। यदि डीएलएल मज़ेशन सरल है तो यह सबसे अच्छा समाधान हो सकता है। लेकिन मेरा "माईडियोड" एक समय लेने वाला मज़ेदार है, इसलिए मैं इसे दो बार कॉल नहीं करना चाहता हूं। – Leo

2

एक और विकल्प डीएल में स्मृति आवंटित करने के लिए एक फ़ंक्शन पॉइंटर को पास करना है। डीएलएल इस कार्य को कॉल करता है जब उसे स्मृति की आवश्यकता होती है और चूंकि स्मृति को एप्लिकेशन के मेमोरी मैनेजर का उपयोग करके आवंटित किया जाता है, तो एप्लिकेशन इसे मुक्त कर सकता है।

दुर्भाग्यवश यह वास्तव में आपकी समस्या का समाधान नहीं करता है बल्कि केवल इसे डीएलएल में ले जाता है जिसे तब समझना चाहिए कि उसे कितनी मेमोरी चाहिए। हो सकता है कि आप एक लिंक्ड सूची में संग्रहीत कई बफर का उपयोग कर सकें ताकि प्रत्येक बार जब डीकोड फ़ंक्शन मेमोरी से बाहर हो जाए तो यह केवल एक और बफर आवंटित करता है।

1

मुझे यकीन है कि अगर यह आप सूट नहीं कर रहा हूँ, लेकिन WideString (इस विशेष उदाहरण में) आप का उपयोग कर सकते हैं:

function MyDecode(Source: PChar; SourceLen: Integer; out Dest: WideString): Boolean; stdcall; 

या:

function MyDecode(Source: PChar; SourceLen: Integer): WideString; stdcall; 

आप WideString कर सकते हैं का उपयोग करके स्मृति आवंटन समस्याओं से बचें।

यह क्यों काम करेगा? क्योंकि वाइडस्ट्रिंग सिस्टम के प्रकार BSTR के लिए उपनाम है। और बीस्ट्रेट के पास विशेष नियम है: इसकी मेमोरी विशिष्ट सिस्टम मेमोरी मैनेजर के माध्यम से आवंटित की जानी चाहिए। अर्थात। जब आप वाइडस्ट्रिंग के साथ काम करते हैं, डेल्फी इस सिस्टम मेमोरी मैनेजर को कॉल करता है, न कि स्वयं। चूंकि सिस्टम मेमोरी मैनेजर प्रत्येक मॉड्यूल से सुलभ है (और यह प्रत्येक मॉड्यूल के लिए समान है) - इसका मतलब है कि दोनों कॉलर (एक्सई) और कैली (डीएलएल) एक ही मेमोरी मैनेजर का उपयोग करेंगे, इस प्रकार उन्हें बिना किसी समस्या के डेटा पास करने की अनुमति मिल जाएगी।

तो, आप वाइडस्ट्रिंग का उपयोग कर सकते हैं और स्मृति के बारे में चिंता किए बिना केवल परिणाम उत्पन्न कर सकते हैं। बस ध्यान दें, वाइडस्ट्रिंग में चार्टर्स यूनिकोड हैं - यानी 2 बाइट्स। यदि आप D2007 और नीचे का उपयोग कर रहे हैं, तो आपके पास एएनएसआई < -> यूनिकोड को परिवर्तित करने के साथ थोड़ा ओवरहेड होगा। यह (आमतौर पर) कोई समस्या नहीं है, क्योंकि सामान्य अनुप्रयोग WinAPI कॉलों का एक टन बनाता है - और प्रत्येक WinAPI कॉल का अर्थ एक ही एएनएसआई < -> यूनिकोड कनवर्टन (चूंकि आप ए-फ़ंक्शंस को कॉल कर रहे हैं)।

+0

यह काम करेगा भले ही होस्टैप डेल्फी प्रोग्राम न हो? –

+0

हां, चूंकि वाइडस्ट्रिंग BSTR है, गैर-डेल्फी एप्लिकेशन को BSTR का उपयोग करने की आवश्यकता होगी, जो सिस्टम प्रकार (वास्तव में, एक COM प्रकार) है। यहां देखें: http://msdn.microsoft.com/en-us/library/ms221069(VS.100).aspx सी ++ से BSTR का उपयोग करने का उदाहरण: http://msdn.microsoft.com/en- हमें/पुस्तकालय/xda6xzx7 (VS.100) .aspx – Alex

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