如何编写C语言程序使热启动(Ctrl+Alt+Delete)失效
可以。尽管不容易讲清楚如何使热启动失效,但其编程实现却并非难事。为了捕获Ctrl+Alt+Delete击键序列,你必须利用键盘的中断服务程序(interrupt service routine,缩写为ISR)。从一个高的层次上讲,键盘ISR是这样工作的:监视(捕获)所有的键盘输入,等待Ctrl+Alt+Delete击键序列。如果捕获到的不是Ctrl+Alt+Delete击键序列,就把它传给“计算机”;如果捕获到Ctrl+Alt+Del击键序列,就把它抹掉(从键盘的字符缓冲区中删掉),或者把它转换为其它击键(你的程序知道这个击键表示用户想要热启动计算机)。在程序结束时,停止监视键盘输入并恢复正常的操作。这就是ISR的工作方式一~它们把自己连接到键盘和其它中断上,这样它们就能知道在什么时候出面去完成自己的任务。
那么你应该如何完成这些工作呢?当然,要用一个C程序。下面是一个简化了的例子,它监视所有的ctrl+Alt+Del击键序列,在该组合键按下时不作任何反应:
# include <stdlib. h>
# include <dos. h>
/ * function prototypes * /
void ( interrupt far_cdecl KbIntProc)(
unsigned short es,unsigned short ds, unsigned short di,
unsigned short si,unsigned short bp, unsigned short sp,
unsigned short bx,unsigned short dx, unsigned short cx,
unsigned short ax,unsigned short ip, unsigned short cs,
unsigned short flags);
void( interrupt far cdecl * OldKbIntProc) (void);
unsigned char far * kbFlags; / * pointer to keyboard flags * /
int key char, junk; * miscellaneous variables * /
/ * keyboard scancode valuss * /
# define AI.T 0x8
# define CTRL 0x4
# define KEY MASK 0x0F
# define DELETE 0x53
void
main(int argc,char ** argv)
{
int i,idx ;
/ * Save old interrupt vectors * /
OldKbIntProc= dos_getvect (0x9)
/* Set pointer to keyboard flags * /
FP SEG(kbFlags) = 0;
FP OFF(kbFlags) = 0x417;
/ * Add my ISR to the chain * /
dos setvect(0xg,KbIntProc) ;
/ * Print something while user presses keys... * /
/ * Until ESCAPE is pressed, then leave * /
while (getch() !=27){
printf ("Disallowing Ctrl+Alt+Delete... \n" );
}
/ * Remove myself from the chain * /
dos setvect(0x9,OldKbIntProc) ;
}
void _interrupt_far_cdecl KblntProc
unsigned short es,unsigned short ds, unsigned short di,
unsigned short si,unsigned short bp, unsigned short sp,
unsigned short bx,unsigned short dx, unsigned short cx,
unsigned short ax,unsigned short ip, unsigned short cs,
unsigned short flags)
{
/ * Get keystroke input from keyboard port * /
key_char =inp (0x60) ;
if( (( * kbFlags & KEY_MASK)= = (CTRL | ALT))
&& (key_char = =DELETE) ) {
/ * Reset the keyboard * /
junk = inp(0x61) ;
outp(0x61,(junk ] 0x80));
outp (0x61 ,iunk) ;
outp(0x60,(key_char | 0x80));
outp (0x60,0xgC) ;
}
/ * Reset the interrupt counter * /
outp (0x20,0x20) ;
/ * Now call the next ISR in line * /
( * OldKbIntProc) () ;
}
这个程序只有两个部分:main()函数体和键盘中断服务程序KbIntProc().main()函数先是通过dos getvect()来检索当前键盘中断服务程序(ISR)的地址,然后通过_dos_setvect()把键盘中断服务程序换为KbIntProc().while循环不断地接收键盘输入,并反复打印同一条消息,直到Escape键(其ASCII码为十进制数27)被按下为止。当Escape键被按下后,程序就调用dos_setvect()来恢复原来的键盘中断服务程序。
然而,好戏全在KbIntProc()之中。当它被装入后(通过前面所介绍的__dos_setvect()调用),它将在任何其它函数(或程序)之前看到所有的键盘输入,因此,它能首先处理或全部删掉键盘输入。当它接收到一个键时,它会检查键盘,看一看Ctrl键和Alt键是否已经被按下,并且检查所接收的键是否是Delete键。如果这两种情况都发生了,它就会复位键盘,从而删掉接收到的Delete键。不管所接收的键是否被忽略、处理或删掉,这个键盘ISR总要调用原来的键盘中断服务程序(OldKbIntProc());否则,计算机会立即停止运行。
如果你认真思考一下,你就会发现这个程序可以捕获任何击键或组合键,包括Ctrl+c和Ctrl+Break。因此,你完全可以考虑用这种办法来捕获Ctrl+Break组合键。应该指出的是,这种方法的入侵性比较强—— 一个很小的错误都会导致计算机停止运行。但是,你不要因此就不去学习或使用这种方法。
那么你应该如何完成这些工作呢?当然,要用一个C程序。下面是一个简化了的例子,它监视所有的ctrl+Alt+Del击键序列,在该组合键按下时不作任何反应:
# include <stdlib. h>
# include <dos. h>
/ * function prototypes * /
void ( interrupt far_cdecl KbIntProc)(
unsigned short es,unsigned short ds, unsigned short di,
unsigned short si,unsigned short bp, unsigned short sp,
unsigned short bx,unsigned short dx, unsigned short cx,
unsigned short ax,unsigned short ip, unsigned short cs,
unsigned short flags);
void( interrupt far cdecl * OldKbIntProc) (void);
unsigned char far * kbFlags; / * pointer to keyboard flags * /
int key char, junk; * miscellaneous variables * /
/ * keyboard scancode valuss * /
# define AI.T 0x8
# define CTRL 0x4
# define KEY MASK 0x0F
# define DELETE 0x53
void
main(int argc,char ** argv)
{
int i,idx ;
/ * Save old interrupt vectors * /
OldKbIntProc= dos_getvect (0x9)
/* Set pointer to keyboard flags * /
FP SEG(kbFlags) = 0;
FP OFF(kbFlags) = 0x417;
/ * Add my ISR to the chain * /
dos setvect(0xg,KbIntProc) ;
/ * Print something while user presses keys... * /
/ * Until ESCAPE is pressed, then leave * /
while (getch() !=27){
printf ("Disallowing Ctrl+Alt+Delete... \n" );
}
/ * Remove myself from the chain * /
dos setvect(0x9,OldKbIntProc) ;
}
void _interrupt_far_cdecl KblntProc
unsigned short es,unsigned short ds, unsigned short di,
unsigned short si,unsigned short bp, unsigned short sp,
unsigned short bx,unsigned short dx, unsigned short cx,
unsigned short ax,unsigned short ip, unsigned short cs,
unsigned short flags)
{
/ * Get keystroke input from keyboard port * /
key_char =inp (0x60) ;
if( (( * kbFlags & KEY_MASK)= = (CTRL | ALT))
&& (key_char = =DELETE) ) {
/ * Reset the keyboard * /
junk = inp(0x61) ;
outp(0x61,(junk ] 0x80));
outp (0x61 ,iunk) ;
outp(0x60,(key_char | 0x80));
outp (0x60,0xgC) ;
}
/ * Reset the interrupt counter * /
outp (0x20,0x20) ;
/ * Now call the next ISR in line * /
( * OldKbIntProc) () ;
}
这个程序只有两个部分:main()函数体和键盘中断服务程序KbIntProc().main()函数先是通过dos getvect()来检索当前键盘中断服务程序(ISR)的地址,然后通过_dos_setvect()把键盘中断服务程序换为KbIntProc().while循环不断地接收键盘输入,并反复打印同一条消息,直到Escape键(其ASCII码为十进制数27)被按下为止。当Escape键被按下后,程序就调用dos_setvect()来恢复原来的键盘中断服务程序。
然而,好戏全在KbIntProc()之中。当它被装入后(通过前面所介绍的__dos_setvect()调用),它将在任何其它函数(或程序)之前看到所有的键盘输入,因此,它能首先处理或全部删掉键盘输入。当它接收到一个键时,它会检查键盘,看一看Ctrl键和Alt键是否已经被按下,并且检查所接收的键是否是Delete键。如果这两种情况都发生了,它就会复位键盘,从而删掉接收到的Delete键。不管所接收的键是否被忽略、处理或删掉,这个键盘ISR总要调用原来的键盘中断服务程序(OldKbIntProc());否则,计算机会立即停止运行。
如果你认真思考一下,你就会发现这个程序可以捕获任何击键或组合键,包括Ctrl+c和Ctrl+Break。因此,你完全可以考虑用这种办法来捕获Ctrl+Break组合键。应该指出的是,这种方法的入侵性比较强—— 一个很小的错误都会导致计算机停止运行。但是,你不要因此就不去学习或使用这种方法。