Delphi的對象機制淺探(50頁)_第1頁
Delphi的對象機制淺探(50頁)_第2頁
Delphi的對象機制淺探(50頁)_第3頁
Delphi的對象機制淺探(50頁)_第4頁
Delphi的對象機制淺探(50頁)_第5頁
已閱讀5頁,還剩53頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、delphi的對象機制淺探2004-1-3前幾天開始閱讀vcl源代碼,可是幾個基類的繼承代碼把我看得頭大。在大 富翁請教了兒位仁兄后,我還是對delphi對彖的創(chuàng)建和方法調(diào)用原理不太清 楚。最后只好臨時啃了一下匯編,把delphi對彖操作的幾個關鍵的方法勘察 了一遍。你可以通過以下鏈接知道我為什么要做這件事: 這是我花費一個晚上的測試結果,更多的細節(jié)只能以后在學習中再去了解。 主要測試項冃為:o測試目標:查看tobject.create的編譯器實現(xiàn)o測試口標:查看constructor函數(shù)屮inherited的編譯器實現(xiàn)o測試目標:以object reference和class referen

2、ce調(diào)用構造函數(shù)的編譯器實 現(xiàn)0測試fi標:考查object和class在調(diào)用class method時的編譯器實現(xiàn)o測試目標:考查shortstring返回值類型的函數(shù)沒冇賦值吋編譯器的實現(xiàn) 我把測試的細節(jié)記錄在后文,一是自己留作參考,二是給對此有興趣的朋友參 考。其實更重要的是,大家可以幫忙檢查我的分析有沒有錯誤。我一直是用 delphi的組件拖放編程,真正的功底只是這幾天閱讀object pascal reference 和vcl得來的,匯編更是臨時抱佛腳,所以錯誤難免。我清楚口己的水平, 所以寫下結論后非常擔心。盡管如此,我的目的是為了學習,希槊你發(fā)現(xiàn)錯誤 后幫我指出來。主要的結論是:

3、(*) tobject.create確實是個空函數(shù),borland并沒有隱藏tobject.create的代 碼。tobject.create的匯編代碼是曲constructor directive指示編譯器形成的, 編譯器對每個class都一視同仁。(*) dl和eax是constructor create實現(xiàn)的關鍵寄存器。borland將對象的創(chuàng) 建過程設計得精妙而清晰(個人感覺,因為我不知道其他的語言比如c+是如 何實現(xiàn)的)。(*) 一個對象的正常的創(chuàng)建(obj := tmyclass.create)il程是這樣的:1. 編譯器保證第一個constructor調(diào)用之前dl = 1編譯器保

4、證inherited create調(diào)用z前dl = 02. dl = 1 時 編譯器保證 create 時 eax = pointer to class vmtdl = 0 時 編譯器保證 create 時 eax = pointer to current object3. 編譯器保證任何層次的constructor調(diào)用后 eax = pointer to current object4. dl = 1 時編譯器保證 create 調(diào)用 system._classcreate,并與 constructor 相同的方式使用eaxdl = 1時 編譯器保證create調(diào)用system._after

5、construction,并且調(diào)用 前后 eax = pointer to current objectdl = 0吋 編譯器保證create不會調(diào)用system._classcreatedl = 0 時編譯器保證 create 不會調(diào)用 system._afterconstruction5. system._classcreate屮設置結構化異常處理,在create即將結束時關閉 結構化異常處理。如果出錯則會釋放由編譯器分配的內(nèi)存恢復堆棧至創(chuàng)建對象之詢 調(diào)用 tsomeclass.destroyo(*) object reference方式的constructor調(diào)用,編譯器嘗試實現(xiàn)為inh

6、erited調(diào) 用,結果當然是錯誤。(*) class method的調(diào)用隱含參數(shù)eax為指向vmt的指針,不管是用class 還是object方式調(diào)用,編譯器都會正確地把指向class vmt的指針傳遞給 eaxo要讀懂卜文的測試過程,可能需要相關基礎,推薦閱讀object pascal reference以下章節(jié):parameter passingfunction resultscalling conventions (register 缺省調(diào)用約定.constructor 和 destructor 函數(shù)必須 采用register約定)inline assambly codedelphi的

7、原子世界非常值得一讀。以下是測試內(nèi)容:o測試目標:查看tobject.create的編譯器實現(xiàn)0測試代碼及反匯編代碼: procedure test; register;varobj: tobject;beginpush ebpmov ebp, esppush ecxobj := tobject.create;mov dl, $01次新建對象的調(diào)用mov eax, $0040 loao eax,call tobject.createmov ebp-$04, eax;前2句用于設置堆棧指針;保存ecx (無用的語句);設置 dl = 1,通知 tobject.create 這是一;把指向tobj

8、ect class vmt的指針存入;作為tobject.create隱含的self參數(shù);調(diào)用 tobject.create 函數(shù);tobject.create返回新建對象的指針至objend;pop ecxpop ebp;恢復堆棧并返冋reto tobject.create的反匯編代碼:vmt(dl= 1)0)test dl, dljz +$08add esp, -$10_classcreate之前都會進行處理call classcreate1:test dl, dljz +$0f;函數(shù)進入時 eax = pointer to eax = pointer to instance (dl =;

9、函數(shù)返回時 eax = pointer to instance;檢查dl是否二0;dl = 0則跳至1;增加16字節(jié)的堆棧,每次調(diào)用;用于system._classcreate設置結構化界常;調(diào)用 system._classcreate;檢查dl是否=0call afterconstructiondl <> 0貝lj調(diào)用;dl = 0則跳到end結束過程system._afterconstruction;(注意不是 tobject.afterconstruction)pop dword ptr fs:$00000000 ; fs:0指向結構化異常處理的函數(shù),此即 取消最后一次的tr

10、y.except設置;這個 try.except 在 system._classcreate 中創(chuàng)建;用于在出錯時口動恢復堆棧/釋放內(nèi)存分配/ 并調(diào)用 tobject.freeadd esp, $0c;恢復堆棧,注意貝恢復了 12字節(jié)的堆棧,還有4字節(jié)由上句pop 了ret 注意:以上匯編代碼中重復出現(xiàn)了 test dl,dl,說明borland并沒有特別對待 tobject.create, tobject.create 確實是個空函數(shù)。tobject.create 的匯編代碼是 由constructor directive指示編譯器形成的,編譯器對毎個class都一視同仁。 注意:這段tob

11、ject.create代碼是在pc機上編譯的結呆,嚴格地說應該是 在 win32操作系統(tǒng)上的實現(xiàn)zo查看system._classcreate就知道borland 還冇其他的異常處理實現(xiàn)機制,產(chǎn)生的tobject.create代碼也不相同。o system._aftercontruction 函數(shù)的代碼:function _afterconstruction(instance: tobject): tobject;begininstance. afterconstruction;result := instance;end;0 system._classcreate 函數(shù)的代碼:functio

12、n _classcreate(aclass: tclass; alloc: boolean): tobject;asm->eax =pointer to vmteax =pointer to instance pushedx;保存寄存器pushecxpushebxtest dl,dl;如果dl = 0則不調(diào)用tobject.newinstancejl noalloccall dword ptr eax + vmtoffset tobject.newinstance ;調(diào) 用 tobject.newinstance noalloc:;設置pc架構的結構化異$ifndef pc_mapped

13、_exceptions 常處理xoredx,edxleaecxjesp+16movebx,fs:edxmov| ecx | .texcframe.next,ebxmovecx.texcframe.hebp,ebpmovecx .texcframe.desc,offset descmovecx .texcframe.constructedobject,eax trick: remembercopy to instance movfs:edxhecx$endifpopebx;恢復寄存器popecxpopedxret$ifndef pc_mapped.exceptions;設置非 pc 架構的結構化

14、開常處理desc:jmp_handleanyexceptiondestroy the objectmoveax,esp+8+9*4moveax,| eax .texcframe.constructedobjecttesteax,eaxjeskipmovecx,eaxmovdl,$81pusheaxcalldword ptr ecx + vmtoffset tobject.destroypopeaxcall_classdestroyskip: reraise the exceptioncall_raiseagain$endifend;o測試目標:查看constructor函數(shù)中inherited

15、的編譯器實現(xiàn)o測試代碼及反匯編代碼:typetmyclass = class(tobject)constructor create;end;constructor tmyclass.create; begininherited; /考查此句的實現(xiàn)beep;end;procedure test; register;varobj: tmyclass;beginobj := tmyclass.create;mov dl, $01mov eax, $004600ec pointercall tmyclass.createmov ebp-$04, eaxend;class reference 吋編譯器設

16、置 dl = 1;設置eax為指向tmyclass的vmt;調(diào)用 tmyclass.create;保存新建對象的指針constructor tmyclass.create 的反匯編代碼:vmt(dl= 1)=0)beginpush ebpmov ebp, espadd esp, -$08test dl, dl1處執(zhí)行jz +$08add esp, -$10call classcreateeax =新建對彖的指針1:mov ebp-$05, dl為后面的 inherited tobject.create;函數(shù)進入時 eax = pointer to eax = pointer to instan

17、ce (dl 函數(shù)返回時 eax = pointer to instance;這3句用于保存堆棧指針和創(chuàng)建堆棧如果dl = 0則跳到classcreate之后;為_classcreate調(diào)用準備堆棧;調(diào)用system._classcreate,執(zhí)行完成后;將dl值保存到堆棧中的1字節(jié)中,因;可能會改變edx的值mov ebp-$04, eax;保存 eax 到堆棧,eax = pointer toinherited;xor edx, edxtobject.create不用 再調(diào)用器實現(xiàn))mov eax, ebp-$04eax值執(zhí)行此句)call tobject.createbeep;call

18、beepmov eax, ebp-$04eax值cmp byte ptr ebp-$05, $00jz +$0f2處call afterconstruction;將edx清零(dl = 0),以通知 ;_classcreate 和 afterconstructor (編譯 ;將eax的值還原為前面保存在堆棧的 ;(這句是多余的,但在其它情況下可能必須;調(diào)用 tobject.create;繼承類中inherited之后實現(xiàn)的功能;將eax的值述原為前而保存在堆棧的;(間接)檢查dl是否=0;dl = 0 則跳過 _afterconstruction 到;調(diào)用 system._afterconst

19、ructionpop dword ptr fs: $00000000??臻g;這2句恢復為_classcreate創(chuàng)建的堆instanceadd esp, $0c2:mov eax, ebp-$04; 返回 pointer to instancepop ecxpop ecxpop ebp ret 結論:真是精妙! 一個對象的正常的創(chuàng)建(obj := tmyobj.create,與后面不正 常的調(diào)用相對)過程是這樣的:1. 編譯器保證第一個constructor調(diào)用之前dl = 1編譯器保證inherited create調(diào)用z前dl = 02. dl = 1 時 編譯器保證 create 時 e

20、ax = pointer to class vmtdl = 0 時 編譯器保證 create 時 eax = pointer to current object3. 編譯器保證任何層次的constructor調(diào)用后 eax = pointer to current object4. dl = 1 時編譯器保證 create 調(diào)用 system._classcreate,并與 constructor 相同的方式使用eaxdl = 1時 編譯器保證create調(diào)用system._afterconstruction,并且調(diào)用 前后 eax = pointer to current objectdl

21、= 0吋 編譯器保證create不會調(diào)用system._classcreatedl = 0 時編譯器保證 create 不會調(diào)用 system._afterconstruction5. system._classcreate屮設置結構化異常處理,在create即將結束時關閉 結構化異常處理。如果出錯則會(1)釋放由編譯器分配的內(nèi)存恢復堆棧至創(chuàng)建對象之詢 調(diào)用 tsomeclass.destroyo看上去有點繁雜,可是如杲讀懂了上而tobject.create和tmyobject.create 則會感覺對象的創(chuàng)建非常清晰。o測試戸標:以object reference和class referen

22、ce調(diào)用構造函數(shù)的編譯器實 現(xiàn)o static constructor測試代碼及反匯編代碼(省略了 begin和end后而的堆 棧分配代碼):procedure test; register;varobj: tobject;beginobj := tobject.create;mov dl, $011;采用class reference時編譯器自動設置dl =mov eax, $0040 loaoeax,用于下一行調(diào)用;把指向tobject class vmt的指針存入call tobject.createmov ebp-$04, eaxobj := obj.create;or edx,-$0

23、1的所有bit都為1mov eax, ebp-$04;采用object reference時編譯器自動設置edx;把obj指針的所指的區(qū)域(即對象內(nèi)存空間)存入eax,用于下一行調(diào)用call tobject.create mov ebp-$04, eaxo virtual constructor測試代碼及反匯編代碼(省略了 begin和end后面的堆 棧分配代碼):procedure test; register;varcomp: tcomponent;begincomp := tcomponent.create(nil);xor ecx, ecx;設置 參數(shù)二 nilmov dl, $01;

24、設置 dl = 1mov eax, $00412eaccall tcomponent.create mov ebp-$04, eaxcomp := comp.create(nil);xor ecx, ecxor edx, -$01mov eax, ebp-$04tcomponent class 的 vmt pointermov ebx, eax值是對的)call dword ptr ebx+$2c-l,nil);mov ebp-$04, eaxend;設置 eax = class vmt pointer;調(diào)用 tcomponent.create;保存新建的對彖至comp;同上;設置edx所有位

25、為1;這句和下句設置ebx為;(如果comp已經(jīng)實例化了,則ebx的;可能是調(diào)用 tcomponent.create(comp,;保存新建的對彖至comp結論:object reference方式的constructor調(diào)用,編譯器嘗試實現(xiàn)為inherited 調(diào)用,結果當然是錯誤。o測試目標:考查object和class在調(diào)用class method時的編譯器實現(xiàn)o測試代碼及反匯編代碼(省略了 begin和end后面的堆棧分配代碼): procedure test; register;varcom: tcomponent;str: string255;begincom := tcompone

26、nt.create(nil);xor ecx, ecxmov dl, $01mov eax, | $00412eac call tcomponent-create mov ebp-$04, eaxstr := com.classname;lea edx, ebp-$00000104mov eax, |ebp-$04mov eax, eaxcall tobject.classnamestr := tcomponent.classname;lea edx, ebp-$00000104;eax = pointer to class vmt;eax = pointer to object;eax =

27、pointer to vmt型的參數(shù)傳遞的mov eax, $00412eaccall tobject.classnameend;edx = address of str;shortstring類型的返回值是以var類;eax = pointer to class vmt結論:class method的調(diào)用隱含參數(shù)eax為指向vmt的指針,不管是用 class還是object方式調(diào)用,編譯器都會正確地把指向class vmt的指針傳 遞給eax<>o測試目標:考查shortstring返冋值類型的函數(shù)沒有賦值時編譯器的實現(xiàn)procedure test; register;begin

28、tcomponent.classname;lea edx, ebp-$00000100;編譯器會在堆棧中創(chuàng)建256 byte的臨時空間,以保證edx不會為非法值mov eax, $00412eaccall tobject.classnameend;0 tobject.classname 函數(shù)代碼:class function tobject.classname: shortstring;$ifdef purepascalbeginresult := pshortstring(ppointer(integer(self) + vmtclassname)a)a; end;$elseasm->

29、eax vmtedx pointer to result string pushesipushedimovedi,edx;edx是返回值串的指針movesi,eax.vmtclassnamexorecx,ecxmovcl,esi;設置 result string 的 lengthincecxrepmovsbpopedipopesiend;$endif結論:這只是我想了解字符串返冋值的傳遞方式。(完)來自:lance2000,時間:2004-1-3 9:46:00, id: 2390276寫的非常好!來自:dedema,時間:2004-1-3 9:57:00, id: 2390302這么厲害??!

30、一個晚上就完成了!來自:積步,時間:2004-1-3 10:10:00, id: 2390324mark來自:zhumoo,時間:2004-1-3 10:26:00, id: 2390353高手就是高手,學習.來自:kk2000,時間:2004-1-3 15:05:00, id: 2390894樓主一個晩上完成,只能說佩服了!來自:renyi,時間:2004-1-3 17:54:00, id: 2391175厲害,不知delphi的對象機制和java 、c#相比,哪個個的效率更 高?來自:einsteingod,時間:2004-1-3 19:07:00, id: 2391225寫的非常好!來自

31、:xff916,時間:2004-1-3 19:49:00, id: 2391246牛呀,學習,學習,在學習來自:積步,時間:2004-1-3 19:50:00, id: 2391248小弟還有一事不知。通過asm訪問類 的私有變量.ta = classprivatefa: integer;publicprocedure seta(value: integer);end;varform 1: tform 1;implementation$r*.dfmprocedure tform 1 .button 1 click(sender: tobject);vara: ta;tmplnt: intege

32、r;begina := ta.create;tmplnt := 0;a.seta(loo);asmmov ecx, a.fa;/為什麼a.fa => 100立即數(shù)就可以顯示為100,如果不改就顯示為其它值。mov tmplnt, ecx;end;sho wmessage(inttostr(tmpint);a.free;end;來自:savetime,時間:2004-1-4 1:30:00, id: 2391511to積步:delphi對“mov ecx, a.fa”生成的代碼實際上是以record的類型生成 的,這樣ecx的值就是變量a的地址加上ta.fa的偏移值,結果是ecx變成堆棧上

33、的一個值, 所以不對。a.fa的實際地址是a指向的地址(也就是對象內(nèi)存位置,而不是a的地址) 加上fa相對于對象頭部的偏移地址。我湊出以下的代碼,可以實現(xiàn)你要的結果:a:ta;tmplnt: integer; begina := ta.create; tmplnt := 0; a.seta(loo); asmmov ebx,amov ecx, ta(ebx).fa; / 通知編譯器 ebx 指向的是 ta classmov tmplnt, ecx;end;showmessage(inttostr(tmpint);a.free;end;我沒寫過匯編代碼,所以不知道delphi會不會自動保護其他使

34、用ebx的 語句。如果你知道在混合匯編的情況下如何使用寄存器請教我一下。其實我真的不知道還有這種方法口j以獲得私有成員,有趣!來自:savetime,時間:2004-1-4 2:40:00, id: 2391532內(nèi)容更正:我發(fā)現(xiàn)自己在上文注釋中的一個錯誤,在以下匯編第三行的“ pushecx ”我把它注釋為“保存ecx(無用的語句)”,更正為:“分配局部變量obj的堆??臻g”。原來add esp, -$4花費3個字節(jié)的指令而 push ecx 只要1個字節(jié)的指令,執(zhí)行更快大家現(xiàn)在知道我不是高手了吧,我是一邊翻匯編手冊,一邊寫注釋的。我只能毫不謙虛地說:我真的是初學者。高手看這些簡單的匯編代碼

35、哪里需要花一個晚上。希望大家關注內(nèi)容,不要只是說“好”,重要的是“冇沒冇錯誤”,這樣才能捉 高。岀錯的注釋段:o測試目標:查看tobject.create的編譯器實現(xiàn)o測試代碼及反匯編代碼:procedure test; register;obj: tobject;beginpush ebpmov ebp, esppush ecx局部變量obj的堆??臻gobj := tobject.create;mov dl, $01次新建對彖的調(diào)用mov eax, $0040 loao;前2句用于設置堆棧指針;保存ecx (無用的語句)> (更正為)分配;設置 dl = 1,通知 tobject.cr

36、eate 這是一;把指向tobject class vmt的指針存入call tobject.createmov ebp-$04, eaxobj;作為tobject.create隱含的self參數(shù);調(diào)用 tobject.create 函數(shù);tobject.create返ih|新建對象的指針至end;pop ecx;恢復堆棧并返冋pop ebpret來自:savetime,時間:2004-1-4 2:40:00, id: 2391533 to積步,我測試了在混合匯編的情況下修改寄存器時的實現(xiàn),結果是:delphi會自動把嵌入?yún)R編屮修改了的寄存器備份在堆棧中,所以可以隨意使用delphi允許的寄存

37、器。來自:book523,時間:2004-1-4 10:20:00, id: 2391614結論:真是精妙! 一個對象的正常的創(chuàng)建(obj := tmyobj.create,與后面不正 常的調(diào)用相對)過程是這樣的:1. 編譯器保證第一個constructor調(diào)用之前dl = 1編譯器保證inherited create調(diào)用z前dl = 02. dl = 1 時 編譯器保證 create 時 eax = pointer to class vmtdl = 0 時 編譯器保證 create 時 eax = pointer to current object3. 編譯器保證任何層次的construct

38、or調(diào)用后 eax = pointer to current object4. dl = 1 時編譯器保證 create 調(diào)用 system._classcreate,并與 constructor 相同的方式使用eaxdl = 1時編譯器保證create調(diào)用system._afterconstruction,并且調(diào)用前 后 eax = pointer to current objectdl = 0吋 編譯器保證create不會調(diào)用system._classcreatedl = 0 時編譯器保證 create 不會調(diào)用 system._afterconstruction5. system._cl

39、asscreate屮設置結構化異常處理,在create即將結束時關閉結 構化異常處理。如果出錯則會(1)釋放由編譯器分配的內(nèi)存恢復堆棧至創(chuàng)建對象之詢 調(diào)用 tsomeclass.destroyo看上去冇點繁雜,可是如呆讀懂了上而tobject.create和tmyobject.create則會感覺對象的創(chuàng)建非常清晰。為什么要保存經(jīng)常調(diào)用dl的值?d1主要用來表示是class級別調(diào)用還是對象級別調(diào)用,class級別調(diào)用時,constructor會自動執(zhí)行system._classcreate, newlnstancejnitlnstance, afterconstruction 等過程, 然后才

40、是constructor中的代碼,而對象級別調(diào)用吋,只會執(zhí)行constructor屮的代碼。來自:savetime,時間:2004-1-4 12:18:00, id: 2391785to book523,你說的是我在測試目標:以object reference和class reference調(diào)用構造 函數(shù)的編譯器實現(xiàn)”中的結果吧。我在文章中寫的結論是:"objectreference方 式的constructor調(diào)用,編譯器嘗試實現(xiàn)為inherited調(diào)用”其實如呆你看了測試代碼的反匯編過程,就應該知道我的這個結論是錯誤的。 borland在object pascal referen

41、ce中寫的就是你說的"對象級別調(diào)用時,只 會執(zhí)行constructoi*中的代碼?!保墒鞘聦嵣喜皇沁@樣。在形式如下的代碼中acomp := acomp.createborland先將edx所有bit設置為1 ,也就是dl為1,也就是仍然嘗試沿用class級別的調(diào)用??墒悄憧磀elphi的生成的匯編代碼不知所云,所以根 木就沒有所謂的“對象級別調(diào)用”。我認為borland應該對acomp := acomp.create調(diào)用提示為語法錯誤。我實在是想不到什么時候會需要這種形 式的調(diào)用。我測試這樣的調(diào)用方式是因為我經(jīng)常在創(chuàng)建form時忘了寫t這一標識符:childform := chil

42、dform.create(nil); / 這里應該是 tchildform.create(nil) 我想知道這樣的結果是什么。來自:vc_delphi,時間:2004-1-4 18:27:00, id: 2392395 高手就是高手,學習.來自:積步,時間:2004-1-4 21:30:00, id: 2392563to savetime:多謝指教。以前也研究過惟編什麼東東的,但是現(xiàn)在沒有多少時間研究。來自:積步,時間:2004-1-4 21:35:00, id: 2392623procedure tform 1 .button 1 click(sender: tobject);a: ta;t

43、mplnt: integer;begina := ta.create;tmplnt := 0;a.seta(loo);asmmov eax, a;mov eax, (eax + 4j;這樣也行mov eax, eax| + 4都是得到當前對象的第一變量/mov eax, eax + 8訪問第二個變量,依此類推/mov eax, eax,是指向vmt的指針mov tmplnt, eax;end;showmessage(inttostr(tmpint);a.free;end;這樣也可以實現(xiàn),但是想不到savetime兄弟還冇更高的招術,厲害厲害!來自:xchen.d,時間:2004-1-4 21:

44、33:00, id: 2392650我看'中國有救了 ',真有耐力!呵呵心不靜,做不了來自:savetime,時間:2004-1-5 10:15:00, id: 2392767to積步,我乂從你這里學到一點匯編知識,知識就是這樣積累出來的呀。to everybody,其實要看懂文中的匯編并不難,我做的這件工作只是delphi的基礎而已。讀 懂和會用根木上是兩冋事。我現(xiàn)在正在分析twincontrol如何如何封裝windows的消息系統(tǒng),二天過 去,進展不大。相關的函數(shù)太多了,述冇一些匯編夾在其中。我認為消息系統(tǒng) 才是vcl的關鍵地方。整個程序的執(zhí)行過程全在里面。來自:tingl

45、iuxingyu,時間:2004-1-5 10:56:00, id: 2393353高手啊,高手,想法啊,想法,學習啊,學習我認為borland應該對acomp := acomp.create調(diào)用提示為語法錯謀。我實 在是想不到什么時候會需要這種形式的調(diào)用??纯磘application的createform過程,冇一個典型的acomp := acomp.create例子,冇些時候生成的匯編是不知所云, 那是因為我們對匯編根木就不了解,匯編的語句單個拿出來都很好懂, 但是要一段拿出來要明口要實現(xiàn)什么功能就困難了。procedure tapplication.createform(instance

46、class: tcomponentclass; varreference);instance: tcomponent;begininstance := tcomponent(instanceclass.newinstance); 調(diào)用 newlnstance 方法分 配內(nèi)存,創(chuàng)建框架等等。然后根據(jù)tcomponent類圈定框架賦給instance tcomponent(reference) := instance;/給 reference 變量賦值tryinstance.create(self);/執(zhí)行 constructor create(owner)的代碼excepttcomponent(

47、reference) := nil;raise;end;訐(fmainform = nil) and (instance is tform) thenbegintform(instance).handleneeded; 調(diào)用 handleneeded 過程,創(chuàng)建窗體。fmainform := tform(instance);/把第一個創(chuàng)建的窗體作為主窗體。end;end;to book523,我又錯了,你真的找出了這樣的代碼,厲害!我要考慮一下再回復你。來自:book523,時間:2004-1-5 12:41:00, id: 2393636我現(xiàn)在止在分析twincontrol如何如何封裝win

48、dows的消息系統(tǒng),二天過 去,進展不大。相關的函數(shù)太多了,還右一些匯編夾在其中。我認為消息系統(tǒng) 才是vcl的關鍵地方。整個程序的執(zhí)行過程全在里面。我現(xiàn)在也在做這個工作,昨天看了李維的那本新書inside vcl開始有點頭 緒了,你不要從twincontrol開始,那樣會不知所云,你可以從項口工程文件的那三 句話開始分析,估計很快就能理出個大概來。application.initialize;application.createform(tform 1, form 1);application.run;來自:book523,時間:2004-1-5 12:45:00, id: 2393645我又

49、錯了,你真的找出了這樣的代碼,厲害!我要考慮一下再回復你。正好昨天分析這個過程看到的。來自:zeroyou,時間:2004-1-5 13:41:00, id: 2393797到此一游,to book523,我找到錯誤的的原因了。我把匯編代碼jz和jl搞混了,所以上而注釋system._classcreate 有錯誤。其實dl寄存器有3種狀態(tài)(我原來以為是2種):dl = 1是在tclass.create z前被設置dl = 0是在inherited 之前被設置dl = -1是在object.create之前被設置dl = 1 system._classcreate 被調(diào)用dl = 0 syst

50、em._classcreate 不被調(diào)用dl = -1 system._classcreate被調(diào)用,但不執(zhí)彳亍newlnstance工作,只是設置異 常斷點"0測試冃標:以object reference和class reference調(diào)用構造函數(shù)的編譯器 實現(xiàn)” 的注釋也有錯誤。重讀 obj.create的匯編代碼,終于明白了應該是有 object reference consturction這一事實。只是在obj.create z前必須用newlnstance分配內(nèi)存 和設置obj vmt的指針,否則obj.create就會失敗。obj.create不會調(diào)用 newlnstan

51、ce,但會設置異常處理,保證出錯吋析構函數(shù)被調(diào)用。對于vcl的消息系統(tǒng),我原木也想從上向下讀,不過我對twincontrol沒 什么了解,只好先看它都包裝了哪些函數(shù)。我現(xiàn)在可以用你推薦的方法試試。 我猜想tapplication只是調(diào)用getmessage再dispatchmessage,所以關鍵的 是vcl如何注冊wndproc,并把注冊的這個wndproc關聯(lián)到對象上。makeobjectlnstance很冇意思,在內(nèi)存屮建立一塊一塊的objectlnsumce代 碼,objectinstance的地址又被注冊為標準的 windows procedure 我是從twincontrol.cr

52、eate入手的,第一句不太明口,fobjectlnstance := classes.makeobjectlnstance(mainwndproc); function makeobjectinstance(method: twndmethod): pointer 你能解釋一下makeobjectlnstance的mainwndproc傳遞的實際內(nèi)容是什么 (是不是傳遞mainwndproc的指針和self指針?我是不太明白為什么編譯 器知道要把self傳過去。)你已經(jīng)拿到inside vcl t,幸福啊。我們這里的書店太差了,到今天還沒通 知我到貨。來自:baifeng,時間:2004-1-

53、5 13:52:00, id: 2393836gz來自:book523,時間:2004-1-5 14:26:00, id: 2393903你能解釋一下makeobjectlnstance的mainwndproc傳遞的實際內(nèi)容是什么 (是不是傳遞mainwndproc的指針和self指針?我是不太明口為什么編譯器知道要把self傳過去。)傳遞的是mainwndproc的指針和self指針,看delphi的消息結構: tmessage = packed recordmsg: cardinal;case integer of0:(wparam: longint;lparam: longint;result: longint);1:(wparamlo: word;wparamhi: word;lparamlo: word;lparamhi: word;resultlo: word;resulthi: word);end;而windows中的消息結構:typedef struct tagmsghwnd hwnd;uint message;wparam wparam;lparam iparam;dword time;point pt; ms

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論