2013-06-04 6 views
9

में नामित प्रक्रिया या फ़ंक्शन को गतिशील रूप से कैसे कार्यान्वित करें मैं फ़ंक्शन तालिका में रहने वाली प्रक्रियाओं या कार्यों को गतिशील रूप से लागू करने की क्षमता के साथ प्रयोग कर रहा हूं। विशिष्ट अनुप्रयोग एक डीएलएल है जो तर्क और प्रकारों की संख्या के साथ एक फ़ंक्शन तालिका में एक सूचक को निर्यात करता है। मेजबान एप्लिकेशन में डीएलएल से पूछताछ करने और कार्यों को कॉल करने की क्षमता होती है। यदि वे ऑब्जेक्ट विधियां थे तो मैं उन्हें आमंत्रित करने के लिए आरटीआई का उपयोग कर सकता था लेकिन वे सामान्य प्रक्रियाएं और कार्य हैं। DLL सामान्य कार्य संकेत दिए गए निर्यात करने के लिए है नहीं वस्तुओं क्योंकि DLL सी, डेल्फी आदि सहित किसी भी भाषा में लिखा जा सकता हैडेल्फी

उदाहरण के लिए, मैं एक रिकॉर्ड की घोषणा की और एक DLL में भरा है:

TAPI = record 
     add : function (var a, b : double) : double; 
     mult : function (var a, b : double) : double; 
end; 
PAPI = ^TAPI; 

मैं पुनः प्राप्त इस रिकॉर्ड के लिए सूचक, घोषित:

apiPtr : PAPI; 

मान लें मैं भी प्रक्रियाओं के नाम की पहुंच है, तर्क और रिकॉर्ड में प्रत्येक प्रविष्टि के लिए तर्क प्रकारों की संख्या।

मान लें कि मैं ऐड फ़ंक्शन को कॉल करना चाहता हूं। जोड़ने के लिए समारोह सूचक होगा:

@apiPtr^.add // I assume this will give me a pointer to the add function 

मुझे लगता है कोई दूसरा रास्ता नहीं है अन्य की तुलना में कुछ एएसएम उपयोग करने के लिए ढेर पर आवश्यक तर्क धक्का और परिणाम पुनः प्राप्त करने के?

पहला सवाल, प्रक्रिया को घोषित करने के लिए सबसे अच्छा कॉलिंग सम्मेलन क्या है, सीडीसीएल? कॉल से पहले ढेर को इकट्ठा करने के लिए सबसे आसान लगता है।

दूसरा प्रश्न, क्या कोई उदाहरण ऑनलाइन है जो वास्तव में ऐसा करता है? मैं http://www.swissdelphicenter.ch/torry/showcode.php?id=1745 (DynamicDllCall) जो मैं चाहता के करीब है भर में आया था, लेकिन मैं सरलीकृत नीचे के रूप में, यह अब परिणाम के लिए सूचक (EAX) देता है:

function DynamicDllCall(proc : pointer; const Parameters: array of Pointer): pointer; 
var x, n: Integer; 
    p: Pointer; 
begin 
n := High(Parameters); 
if n > -1 then begin 
    x := n; 
    repeat 
    p := Parameters[x]; 
    asm 
     PUSH p 
    end; 
    Dec(x); 
    until x = -1; 
end; 
asm 
    CALL proc 
    MOV p, EAX <- must be changed to "FST result" if return value is double 
end; 
result := p; 

अंत;

लेकिन मैं इसे काम नहीं कर सकता, यह परिणाम के बजाय पहले पैरामीटर के लिए एक मूल्य देता है। हो सकता है कि मेरे पास कॉलिंग सम्मेलन गलत हो या शायद मैं गलत समझूं कि ईएक्स में परिणाम कैसे प्राप्त किया जाए।

var proc : pointer; 
    parameters: array of Pointer; 
    x, y, z : double; 
    p : pointer; 
begin 
    x:= 2.3; y := 6.7; 
    SetLength(parameters, 2); 
    parameters[0] := @x; parameters[1] := @y; 
    proc := @apiPtr^.add; 
    p := DynamicDllCall(proc, Parameters); 
    z := double (p^); 

किसी भी सलाह कृतज्ञता प्राप्त किया: इस प्रकार

मैं DynamicDllCall कहते हैं। मैं सराहना करता हूं कि कुछ लोगों को यह महसूस हो सकता है कि ऐसा करने के बारे में कोई नहीं होना चाहिए, लेकिन यदि यह कम से कम संभव है तो भी मैं उत्सुक हूं।

अद्यतन 1 मैं पुष्टि कर सकता हूं कि ऐड फ़ंक्शन को अतिरिक्त करने के लिए सही मान मिल रहे हैं।

अद्यतन 2 अगर मैं करने के लिए जोड़ के हस्ताक्षर बदलने के लिए:

add : function (var a, b, c : double) : double; 

और मैं करने के लिए ग के अंदर जोड़ने के परिणाम दें और इसके बाद मैं पैरामीटर सरणी में सही उत्तर प्राप्त कर सकते हैं (यह मानते हुए मैं एक जोड़ने इसके लिए अधिक तत्व, 2 के बजाय 3)। इसलिए समस्या यह है कि मैं गलत समझता हूं कि कार्यों से मूल्य कैसे लौटाए जाते हैं। क्या कोई समझा सकता है कि फ़ंक्शन मूल्य कैसे लौटते हैं और उन्हें कैसे पुनर्प्राप्त किया जा सकता है?

अद्यतन 3 मेरे पास मेरा जवाब है। मुझे अनुमान लगाया जाना चाहिए था। डेल्फी विभिन्न रजिस्टरों के माध्यम से विभिन्न प्रकार लौटाता है। उदाहरण के लिए ईएक्स के माध्यम से पूर्णांक वापसी, दूसरे हाथ पर डबल एसटी (0) के माध्यम से देता है। परिणाम चर में एसटी (0) की प्रतिलिपि बनाने के लिए मुझे "एमओवी पी, ईएक्स" के बजाय "एफएसटी परिणाम" का उपयोग करना होगा। कम से कम अब मुझे पता है कि ऐसा करने के लिए सिद्धांत में यह संभव है। चाहे यह करने के लिए एक समझदार बात है, अब एक और बात है जिसके बारे में मुझे अब सोचना चाहिए। जो भी कारण के लिए, आप तय कर लिया है वाई समाधान है, लेकिन आप वाई काम करने में परेशानी हो रही आप एक्स करना चाहते हैं, और,:

+0

www.delphi3000.com (लेख/article_3766.asp) पर डेल्फी एएसएम के लिए एक अच्छा परिचय किया गया था, लेकिन यह पूरी साइट अब चली गई है ... –

+1

शायद [विधानसभा प्रक्रियाओं और कार्यों] पर दस्तावेज़ीकरण (http : //docwiki.embarcadero.com/RADStudio/XE4/en/Assembly_Procedures_and_Functions) मदद करेगा। 'फंक्शन परिणाम' विषय देखें। –

+0

वहां बहुत कुछ नहीं है और आधिकारिक दस्तावेज़ भयानक उपयोगी नहीं हैं।हालांकि मैंने पर्याप्त जानकारी प्राप्त की: http://stackoverflow.com/questions/15786404/fld-instruction-x64-bit और http://www.guidogybels.eu/docs/Using%20Assembler%20in% 20Delphi.pdf – rhody

उत्तर

1

यह हल करने में एक कठिन समस्या है। रनटाइम पर डीएलएल में गतिशील रूप से विधियों तक पहुंचने का एक तरीका विदेशी फ़ंक्शन इंटरफ़ेस लाइब्रेरी जैसे libffi, dyncall या DynaCall() का उपयोग करना होगा। इनमें से कोई भी अभी तक डेल्फी पर्यावरण में नहीं भेजा गया है।

यदि आवेदन डीएलएल द्वारा प्रदान की गई आरटीआई जानकारी के साथ एक डीएलएल में विधियों का एक सेट इंटरफ़ेस करना है और उन्हें पाइथन जैसे स्क्रिप्टिंग भाषा में बेनकाब करना है, तो एक विकल्प डेल्फी कोड लिखना है जो डीएलएल का निरीक्षण करता है और लिखता है ctypes संगत स्क्रिप्ट जिसे रनटाइम पर एम्बेडेड पायथन दुभाषिया में लोड किया जा सकता है। जब तक कि हाथ से पहले एक सीमित लेकिन पर्याप्त प्रकार के सेट को परिभाषित करता है जो डीएलएल विधियों को संभाल सकता है, यह एक व्यावहारिक समाधान है।

9

यह एक XY समस्या है। आपके मामले में, एक्स संकेत के माध्यम से कॉल बाहरी कार्यों और वाईमैन्युअल ढेर पर मानकों धक्का है। लेकिन एक्स को पूरा करने के लिए, आपको वास्तव में वाई करने की आवश्यकता नहीं है।

अभिव्यक्ति @apiPtr^.add आपको फ़ंक्शन में सूचक नहीं देगा। यह आपको TAPI रिकॉर्ड के add फ़ील्ड में पॉइंटर देगा। (चूंकि add रिकॉर्ड का पहला सदस्य है, उस क्षेत्र का पता apiPtr में दिए गए पते के बराबर होगा; कोड, Assert(CompareMem(@apiPtr, @apiPtr^.add, SizeOf(Pointer)) में। add फ़ील्ड फ़ंक्शन पर एक पॉइंटर रखता है, इसलिए यदि आप यही चाहते हैं , बस apiPtr^.add का उपयोग करें (और ध्यान दें कि ^ डेल्फी में वैकल्पिक है)।

उपयोग करने के लिए सबसे अच्छा कॉलिंग सम्मेलन stdcall है। डीएलएल कार्यों को निर्यात करने में सहायता करने वाली कोई भी भाषा उस कॉलिंग सम्मेलन का समर्थन करेगी।

आपको अपने कार्यों को कॉल करने के लिए असेंबलर या किसी अन्य मुश्किल स्टैक मैनिपुलेशन की आवश्यकता नहीं है। आप पहले से ही फ़ंक्शन के प्रकार को जानते हैं क्योंकि आपने इसे add घोषित करने के लिए उपयोग किया था। समारोह है कि फ़ील्ड द्वारा इंगित फोन के लिए, बस एक साधारण समारोह फोन करने के लिए के रूप में ही सिंटैक्स का उपयोग करें:

z := apiPtr.add(x, y); 

संकलक, add क्षेत्र के घोषित प्रकार जानता है तो यह आप के लिए ढेर व्यवस्था करेंगे।

+0

आप सही हैं कि मैं apiPtr.add (x, y) का उपयोग कर सकता हूं और यही वह है जिसका मैं उपयोग कर रहा हूं। लेकिन इसका मतलब है कि मुझे संकलन समय पर ऐड फ़ंक्शन के विवरण की आवश्यकता है। मैं रनटाइम जानकारी के आधार पर ऐड कॉल करना चाहता हूं। मेरे डीएलएस प्रत्येक समारोह पर आरटीआई जानकारी प्रदान करने के लिए अतिरिक्त तरीकों का निर्यात कर सकते हैं। इस जानकारी को मुझे रनटाइम पर फ्लाई पर कॉल करने की अनुमति देनी चाहिए। क्यूं कर? मेरा विशेष एप्लिकेशन रनटाइम पर स्क्रिप्टिंग इंजन पर स्वचालित रूप से ऐसी विधियों को उपलब्ध कराने की अनुमति देना है। स्क्रिप्टिंग इंजन को ध्यान नहीं देना चाहिए कि डीएलएल में कौन से फ़ंक्शन उपलब्ध हैं, बस उन्हें उपयोगकर्ता को पास करें। – rhody