📄 第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 + -