2010-07-01 7 views
9

में COM विधि ऑफसेट्स डेल्फी में, मैं COM विधि का पता कैसे ढूंढूं? मैं ऑफसेटडेल्फी

//0 is the offset of the QueryInterface method 
p := TPonterArray(pointer(SomeInterface)^)[0]; 

हार्डकोड कर सकते हैं, लेकिन मैं प्रतीकात्मक नाम का उपयोग करना पसंद करेंगे। अनुवर्ती रूप से काम नहीं करता है:

var M : TMethod; 
... 
M := TMethod(SomeInterface.QueryInterface); 

धन्यवाद!

+3

डेल्फी सभी रक्तमय कॉम विवरण का एक बहुत दूर ले जाता प्राप्त करने के लिए, मुझे लगता है कि आप जिस तरह से अपने आप को बहुत ज्यादा करना चाहते हैं। आप क्या हासिल करने का प्रयास कर रहे हैं? अपना स्वयं का COM सर्वर बनाना या मौजूदा का उपयोग करना? –

+0

क्या आप इंटरफ़ेस में विधि की संख्यात्मक ऑफ़सेट चाहते हैं (उदाहरण के लिए, IUnknown.QueryInterface 0 है), कक्षा में विधि का पता जो उस इंटरफ़ेस विधि को लागू करता है (उदाहरण के लिए, @ TInterfacedObject.QueryInterface), या पते का पता एक इंटरफ़ेस कॉल को संबंधित ऑब्जेक्ट विधि से जोड़ने के लिए जेनरेट किया गया स्टब कोड? उत्तरार्द्ध कक्षा की इंटरफ़ेस तालिका में संग्रहीत है। –

+0

@The_Fox: न तो: मैं Win32Hook.pas का उपयोग कर बाहरी COM ऑब्जेक्ट पर कॉल को रोक रहा हूं। @ रोब केनेडी: कोई TInterfacedObject क्लास नहीं है - मेरे पास केवल बाहरी डीएल द्वारा कार्यान्वित एक इंटरफ़ेस है। –

उत्तर

3

मुझे नहीं लगता कि डेल्फी इसका समर्थन करता है। ऑफसेट्स हार्डकोडिंग शायद एकमात्र चीज है जो काम करेगी, क्योंकि कंपाइलर इंटरफ़ेस विधियों को प्रतीकों के रूप में नहीं मानता है जिनके मूल्य को फ़ंक्शन पॉइंटर को असाइन किया जा सकता है, जिस तरह ऑब्जेक्ट विधियों या स्टैंडअलोन फ़ंक्शन कर सकते हैं।

आप ऐसा करने की कोशिश क्यों कर रहे हैं, बीटीडब्ल्यू?

+1

मैं Win32Hook.pas का उपयोग कर बाहरी COM ऑब्जेक्ट पर कॉल को अवरुद्ध कर रहा हूं - मेरे OutlookSpy (http://www.dimastr.com/outspy/) –

+1

बीटीडब्लू के लिए सिर्फ एक लॉगिंग सुविधा, डेल्फी कंपाइलर स्पष्ट रूप से विधि ऑफ़सेट जानता है, मैं बस हूँ हार्डकोडेड ऑफसेट का उपयोग करने के बजाय ऐसा करने का तरीका खोजने का प्रयास कर रहा है। –

+0

हाँ, संकलक इसके बारे में जानता है, लेकिन जहां तक ​​मैं कह सकता हूं, इसे सीधे प्राप्त करने का कोई तरीका नहीं है। –

6

इंटरफ़ेस की विधि तालिका की शुरुआत के सापेक्ष एक इंटरफ़ेस विधि के बाइट ऑफसेट प्राप्त करने के लिए आप vmtoffset असेंबलर निर्देश का उपयोग कर सकते हैं। उदाहरण के लिए System.pas में _IntfCast के कार्यान्वयन पर एक नजर डालें,:

call dword ptr [eax] + vmtoffset IInterface.QueryInterface 
... 
call dword ptr [eax] + vmtoffset IInterface._Release 

पहली अभिव्यक्ति 0 कहते हैं, दूसरा, 8.

हालांकि आप उन अभिव्यक्तियों को पैरामीटर नहीं कर सकते हैं। वे संकलन-समय स्थिरांक हैं, इसलिए आप यह नहीं चुन सकते कि आप किस समय पर चलाना चाहते हैं। आपको पहले से प्रदर्शित सभी संभावित विधि नामों की आवश्यकता है।

आप सभी वास्तव में को हुक करने की आवश्यकता है QueryInterface। एक बार आपके पास हो जाने के बाद, आप जो भी प्रॉक्सी ऑब्जेक्ट चाहते हैं उसे वापस कर सकते हैं जो सभी अन्य तरीकों से कॉल को रोक सकता है।

+0

यह आशाजनक लग रहा है ... मैं इसे बाद में आजमाउंगा और परिणाम पोस्ट करूंगा। धन्यवाद! –

2

आपका कोड गलत है क्योंकि एक इंटरफ़ेस संदर्भ एक इंटरफ़ेस विधि तालिका के लिए सूचक नहीं है लेकिन एक इंटरफ़ेस विधि तालिका पर पॉइंटर के लिए एक सूचक है। इस प्रकार डेल्फी इंटरफेस बाइनरी स्तर पर लागू किए जाते हैं। अधिक कहना मुश्किल है और अपने कोड में त्रुटि को इंगित करें क्योंकि आपने कोड कोड नहीं दिया है जिसे संकलित किया जा सकता है। विधि सूचक के लिए इंटरफ़ेस संदर्भ सही ढंग से परिवर्तित करने के लिए निम्न कोड का उपयोग, विचार Barry Kelly's demonstration of creating a method pointer from a method reference से लिया गया है:

procedure IntRefToMethPtr(const IntRef; var MethPtr; MethNo: Integer); 
type 
    TVtable = array[0..999] of Pointer; 
    PVtable = ^TVtable; 
    PPVtable = ^PVtable; 
begin 
    // QI=0, AddRef=1, Release=2, etc 
    TMethod(MethPtr).Code := PPVtable(IntRef)^^[MethNo]; 
    TMethod(MethPtr).Data := Pointer(IntRef); 
end; 

आप MethNo के लिए प्रतीकात्मक नाम चाहें, तो आप उन्हें ऑफसेट स्थिरांक के रूप में अपने आप को घोषित करने के लिए बेहतर हैं

+0

नहीं, डेल्फी में एक इंटरफेस चर एक वी-टेबल के लिए एक सूचक है। –

+0

नहीं, दिमित्री, सर्ग सही है। एक इंटरफेस वैरिएबल सिर्फ एक vtable के लिए एक सूचक नहीं हो सकता है। कक्षा के सभी उदाहरण गैर-इंटरफेस कक्षाओं की तरह, एक एकल vtable साझा करते हैं। सी ++ पर विचार करें, जिसमें इंटरफेस और सामान्य कक्षाओं के बीच कोई अंतर नहीं है। एक ऑब्जेक्ट पॉइंटर केवल एक vtable सूचक नहीं है, इसलिए न तो एक इंटरफ़ेस सूचक है। –

+0

@ रोब केनेडी: धन्यवाद, प्रश्न ने मुझे डेल्फी इंटरफेस के बारे में ब्लॉग पोस्ट लिखने के लिए मजबूर किया: http://sergworks.wordpress.com/2010/07/06/delphi-interfaces-on-binary-level/ – kludg

1

दो अतिरिक्त निर्देश असेंबली कोड को गतिशील और वर्चुअल विधियों तक पहुंचने की अनुमति देते हैं: VMTOFFSET और DMTINDEX।

वीएमटीओएफएफएसटी आभासी विधि तालिका (वीएमटी) की शुरुआत से वर्चुअल विधि तर्क की तालिका प्रविष्टि वर्चुअल विधि सूचक तालिका प्रविष्टि के बाइट्स में ऑफ़सेट पुनर्प्राप्त करता है। इस निर्देश को पैरामीटर के रूप में विधि नाम के साथ पूरी तरह से निर्दिष्ट वर्ग नाम की आवश्यकता है (उदाहरण के लिए, TExample.VirtualMethod), या एक इंटरफ़ेस नाम और एक इंटरफ़ेस विधि नाम।

DMTINDEX पास गतिशील विधि की गतिशील विधि तालिका अनुक्रमणिका पुनर्प्राप्त करता है।इस निर्देश को पैरामीटर के रूप में एक विधि नाम के साथ पूरी तरह निर्दिष्ट क्लास नाम की आवश्यकता है, उदाहरण के लिए, TExample.DynamicMethod। गतिशील विधि का आह्वान करने के लिए, सिस्टम पर कॉल करें। @ (आईडी) एसआई रजिस्टर के साथ @ CallDynaInst जिसमें DMTINDEX से प्राप्त मूल्य है।

docwiki.embarcadero.com

यहाँ कोड की जरूरत विधि सूचक

function GetMethodPointer(const IntRef: IInterface): Pointer; assembler; 
asm 
    mov eax, [IntRef] 
    add eax, vmtoffset ISomeInterface.MemberMethod 
    mov eax, [eax] 
end;