Olay özetle şu:
Bir 3. party DLL var. Bu DLL'e program kodunuzdaki bir function'ı register ediyorsunuz. DLL'e remote bir çağrı geldiğinde sizin function'ı call ediyor.
Register edilen function şöyle birşey:
Kod: Tümünü seç
// DLL C'de yazıldığı için stdcall şart.
function MyFunction(Handle: LongWord): LongWord; stdcall;
Function'ı şöyle yaptım:
Kod: Tümünü seç
TMyClass = class
private
function MyFunction(Handle: LongWord): LongWord; stdcall;
end;
oldu bana bir method. Sonra bu method'un pointer'ini DLL'e gönderdim. Fakat o da ne? Function-method gayet güzel çağırılıyor, ancak Handle parametresi abuk sabuk bir değerle dönüyordu. Normalde 1 değeri ile dönmesi gerekirken $1F322 gibi bir değer alıyordu. Lam dedim acaba calling convention'lardan mıdır? cdecl, safecall, pascal hatta ve hatta register'i bile denedim, yemedi.
Bu arada google harıl harıl bana çalışıyor. Ara, tara yok böyle birşey.
Debugging yolları göründü sonunda...
Koydum breakpoint'imi function'ın başına. Bir de çay koydum kendime.
Neyse lafı uzatmayayım. Program kırılınca açtım CPU view'ı. Call eden yere döndüm. Baktım DLL paşa gibi, aslanlar gibi "push" etmiş stack'e parametreyi, gönderiyor. Aferim dedim. Function'ımın başına döndüm bi baktım bu gitmiş DLL'in stack'e koyduğu değeri değil, ondan bir DWORD önceki değeri almış.
"Alla allaa niye ki?", dedim. Bu sefer Method'umu değil standart function'ımı register edip denedim. Bu alıyor stack'ten doğru değeri. Aradaki bir DWORD'lük değeri neden atlıyor acaba function'ı method yapınca? Bu işe anlam veremedim. Kesin VMT (Virtual Method Table) hesabıdır, vardır bir hikmeti dedim.
Sonra Google'da bir yere denk geldim. Link'i şu:
http://info.borland.com/techpubs/delphi ... ntrol.html
Esasen buradaki şeyler Delphi Help'te de var. Ancak gözümden kaçmış işte.
Adam diyor ki:
Yani Self gizli bir ilk parametre olarak davranıyormuş methoda girişte. Biz böyle illegal çağırtınca o da ilk parametre olan Handle'ı, Self parametresi zannedip, 2. Parametre varsaydığı Handle'a Self'den bi sonraki değeri alıyormuş.Under the cdecl, stdcall, and safecall conventions, Self behaves as if it were declared before all other parameters, but after the additional var parameter (if any) passed for a function result. It is therefore the last to be pushed, except for the additional var parameter.
Yani şöyle:
Şimdi bu stack olsun. 3 adet değer var içinde 12, 23 ve 45.00001 - 12
00002 - 23
00003 - 45
Method call yapıldığında Delphi gidip Self diye 00002 adresindeki 23 değerini alıyor. Aslında o bana gelen Handle.
Handle değerine de 00003 adresindeki 45 i koyuyor.
Self sanki method başında tanımlı bir gizli parametre olarak varsayılıyor.
Ha ben ne yaptım çözüm olarak:
Method'a parametre falan vermedim.
Handle'ı da Self'ten aldım.
Yani:
Kod: Tümünü seç
function TMyClass.MyFunction: LongWord; stdcall;
var
Handle: Longword;
begin
Handle:= Longword(Self);
end;
Ne kadar doğru bir yöntem zaman gösterecek. Bir gün böyle birşeyle karşılaşırsanız neler oluyor demeyin.. İşte olay budur. Ha, es kaza method'u dynamic veya virtual olarak tanımladıysanız, o zaman method adresini almak için farklı şeyler yapmanız gerekiyor. O zaman da bkz. Delphi Help. Inline assembler bölümü.
İyi günler dilerim.