没有一个普通的方法可以中断一个Windows程序,从而让你去完成一项必需的任务(如果这就是你的目标的话)。Windows 3.x是一种不支持优先调度的多任务操作系统,换句话说,它是一种合作性(cooperative)的多任务操作系统——原因之一就是你无法简单地从当前正在由处理器控制着的一个Windows程序中抢占一段时间。如果你看一下Windows API,你会发现PeekMessage()和WaitMessage()这样一些函数,在Microsoft的帮助文档中有这样一段介绍这些函数的话:
函数GetMessage(),PeekMessage()和WaitMessage()把控制权交给别的应用程序,允许别的应用程序运行的唯一方法就是使用这些函数。如果一个应用程序长时间不调用这些函数,那么它就阻止了别的应用程序的运行。
尽管这样,你还是可以中断一个Windows程序的。一种办法是在你的Windows程序中建立一个定时器,它每隔一段时间就会发出信号,只要你的程序处于激活的状态,那么在定时器发出信号的时候,你就能获得时间来完成各种所需的工作。但是,从技术角度来讲,这种方法并没有中断一个程序的处理过程——它只是应用了Windows的合作性多任务性能。如果你需要中断一个Windows程序,你可以使用过滤函数(filter function,也叫做hook function,即钩子函数)。Windows中的过滤函数与DOS中的中断处理程序相似(见20.12和20.17),你可用它“挂上(hook)”某个Windows事件,并在该事件发生时执行相应的任务。实际上,你可以用一个使用了一个或多个可用的钩子(hook)的过滤器来监视Windows中的几乎每一条消息。下面的例子使用了键盘钩子,因为它要使你能随时按一个特定的组合键来中断一个程序。该例挂上了键盘事件链,并且在Ctrl+Alt+F6键按下时打开一个消息框。不管当前正在执行的是哪一个应用程序,该例都能起作用。
# 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这样的系统模式对话框时,它会接收键盘输入并且中断该对话框。