----這種辦法是利用VisualBasic提供的創建ActiveX部件的功能設計一個專門完成“大任務”的ActiveX部件。這裡對ActiveX部件作如下簡單介紹,以期適合不同的讀者。VisualBasic所能設計的部件共有兩種:一種是可視的部件;另一種是不可視的部件。ActiveX控件和窗體一起構成了應用程序與用戶交互的界面,ActiveX文檔使用在Internet應用程序中。由於我們的問題不涉及到可視的部件,所以這裡不再贅述。
----不可視的部件又稱為代碼部件,包括ActiveDLL部件和ActiveXEXE部件兩種。ActiveX部件的另一個名稱是ActiveX服務器,之所以被稱作服務器是由於ActiveX部件與使用它們的應用程序之間的關系可以被類比為服務器程序與客戶端程序之間的關系:ActiveX部件封裝了特定的功能或業務規則,應用程序不需要知道ActiveX部件是如何實現這些功能或業務規則的,只需要通過ActiveX部件提供的編程接口(API)傳遞應用程序的要求(通過屬性或方法的參數),然後從部件的事件獲得執行結果。根據ActiveX部件(ActiveX服務器)的執行方式可以把ActiveX部件分為進程內部件和進程外部件,所謂進程內部件即部件和使用它們的應用程序執行時共享同一個進程;而進程外部件卻執行在自己的進程中,也可以這樣認為:進程外部件的執行不影響使用它們的應用程序!顯然,這個特性正是本文開始面對的那個問題所需要的。在部件中只有ActiveXEXE部件是進程外部件,因此利用這個特性我們可以創建一個ActiveXEXE部件來完成“大任務”,而應用程序窗體只顯示一些任務的提示信息,直到ActiveXEXE部件的類的事件提示任務結束為止。這樣應用程序就避免了那種呆板的“白布”窗體的出現,而能夠響應任何來自用戶的操作或者當從那些遮蓋住它的程序切換回來時自行刷新。給用戶的感覺是程序是在“異步”執行。
----下面我們通過例子來看如何實現這一想法:這個例子中,我們假設應用程序窗體是一個一直顯示當前時間的數字時鐘,當你使其執行“大任務”直到任務的完成,這期間你會發現數字時鐘窗體從來就沒有被“掛起”過,仍然能夠響應你的拖動操作和不停地顯示時間。以下是實現這一程序和ActiveXEXE部件的步驟及源代碼:
----步驟二:為工程添加一個Timer控件的容器窗體(添加窗體通過菜單工程>添加窗體完成)。窗體名稱改為frmClock;在窗體上放置一個Timer控件(從工具箱中選擇Timer控件),名稱改為timClock。
----說明:添加該窗體的用意是提供一個執行任務的定時器(Timer控件)
----步驟三:設計實現“大任務”的類BigJob(注:代碼部件是通過各種類實現應用程序交給它的任務的,關於類的創建請參考《手冊》或MSDN文檔),默認情況下當你新建ActiveXEXE部件時VisualBasic為你添加了一個名為Class1的類(要增加類通過菜單工程>添加類模塊完成),從工程資源管理器中選中Class1,然後在屬性窗口中設置如下屬性:
----(名稱):BigJob
----Instancing:5-MultiUse
----編寫API:為類BigJob添加方法和事件(通過菜單工具>添加過程完成)部分代碼及程序說明如下:
PrivatefrmTimeClockAsfrmClock
'聲明定時器容器窗體
PrivateWithEventsoTimerAsTimer
'聲明定時器(包括其事件)
PublicEventJobStart()
'聲明任務開始事件
PublicEventJobEnd()
'聲明任務結束事件
PrivateSubClass_Initialize()
'----類初始化事件----
'在這裡創建定時器窗體frmTimeClock
'並引用定時器oTimer
SetfrmTimeClock=NewfrmClock
LoadfrmTimeClock
SetoTimer=frmTimeClock.timClock
oTimer.Enabled=False
EndSub
PrivateSubClass_Terminate()
'類終止事件,
釋放定時器並卸載定時器窗體
SetoTimer=Nothing
UnloadfrmTimeClock
EndSub
PublicSubStartJob()
'方法-通知執行“大任務”
oTimer.Interval=100
'經過0.1秒時間開始執行任務
oTimer.Enabled=True
EndSub
PrivateSubdoBigJob()
'模擬的“大任務”
是這個空耗時間的循環
'顯然,這段代碼在標准EXE程序中
一定會造成“掛起”狀態!
DimlngTempAsLong
DimlngSumAsLong
ForlngTemp=1To10000000
lngSum=lngSum+1
Next
EndSub
PrivateSuboTimer_Timer()
'定時器周期到時開始執行任務
oTimer.Enabled=False
RaiseEventJobStart'觸發“開始執行”事件
doBigJob'執行“大任務”
RaiseEventJobEnd'觸發“任務結束”事件
EndSub
----現在保存工程:選擇菜單文件>保存工程,根據提示窗口選擇合適的文件夾保存所有工程資源(工程文件,窗體文件,類文件)。
----步驟二:最小化VisualBasic,然後啟動另一個VisualBasic的實例,新建一個標准EXE工程。選擇菜單工程>引用,在可引用的部件中我們可以找到BigJobServer部件,選中該部件,按“確定”按紐返回,這樣就建立了應用程序和部件服務器間的聯系。現在可以在這個工程中創建BigJob類並使用其方法和事件了。
----步驟三:在默認的窗體Form1上放置如下控件並設置其屬性(方法同前):
-width="20">類型->-width="20">名稱->-width="40">標題(Caption屬性)->-width="20">Label->-width="20">lblTime->-width="40">lblTime->-width="20">Label->-width="20">lblMessage->-width="40">lblMessage->-width="20">Timer->-width="20">timClock->-width="40">(無)->-width="20">Command->-width="20">cmdStart->-width="40">執行任務->
----步驟四:為該工程編寫簡單的代碼:
OptionExplicit
DimWithEventsmyJobAsBigJob
'聲明BigJob對像(包括事件)
PrivateSubForm_Load()
SetmyJob=NewBigJob'創建BigJob的實例
EndSub
PrivateSubForm_Unload(CancelAsInteger)
SetmyJob=Nothing'釋放對像
EndSub
PrivateSubcmdStart_Click()
myJob.StartJob
'通知對像執行任務
EndSub
PrivateSubmyJob_JobStart()
'在對像的“開始”
事件中給用戶一些提示
lblMessage.Caption=“正在執行任務..."
EndSub
PrivateSubmyJob_JobEnd()
'在對像的“結束”
事件中給用戶一些提示
lblMessage.Caption=“任務完成!"
EndSub
PrivateSubtimClock_Timer()
'“數字時鐘”在不間斷地
顯示當前時間
lblTime.Caption=Format(Now,“HH:NN:SS")
EndSub
----步驟五:保存並運行這個測試工程,會看到如下結果:當你按下“執行任務”按紐後從提示可以知道那個可怕的“大任務”已經開始執行,直到程序提示任務結束,這期間無論是拖動窗體還是時間的顯示均不會受到影響。由此可見程序被“掛起”的尴尬局面得到了解決。