?? 第20章 雜項.txt
字號:
# include <dos. h>
# include <windows. h>
DWORD FAR PASCAL __loadds KeyBoardProc(int,WORD,DWORD);
static FARPROC nextKeyboardFilter=NULL;
BOOL shiftKeyDown ,ctrlIKeyDown ;
# define REPEAT-COUNT 0x000000FF / * test key repeat * /
# define KEY_WAS_UP 0x80000000 / * test WM_KEYUP * /
# define ALT KEY_DWN 0x20000000 / * test ALT key state * /
# define EAT_THE_KEY 1 /* swallow keystroke * /
# define SEND_KEY ON 0 /* act on keystroke ~ /
BOOL useAltKey=TRUE; / * use Alt key in sequence * /
BOOL useCtrlKey=TRUE; / * also use Ctrl key * /
BOOL useShiftKey=FALSE; / * don't use Shift key * /
/ * Entry point into the DLL. Do all necessary initialization here * /
int FAR PASCAL LibMain (hModule,wDataSeg,cbHeapSize,lpszCmdLine)
HANDLE hModule ;
WORD wDataSeg ;
WORD cbHeapSize ;
LPSTR lpszCmdLine ;
/ * initialize key state variables to zero * /
shiftKeyDown = 0 ;
ctrlKeyDown = 0 ;
return 1 ;
/* The keyboard filter searches for the hotkey key sequence.
If it gets it, it eats the key and displays a message box.
Any other key is sent on to Windows. * /
DWORD FAR PASCAL _loadds
KeyBoardProc (int nCode, WORD wParam, DWORD lParam)
BOOL fCallDefProc ;
DWORD dwResult = 0 ;
dwResult=SEND_KEY_ON ; / * default to send key on * /
fCallDefProc=TRUE; / * default to calling DefProc * /
switch (nCode) {
case HC ACTION :
case HC-NOREMOVE :
/ * If key is Shift , save it * /
if (wParam= = (WORD)VK_SHIFT) (
shiftKeyDown = ( (1Param & KEY_WAS_UP) ? 0 : 1 ) ;
break ;
/ * If key is Ctrl,save it * /
else if(wParam= = (WORD)VK_CONTROL) {
ctrlKeyDown=((lParam & KEY WAS UP)? 0:1);
break ;
/ * If key is the F6 key,act on it * /
else if(wParam= = (WORD)VK_F6) {
/ * Leave if the F6 key was a key release and not press * /
if (lParam * KEY_WAS_UP) break;
/ * Make sure Alt key is in desired state, else leave * /
if((useAltKey) && ! (lParam & ALT_KEY_DOWN) ) {
break ;
else if((!useAltKey) && (lParam & ALT KEY_DOWN)){
break ;
/ * Make sure Shift key in desired state, else leave * /
if(useShiftKey && ! shiftKeyDown){
break ;
else if ( !useShiftKey && shiftKeyDown) {
break ;
/ * Make sure Ctrl key in desired state, else leave * /
if(useCtrlKey && ! ctrlKeyDown){
break ;
else if ( !useCtrlKey && ctrlKeyDown) {
break ;
}
/ * Eat the keystroke, and don't call DefProc * /
dwResult = EAT_THE_KEY;
fCallDefProc =FALSE ;
/ * We made it, so Ctrl+Alt+F6 was pressed! * /
MessageBox (NULL, (LPSTR)" You pressed Ctrl + Alt + F6!" , (LPSTR)" Keyboard
Hook" ,MB_OK) ;
break ;
}
default :
fCallDefProc = TRUE ;
break ;
}
if((nCode<0) | (fCallDefProc && (nextKeyboardFilter ! =NULL)))
dwResult = DefHookProc (nCode, wParam, lParam,&nextKeyboardFilter) ;
return (dwResult) ;
}
/ * This function is called by the application to set up or tear
down the filter function hooks. * /
void FAR PASCAL
SetupFilters (BOOL install)
{
if (install) {
next KeyboardFilter = SetWindowsHook (WH-KEYBOARD,
(FARPROC) KeyBoardProc) ;
}
else {
UnhookWindowsHook (WH-KEYBOARD, (FARPROC)KeyBoardProe) ;
nextKeyboardFitter = NULL ;
}
}
Microsoft強調最好把過濾函數放在DLL中而不是放在應用程序中(注意在DLL中有LibMain()而沒有WinMain()),為了實現上述應用,你需要編寫一個普通的Windows應用程序來調用SetupFilters()函數——當該函數的參數值為TRUE時,該程序就開始監視鍵盤輸入;當該函數的參數值為FALSE時,該程序就停止監視鍵盤輸入。如果該程序被激活并且調用了SetupFilters(TRUE),回調函數KeyBoardProc()就會接收所有的鍵盤輸入,而不管你是否正在運行其它的Windows程序。如果你按下Ctrl+Altq+F6,屏幕上就會出現一個小的消息框,通知你這些鍵被你按下了。在按下這些鍵的那一剎那,正在運行的那個程序被中斷了。
注意,在DOS Shell下,鍵盤過濾函數不會接收鍵盤輸入,但是在出現象詢問你是否真的要退出Windows這樣的系統模式對話框時,它會接收鍵盤輸入并且中斷該對話框。
請參見:
20.12怎樣把數據從一個程序傳遞到另一個程序?
20.17可以使熱啟動(Ctrl+Alt+Delete)失效嗎?
21.10什么是動態連接?
20.9 為什么要使用靜態變量
靜態變量作為一個局部變量是很合適的,它在函數退出后不會失去其本身的值。例如,有一個要被調用很多次的函數,它的一部分功能就是計算自己被調用的次數。你不能用一個簡單的局部變量來實現這部分功能,因為每次進入該函數時,這個變量都沒有被初始化。如果把這個計數變量說明為靜態的,那么它就會象一個全局變量那樣保留自己的當前值。
那么為什么不直接使用一個全局變量呢?你可以使用一個全局變量,而且這樣做沒有錯誤。問題是使用了大量全局變量的程序維護起來很麻煩,尤其是有許多函數都各自訪問一個全局變量的程序。再說一遍,這樣做沒有錯誤,這只是一個程序設計和可讀性是否好的問題。如果你把這樣的變量說明為靜態的,你就可以提醒自己(或者其它可能讀你的程序的人)它是局部變量,但要象全局變量那樣被處理(保留自己的值)。如果你把它說明為全局的,那么讀這個程序的人一定會認為有很多地方要引用它,盡管實際上并不是這樣。
總而言之,當你需要一個能保持自己的值的局部變量時,使用靜態變量是一種好的編程習慣。
請參見:
2.17可以頭文件中說明static變量嗎?
20.10 怎樣在一個程序后面運行另一個程序?
顯然,在一個程序后面運行另一個程序的最簡單的辦法是把它們依次列入一個批處理文件中,在執行該批處理文件時,其中所列的程序就會依次運行。然而,這是一種人們已經知道的辦法。
在c或DOS中,都沒有一種特定的方法來完成“在一個程序結束后運行另一個程序”這樣一種函數調用。然而,c提供了兩組函數,它們允許一個程序隨時可以運行另一個程序,而后者的運行將結束前者的運行。如果你將這樣的一個函數調用放到第一個程序的末尾,你就能達到上述目的。C所提供的這兩組函數實際上是由exec()和spawn()所代表的兩個函數族,其中的每一個函數都具有一種區別于同族其它函數的功能。exec()函數族包括這樣一些成員:execl(),execle(),execlp(),execlpe(),execv(),execve(),execvp()和execvpe()。下面列出了這此函數名中的e,l,p和v等后綴的含義:
e 明確地把一個指向環境參數的指針數組傳遞給子進程
l 把命令參數逐個傳遞給要執行的程序
p 通過環境變量PATH找到要執行的文件
v 把命令行參數以一個指針數組的形式傳遞給要執行的程序
在程序中選用哪一個函數完全取決于你以及要執行的程序的需要。下例中的程序調用了其參數由命令行指定的另一個程序:
# include <stdio. h>
# include <process. h>
char * envString[] = { / * environment for the app * /
"COMM VECTOR=0x63", /* communications vector */
"PARENT=LAUNCH. EXE", / * name of this app * /
"EXEC=EDIT. COM", / * name of app to exec * /
NULL} ; / * must be NULL-terminated * /
void
main(int argc, char **argv)
{
/ * Call the one with variable argumets and an enviroffment * /
_execvpe (" EDIT. COM", argv, envString ) ;
printf("If you can read this sentence, the exec didn't happen!\n") ;
}
上面這個短小的例子調用_execvpe()來執行DOS的文件編輯器EDIT.COM,EDIT程序的參數來自該例的命令行。在調用execvpe()函數后,上例中的程序就結束了;當EDIT程序退出時,你將返回到DOS提示符。如果printf()語句的打印內容顯示在屏幕上,則說明_execvpe()函數調用出了問題,因為如果它調用成功,就不會有上述結果。注意,上例所提供的EDIT.COM的環境變量是沒有任何意義的,然而,如果上例要執行一個需要環境變量的程序,那么所提供的環境變量就能供該程序使用了。
用spawn()函數同樣可以完成上例所做的工作。spawn()函數族包括這樣一些成員:
spawnl(),spawnle()。spawnlp(),spawnlpe(),spawnv(),spawnve(),spawnvp()和spawnvpe()。這些函數名中的e,l,p和v等后綴的含義與exec()族函數名中的相同。實際上,spawn()函數族與exec()函數族基本相同,只不過有一點小小的差別——spawn()函數既可以在結束原來的程序后啟動另一個程序,也可以啟動另一個程序并在該程序結束后返回到原來的程序。spawn()函數的參數與exec()函數的基本相同,只不過需要增加一個參數一你必須用_P_OVERLAY(結束原來的程序)或_P_WAIT(結束后返回到原來的程序)作為spawn()函數的第一個參數。下例用spawn()函數完成了與前面的例子相同的工作:
# include <stdio. h>
# include <process. h>
char * envString[] = { / * environment for the app * /
"COMM VECTOR = 0x63", / * communications vector * /
"PARENT=LAUNCH. EXE", / * name of this app * /
"EXEC=EDIT. COM" , / * name of app to exec * /
NULL} ; / * must be NULL-terminated * /
void
main(int argc, char **argv)
{
/ * Call the one with variable argumets and an environment * /
_spawnvpe (_P_OVERLAY, "EDIT. COM", argv, envString) ;
printf("If you can read this sentence, the exec didn't happen!\n" );
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -