在軟體開發過程中,有一些看似很簡單的問題,卻很容易被一般的開發人員所忽略,這些「Bugs」的存在,影響我們軟體走向商品化。以下列出的是筆者在使用VisualBasic開發軟體時,碰到了幾個這類問題,這裡給出其解決方法,供大家探討交流。
一防止應用程式載入兩份
當我們的應用程式在Windows下運行後,在操作過程中,有時會把它最小化隱藏起來,或者切換到程序管理器下進行其它操作,而後又想進入原來的應用程序,這時如果忘記了剛才啟動的應用程序,又去重新啟動該應用程序,在內存中就同時加載了兩份同樣的應用程序,這樣不僅佔用了內存空間,而且容易引起誤操作,造成數據的損失。為了避免這種情況發生,就需要程式能夠給出提示「已經載入過」或直接進入第一次被載入的應用程式。對於這個問題,看起來比較難辦,其實我們只要對Windows管理應用程式的機理有所了解,就很容易解決。
我們知道,對於每一個運行著的應用程序,Windows都分配給一個唯一的「句柄(Handle)」和一個模組代碼(Module)。當同時運行兩份相同的程式時,兩份程式的模組程式碼都相同,因此,只要找到記憶體中兩個相同的模組程式碼,我們就知道有兩份程式在運行,從而可以控制它。 Windows提供的兩個介面函數GetModuleHandle和GetModuleUsage可以完成此任務。具體方法如下,首先在一個新的模組檔案(*.Bas)中宣告API函數。
DeclareFunctionGetModuleHandleLibKernel(ByVallpPRogName$)
DeclareFunctionGetModuleUsageLibKernel(ByValhModule)
同時建立一個子過程,名字為main,子過程中的程式碼如下:
SubMain()
OnErrorGoToerrMain'錯誤處理
DimhModule'模組句柄
DimAppCount'應用程式的個數
appPath$=app.Path /'應用程式的啟動路徑
hModule=GetModuleHandle(appPath$ app.EXEName .exe)'取得該程式的句柄。
AppCount=GetModuleUsage(hModule)'取得模組程式碼,即執行的應用程式數目。
lfAppCount>1Then'同一應用程式數大於1
MsgBox程式已經載入,64
End'結束目前啟動的應用程式
Elsc
mainForm.Show'mainForm是程式的主窗體
Endlf
ExitSub
errMain:
lfErr<>0Then
MsgBox啟動程式時發生錯誤,64
ExitSub
Endlf
EndSub
流程完成後,在VB3.0主選單[options]下,選擇[Project]選單項,設定[StartupFrom]項為Submain,即程式執行時,最先從Submain子程式開始。這樣保證上面的程式碼一定會執行。 Submain是VB3.0約定的子過程名,不能用其它的名字來代替。
重新產生EXE文件,在程式管理員下,啟動該應用程序,然後把產生的窗體最小化,接著從程式管理員下再運行它,用戶將看到一個訊息框,告訴用戶,應用程式已被載過了,第二份程式終止執行。上面的程序僅用來防止載入二份程序,但還沒有做到當不能啟動第二份時,自動進入到第一份程序。要做到這一點,所涉及的程序較複雜,這裡就不詳細介紹了。
二判斷Windows的安裝路徑
在我們開發的軟體中,有時會直接呼叫Windows提供的小型應用程序,如計算器、計事本等;或需要把一些特殊的檔案放到Windows或SYSTEM的路徑下。通常,Windows都會安裝在C:\WINDOWS目錄下,但使用者可以任意修改Windows的主目錄名,因此,在我們的軟體中,就需要判斷Windows的安裝路徑。對於這個問題,Windows提供了兩個API函數:GetWindowsDirectory和GetSystemDirectory,可以傳回Windows目錄和SYSTEM目錄的名稱。
為此,編制一個通用函數GetWinDir,它會傳回Windows的安裝目錄名稱。類似,可以寫出GetSysDir,略。
在*.BAS模組檔案中聲明API函數
DeclareFunctionGetWindowsDirectoryLibKernel(ByValipBufferAsString,ByValnSizeAsInteger)asIntegerFunctionGetWinDir()AsStringDimWindir$Windir$=Space$(144)'144是WINDOWS目錄名稱理論上的最大長度。
lfGetWindowsDirectory(Windir$,144)=0Then
MsgBox不能確定WINDOWS的安裝路徑,16
GetWinDir=
Else
Windir$=ALLTrim$(Windir$)
ifRight$(Windir$,1)<>“/”thenWindir$=Windir$ “/”
'加上反斜線
GetWinDir=Windir$
Endlf
EndFunction
其中ALLTRIM是用來去掉字串中空字元的函數
FunctionALLTrim(FatStr$)AsString
'thisFunctiondeleteSpacecharinstringofFatStr$
DimSlimStr$,I
SlimStr$=FatStr$
I=lnStr(SlimStr$,Chr$(0))'空格的位置
IfIThenSlimStr$=Left$(SlimStr$,I-1)
SlimStr$=Ltrim$(Rtrim$)(SlimStr$))
AIITrim$=SlimStr$
EndFunction
三在關掉窗體前提示保存數據
一般說來,通常用5種方式可以關閉一個應用程式:
1.使用者選擇了目前窗體ControlBox中的[關閉]指令
2.激發程式中的結束指令碼(如End,Unload)
3.退出Windows
4.在Windows的任務清單中關閉應用程式。
5.多重文件操作時,關閉主MDI窗體,造成子MDI窗體關閉。
在關閉一個應用程式之前,我們要給使用者一個機會,提示“是否儲存資料”,或取消“關閉”的操作。在VB中,窗體的關閉引發的是Form_Unload事件,我們可以對該事件進行編程,來控制「關閉」操作。假設現已有一個過程FileSave用來保存文件,可以這樣來寫程式。
SubForm_Unload(CancelAslnteger)
selectcastMsagbox(“是否儲存資料?”,3 32)
'Yes,No,Cnacel三種選擇
case6'YES
FileSave'儲存數據
case2'cancel
Cancel=TRUE'取消關閉操作
caseelse'NO'不儲存,執行關閉操作
Endselect
EndSub
上面程式碼中的Cancel變量,是Form_unload事件本身的固有傳出變量,它給Windows控制過程傳遞訊息,從而控製程式的走向。
上面三個例子,只是軟體完善過程中的一些小問題,要讓軟體穩定可靠,需要做大量細緻認真的工作。有些問題,我們可以透過發掘VB本身的潛力,深入掌握一些流程的操作技巧來解決;而有些較複雜的問題,涉及到Windows底層方面的操作,採用Windows的API函數,可以輕鬆實現。當然這需要對Windows的函數和機制有一定的了解。隨著Windows程式設計等級的提高,我們會逐漸學會並喜歡利用API函數來輔助完成程式編碼。 ->