VB 程式大揭秘 (轉)

worldblog發表於2007-12-10
VB 程式大揭秘 (轉)[@more@]大揭秘
 

  1.程式概況 

  我用W32Dasm(Ver 8.93)解開一個比較複雜的VB程式,其中用到了許多 比如GetPrivateProfileString、OCreateLink、SHBrowseForFolder 等來自很多DLL的API。解開以後卻發現程式只用到了一個DLL:msvbvm50.dll(我用的還是VB5)!VC、等程式語言編譯出的程式可是直接引用DLL的。經過研究發現程式使用瞭如下幾個主要的來自MSVBVM50.dll的API:

rtcRanize :Randomize 函式的對應API; 
rtcMidCharVar :Mid 函式的對應API; 
rtcLeftCharVar、rtcRightCharVar :看出來了吧,這些是Left、Right函式的對應API; 
rtcUpperCaseVar :UCase 函式的對應API; 
rtcKillFiles :Kill 語句的對應API; 
rtcFileCopy :FileCopy 語句的對應API; 
rtcFileLength :EOF、FileLen函式的對應API; 
rtcGetTimer :Randomize Timer中獲取Timer的對應API; 
rtcShell :Shell函式的的對應API; 
rtcMakeDir :MkDir 語句的對應API; 
rtcRemoveDir :RmDir 語句的對應API; 
rtcDir :Dir 函式的對應API; 
rtcSpaceVar :Space 函式的對應API; 

  沒問題的人應該看出來了:VB的所有函式、語句、方法都是由MSVBVM50.dll 中的API實現的,一般是由“rtc”接上函式或語句的全名,涉及字串的API一般還得在最後加上“Var”。另外還有一些函式是這樣寫的:

__vbaUbound : UBound 的對應API; 
__vbaFileOpen :Open 語句的對應API; 
__vbaStrCmp :比較兩個字串:If String1 = String2 Then ...... 
__vbaVarOr :Or 運算子的對應API; 
__vbaRedim :Redim 語句的對應API; 
__vbaRedimPreserve :Redim 語句加上 Preserve 引數的對應API; 
__vbaGet、vbaPut :Get、Put語句的對應API…… 

  在執行時,VB程式就呼叫它們完成工作。

  2.其它DLL的呼叫

  第一部分解決了。我們知道了VB程式實際上不是一個真正的可,它只是機械性地呼叫MSVBVM50.dll中的API執行程式。那麼VB程式既然只呼叫了MSVBVM50.dll,它又是怎樣呼叫其他DLL中的API呢?

  注意這個API。它能引起我們的注意:

  DllFunctionCall:看到了嗎?它就是我們的主角。

  從字面上看就能看懂了:它用來呼叫其它DLL。這樣可以使程式使用的函式集中在MSVBVM50.dll裡(怎麼有點像封建制度,中央集權……)。

  3.重中之重:VB程式的啟動

  我們已經知道了VB程式的執行方法。那麼它是怎樣啟動的呢?

  再看看程式呼叫的API。其中有一個API雷打不動,每個VB程式都有:

  ThunRTMain 

  首先,VB程式呼叫ThunRTMain。ThunRTMain為程式初始化程式,並獲取程式ID。

  隨後它載入vb5chs.dll,為開啟新視窗準備。然後它開始用LoadString等API 獲取視窗屬性,比如字型、標題、顏色等。再呼叫IMM32.dll,開始利用它開啟新視窗。然後使用GetModuleFileName獲得VB程式名,隨後用CreateSemaphore增加訊號機。訊號機的作用是:當值大於0時,訊號機工作。再呼叫OLE32.dll,使用CreateWindowEx開啟一個叫做“DDE Server”的隱藏視窗,讓它從中作梗。退出OLE32.DLL,MSVBVM50又開始呼叫程式管理器。

  前面的工作為我們的VB程式註冊了一個類名:VBFocusRT5,下面就可以使用這個類名建立VB窗體。首先使用大量迴圈讀取半形/全形字元,然後讀取各個的屬性,再使用Local_Function把這些屬性、方法、事件等“拼”成一個完整的控制元件,最後把上面做的所有工作綜合起來,開始VB程式。

  從過程來看,使用時間最多的自然是載入控制元件了,其次是載入字符集。VB程式速度慢主要是指啟動速度慢。這是難以避免的,希望VB7推出時能改進這一點。

  不知大家看沒看出來,編譯後的VB程式只是源程式的翻版,連控制元件屬性、方法和事件名都一模一樣。VB程式的慢就是來自這裡,它們只是機械地、無休止地呼叫MSVBVM50.dll裡的API來執行程式。要想徹底擺脫這一點,只能改革VB程式編譯時的方法,使其成為一個標準的資源性程式。

  附:VB程式與VC++程式啟動速度大火拼

  注意:這裡提到的只是“啟動”速度。實際上,VB程式啟動後的執行速度與其它程式語言編譯出來的EXE速度差不多(甚至更快),只不過是啟動速度太慢而已。

  我們知道,附帶的計算器是用VC++編制的。我編了一個示例計算器程式,流程很簡單,單擊Command1時把Text1與Text2相加,再賦值到Text3。

  程式碼只有一行:

  Private Sub Command1_Click() 

  Text3 = CStr(Val(Text1) + Val(Text2)) 

  End Sub 

  把它編譯為EXE。為了表現出速度差異,我選擇了一臺比較慢的:

  Pentium 166 MMX + 80M EDO + 3.2G。

  啟動速度對比:為了結果公平,共測試五次,取平均值。

單位:秒


執行次數 VB計算器 VC++計算器 
1 2.43 0.87 
2 0.85 0.74 
3 0.92 0.92 
4 1.02 0.78 
5 0.87 0.84 
平均速度 1.22 0.83 

  你會發現,VB計算器第一次比較慢,剩下幾次就快了。這是因為ThunRTMain 把所有控制元件資訊寫入,每次開啟程式時檢測是否有可用控制元件資訊而且符合本程式(大概比爾也知道VB慢吧)。另外,我們只能算加法的計算器啟動速度就和功能眾多的Windows計算器差不多,更可以知道我們如果用VB編出一個和Windows計算器功能相同的計算器的啟動速度了。:( VB也不全是缺點,至少它的環境是其它程式語言所不具備或不擅長的。

  像VB這樣簡單易學,可以像畫圖一樣構造程式介面的程式語言可以說只有VB 一個,它為初學者指明瞭方向。VB是有它存在的理由的,至少,我SuperAPI還在用它。:) 

  後記:

  寫這篇文章的靈感來自於兩天前VB論壇裡cy72提出的問題。昨天半夜沒上網,集中精力一個VB程式,終於找出了答案。在DLL裡轉來轉去的感覺真的很難受,加之我對還不太懂。以每秒3條語句的速度進行,除錯了49218 步,共用了4個半小時。我自從接觸VB以來從沒感覺過VB程式是這樣複雜。

  尤其值得一提的是,4個半小時中4個小時是泡在近似無限的迴圈中,這種長時間重複一件枯燥而乏味的事情我可總算是見識到了,各位除錯VB程式時大可不必心煩意亂,你只要想想長時間按著F7、F5鍵,在迎面撲來的一堆堆成山的天書般的組合語言中尋找有用東西的滋味你就知道除錯VB程式是最簡單的了。:)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990827/,如需轉載,請註明出處,否則將追究法律責任。

相關文章