VB 程序大揭秘
發表于:2007-07-14來源:作者:點擊數:
標簽:
1.Visual Basic程序概況 我用W32Dasm(Ver 8.93)解開一個比較復雜的 VB 程序,其中用到了許多API 函數比如GetPrivateProfileString、OSfCreateShellLink、SHBrowseForFolder 等來自很多DLL的API。解開以后卻發現程序只用到了一個DLL:ms vb vm50.dll(我用的還
1.Visual Basic程序概況
我用W32Dasm(Ver 8.93)解開一個比較復雜的
VB程序,其中用到了許多API 函數比如GetPrivateProfileString、OSfCreateShellLink、SHBrowseForFolder 等來自很多DLL的API。解開以后卻發現程序只用到了一個DLL:ms
vbvm50.dll(我用的還是VB5)!VC、Delphi等程序語言編譯出的程序可是直接引用DLL的。經過研究發現程序使用了如下幾個主要的來自MSVBVM50.dll的API:
rtcRandomize :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程序編譯時的方法,使其成為一個標準的資源性Win32程序。
附:VB程序與VC++程序啟動速度大火拼
注意:這里提到的只是“啟動”速度。實際上,VB程序啟動后的運行速度與其它程序語言編譯出來的EXE速度差不多(甚至更快),只不過是啟動速度太慢而已。
我們知道,
Windows附帶的計算器是用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程序是最簡單的了。:)
原文轉自:http://www.anti-gravitydesign.com