請求執行時間段通常被簡稱為"appy time"。是指當系統VM穩定到充許VxDs和ring-3層級的應用軟體(特別是16-bit的應用軟體)互動時的時間段。例如,在一個特定時間段,VxDs能載入並調用在16-bit Dlls中的函數。這個appy time在Windows 3.x中是無效的。在Windows3.x,一個VxD能包含在16-bit DLLs中的任意函數的地址,並類比一個遠調用到這個地址。然而,因為造成了VMM重入,這個操作將中斷所有正在ring-3中執行的任務。所以能被VxDs能調用的APIs被要求是中斷安全的,象PostMessage。在Windows 95,一個VxD在appy time的協助下能調用任意一個在16-bit DLLs中的函數。
假如你的VxDs被通知正處在appy time,它就能載入16-bit DLLs並調用其中的函數。VxDs怎麼知道appy time到來了呢?這就要使用Shell VxD請求一個appy time。當系統VM在穩定點,Shell VxD將調用某VxD的一個回呼函數,此函數是在VxD請求appy time時指定的。Shell VxD發生一次appy time事件僅僅調用一次你的回呼函數。這就象找工作。你到職業介紹所,登記你的名字和電話號碼。當你回到家,如有一個工作適合你,職業介紹所將電話通知你這個好訊息。當你收到了這個訊息,他們就不再通知你了。
在一個appy time起作用前要花上一些時間進行相關處理。appy time事件以下環境中將不起作用:
1、系統啟動或關機時。
2、當系統VM在臨界段或等待一個訊號量時。
管理一個appy time事件
你可以通過調用_SHELL_CallAtAppyTime來註冊一個appy time事件,它的定義如下:
VxDCall _SHELL_CallAtAppyTime, <<OFFSET32 pfnCallback>, dwRefData, dwFlags, dwTimeout>
pfnCallBack -- 當appy time事件發生時你要Shell VxD調用的回呼函數的平板地址。這個函數接收兩個參數,dwRefData和dwFlags,與你傳送給_SHELL_CallAtAppyTime的兩個一樣。記住,Shell VxD採用C調用順序調用你的回呼函數。總而言之,你要象這樣定義你的回呼函數:
BeginProc OnAppyTime, CCALL, PUBLIC
ArgVar dwRefData,DWORD ; declare argument name and type
ArgVar dwFlags, DWORD
EnterProc
你的代碼...
LeaveProc
Return
EndProc OnAppyTime
dwRefData -- 你要Shell VxD傳送給你的回呼函數的參考資料。可以是你想要的任何東西。
dwFlags -- 事件標誌。
如下值之一:
CAAFL_RING0 ring-0事件
CAAFL_TIMEOUT 由dwTimeout指定的時間到期事件。
假如你只想在一定的時間內等待appy time事件,使用CAAFL_TIMEOUT標誌。如你想一直等待appy time事件,使用NULL。CAAFL_RING0作用不明。
dwTimeout -- 在appy time事件發生前,VxD能等待時間段長度。時間段的單位不明。
這個服務是非同步,意味著你為appy time事件註冊回呼函數之後立即返回。
如果這個服務調用是成功的,在eax中返回appy time事件控制代碼。假如調用失敗,在eax返回0。
你可以調用_SHELL_CancelAppyTimeEvent來撤消appy time事件註冊,它僅有一個參數,就是由_SHELL_CallAtAppyTime返回的appy time事件控制代碼。
你應當在appy time事件到來時檢查系統。例如,當你在系統關閉時註冊appy time會發生什嗎?你的VxD的回呼函數將不會得到調用!當appy time事件到來時,你應當調用_SHELL_QueryAppyTimeAvailable來查詢系統狀態。這個服務沒有參數。如果appy time無效,在eax中返回0,例如:當系統關閉時或Message Service程式產生一個一般保護性錯誤時。
這個服務不會告訴你現在是不是appy time:它僅僅告訴你可能有一個appy time事件到來。簡而言之,如果你想安全運行,首先調用_SHELL_QueryAppyTimeAvailable並檢查eax中的值是否非零值,然後才可繼續調用_SHELL_CallAtAppyTime。
當appy time到達時,你可以使用幾個Shell服務調用:
_SHELL_CallDll
_SHELL_FreeLibrary
_SHELL_GetProcAddress
_SHELL_LoadLibrary
_SHELL_LocalAllocEx
_SHELL_LocalFree
使用提供的這6個服務,VxDs可以調用在16-bit DLLs/EXE中的16-bit函數,象WinHelp。然而,我們馬上要進步到32-bit時代(未來是64-bit) ,所以我不會仔細研究它們。如你對此感興趣,你可以在Windows 95/98DDK文檔中瞭解它們。
另外一些只請求執行時間段服務我想更有用處:_SHELL_ShellExecute和 _SHELL_BroadcastSystemMessage。使用_SHELL_BroadcastSystemMessage,你能在一次調用中發送訊息到頂端的視窗和所有的VxDs。如果appy time有效,你可以發送訊息到視窗和VxDs。如果appy time無效,你只能發送訊息到VxDs。
_SHELL_ShellExecute是在ring-3中的函數ShellExecute在ring-0中的對應函數。實際上,它調用ring-3中的ShellExecute完成這個工作。使用外殼服務,你可以運行/開啟/列印任意檔案。
_SHELL_ShellExecute的定義如下所示:
VxDCall _SHELL_ShellExecute,<OFFSET32 ShexPacket>
它僅有一個參數,SHEXPACKET結構的平板地址。它從ShellExecute函數中返回一個值到eax中。讓我們研究一下SHEXPACKET結構:
shex_dwTotalSize SHEXPACKET結構的位元組數加上可選的參數rgchBaggage的大小,它直接跟隨在這個結構之後。我等一下描述rgchBaggage。
shex_dwTotalSize SHEXPACKET結構的位元組數加上可選的參數rgchBaggage的大小,它直接跟隨在這個結構之後。我等一下描述rgchBaggage。
shex_dwSize SHEXPACKET結構的位元組數,不包括rgchBaggage。結合上面的shex_dwTotalSize值,外殼VxD能計算任意長度的rgchBaggage的大小。
shex_ibOp 你要完成的操作。假如你指定0,意味著你想要開啟一個檔案。如果是一個可執行檔,就運行它。如果你想要完成其他的操作,你必須在rgchBaggage中指定操作的名字,在這個域中,必須包括從這個SHEXPACKET結構開始到一個ASCII字串的距離,此距離大小以位元組計數,字串指定你要完成的操作的名稱。SHEXPACKET結構的大小是32位元組。如果操作字串緊跟在SHEXPACKET結構後,shex_ibOp中的值必須是32。要知道你可以完成的操作,請查看ShellExecute服務。有三個操作被定義,"open"、"print"和"explore"。
shex_ibFile 從此結構開始到一個ASCII字串的距離,這個字串是你想要傳遞給ShellExecute的檔案名稱,就象Shex_ibOp成員。
shex_ibParams 你想傳遞到由shex_ibFile指定的檔案的選擇性參數。假如此檔案是一個文檔檔案,你不想傳遞任何參數給它,就用0。假如你想傳遞參數給那個檔案,在把從此結構開始到此成員指定的字串的距離放在這個成員中。簡而言之,就象shex_ibOp和shex_ibFile成員。
shex_ibDir 工作目錄。假如你想使用Windows目錄就指定0,否則指定其為在此結構後的首選目錄名字串,並把從此結構開始到目錄名字串的距離值放到這個成員中。
shex_dwReserved 如其名字所指,它是保留的。不要理它。
shex_nCmdShow 應用程式視窗怎樣被顯示。這是一個你正常傳遞給ShowWindow的值,比如,SW_XXXX值。可在windows.inc中查看這些值。
所有成員的大小都是雙字的。在這裡我介紹剛才我承諾的rgchBaggage成員。僅有一點不同,因為其大小是可變的,所以它作為SHEXPACKET結構的一員卻不能包括在此結構的定義中。查看shell.inc,你看到rgchBaggage並不在SHEXPACKET結構的定義中,儘管在Windows 9x DDK文檔中,聲明其是SHEXPACKET結構的一員。
rgchBaggage是什嗎?簡單說來其是跟在SHEXPACKET結構後的一個字串數組。在這個數組中,你可以把你要對檔案完成的操作名稱、檔案的名字、你要傳遞給檔案的參數和工作目錄放在其中。首先得到從SHEXPACKET結構到這些字串的第一個字元之間的距離(即此結構的一些成員值),再把這些值加上SHEXPACKET結構的平板編移量,Shell VxD就能得到這些字串在rgchBaggage數組中的位移量。例如,假如SHEXPACKET結構從60000h開始,字串緊跟其後,結構與字串之間的距離是結構本身的大小,32位元組(20h)。所以Shell VxD知道字串定位在60020h。