浅析ANSI-C语言中的中断处理(如有疑问,敬请留言)

来源:互联网 发布:lte网络架构图 编辑:程序博客网 时间:2024/06/04 17:39

          设置一个好的时钟中断,将能使1个CPU发挥2个CPU的功效,大大方便和简化程序的编制,提高系统的运行效率和可操作性。我们可以把一些例行的或者需要定时执行的时钟中断中,还可以利用时钟中断完成定时、延时等操作。

        对于一般的C语言爱好者而言,就如何在C中使用中断例程这一问题应该已经非常熟悉,例如,我们可以通过INT86()函数调用13H号中断直接对磁盘物理扇区进行操作,也可以通过INT86()函数调用33H号中断在屏幕上显示鼠标光标等。其实,13H号也好,33H号也好,它们只不过就是一些函数,这些函数的参数通过CPU的寄存器传递。中断号也只不过是间接地指向函数体的起始内存单元,说它是间接的,也就是说,函数的起始段地址和偏移量是由中断号通过一种方法算得的(具体如何操作,下面会作解释)。如此一来,程序员不必要用太多的时间去写操作硬件的程序了,只要在自己的程序中设置好参数,再调用BIOS或DOS提供的中断服务程序就可以了,大大减小了程序开发难度,缩短了程序开发周期。那么中断既然是函数,就可以由用户任意的调用、由用户任意地编写。  
        计算机内存的前1024个字节(偏移量00000H到003FFH)保存着256个中断向量,每个中断向量占4个字节,前两个字节保存着中断服务程序的入口地址偏移量,后两个字节保存着中断程序的入口段地址,使用时,只要将它们分别调入寄存器IP及CS中,就可以转入中断服务程序实现中断调用。每当中断发生时,CPU将中断号乘以4,在中断向量表中得到该中断向量地址,进而获得IP及CS值,从而转到中断服务程序的入口地址,调用中断。这就是中断服务程序通过中断号调用的基本过程。在计算机启动的时候,BIOS将基本的中断填入中断向量表,当DOS得到系统控制权后,它又要将一些中断向量填入表中,还要修改一部分BIOS的中断向量。有一部分中断向量是系统为用户保留的,如60H到67H号中断,用户可以将自己的中断服务程序写入这些中断向量中。不仅如此,用户还可以自己更改和完善系统已有的中断向量。 

一、键盘中断的设计

例程如下:

/*键盘中断的设计*/#include<stdio.h>#include<dos.h>#include<conio.h>#include<math.h>#include<bios.h>#include<graphics.h>#include<stdlib.h>#include<string.h>/*定义按键*/#define ENTER 7181#define UP 18432#define DOWN 20480#define LEFT 19200#define RIGHT 19712#define LOWERV 12150/*定义delay()函数的间隔,根据电脑的不同请调节数字*/#define TIME 1500#define TIME2 1500/*myi,myj是自己的坐标,number记录豆子数,seed,seed2是种子参数,为产生随机数*/int myi,myj,number=0,seed=0,seed2=100;int a[25][19];                                        /*a[][]记录每个方格的信息,1墙,6豆子*/int d[4]={2,3,22,22},e[4]={5,16,3,16};      /*记录4个敌人的坐标,d记录横坐标,e纵坐标*/int i,j,k;/*指针记录自己坐标,以便于函数中的操作,具体请看moveright等函数*/int* p1=&myi;int* p2=&myj;int q=0,z=0;char num[4];/*存储画面用*/int size2,size3,size4,size5,size6;void *buffer2;void *buffer3;void *buffer4;void *buffer5;void *buffer6; /*主函数*/int main(){  int graphdriver=VGA;  int graphmode=VGAHI;  int* moveup(int*,int*);     /*该函数,自己向上移动一格,后三个类似*/  int* movedown(int*,int*);  int* moveleft(int*,int*);  int* moveright(int*,int*);  int dmove(int,int);         /*怪的移动:和自己拉近距离*/  int dmove2(int,int);   /*怪的移动:为了不让怪逼得太紧,该函数产生随机坐标,怪向那个坐标靠近一步*/  int zhadan1(int,int);     /*炸弹*/  for(i=0;i<25;i++)         /*数组a清零*/    for(j=0;j<19;j++)       a[i][j]=0;    for(i=0;i<25;i++)            /*最边上一圈设为7,(只为了填充颜色表示界限)之后会参数改1,表示墙体*/       a[i][0]=7,a[i][18]=7;    for(j=0;j<19;j++)       a[0][j]=7,a[24][j]=7;    /*以下是墙体*/    a[6][1]=1;a[13][1]=1;a[2][2]=1;a[20][2]=1;a[4][3]=1;a[8][3]=1;a[22][3]=1;    a[2][4]=1; a[6][4]=1; a[13][4]=1; a[18][4]=1;a[15][5]=1;a[4][6]=1;a[7][7]=1;a[10][7]=1;a[20][7]=1;a[3][8]=1;a[5][8]=1;a[16][8]=1; a[12][9]=1;  a[2][10]=1; a[19][10]=1; a[22][10]=0; a[5][11]=0;a[10][11]=1; a[17][12]=1;  a[14][13]=1; a[22][13]=1; a[3][14]=1;a[7][14]=1; a[5][15]=1; a[10][15]=1; a[2][16]=1; a[14][16]=1; a[19][16]=1; a[6][17]=1;a[16][17]=1;a[9][1]=1; a[11][2]=1; a[16][2]=1; a[9][5]=1; a[11][5]=1; a[22][5]=1; a[1][7]=1;a[17][6]=1;a[22][5]=1; a[13][7]=1; a[23][7]=1; a[18][8]=1; a[8][9]=1; a[15][10]=1; a[13][11]=1;a[3][12]=1;a[8][12]=1; a[20][12]=1; a[1][13]=1; a[12][14]=1; a[16][14]=1; a[19][14]=1; a[11][17]=1;    /*以下是豆子*/a[15][1]=6;a[18][1]=6;a[3][2]=6;a[18][2]=6;a[22][2]=6;a[7][3]=6;a[9][3]=6;a[11][3]=6;a[13][3]=6;a[1][4]=6;a[15][4]=6;a[20][4]=6;a[5][5]=6;a[13][5]=6;a[16][6]=6;a[19][6]=6;a[2][7]=6;a[15][7]=6;a[1][8]=6;a[9][8]=6;a[10][8]=6;a[11][8]=6;a[15][8]=6;a[6][9]=6;a[9][9]=6;a[17][9]=6;a[21][9]=6;a[3][10]=6;a[9][10]=6;a[10][10]=6;a[11][10]=6;a[16][10]=6;a[1][11]=6;a[8][11]=6;a[6][12]=6;a[9][12]=6;a[12][12]=6;a[16][12]=6;a[4][13]=6;a[9][14]=6;a[21][14]=6;a[17][15]=6;a[3][16]=6;a[7][16]=6;a[13][16]=6;a[9][17]=6;clrscr();initgraph(&graphdriver,&graphmode,"");/*墙体上色,参数1的为淡灰色,参数7的为棕色*/for(i=0;i<25;i++)for(j=0;j<19;j++){if(a[i][j]==1){setfillstyle(1,7);bar(i*25+1,j*25+1,25*i+25,25*j+25);}if(a[i][j]==7){setfillstyle(1,6);bar(i*25+1,j*25+1,25*i+25,25*j+25);}}/*参数7改1,表示墙体,以便于后边统一操作*/for(i=0;i<25;i++)a[i][0]=1,a[i][18]=1;for(j=0;j<19;j++)a[0][j]=1,a[24][j]=1;/*画自己,一个扇形*/setfillstyle(1,4);pieslice(288,238,15,345,11);myi=11,myj=9;/*画敌人*/setfillstyle(8,2);for(i=0;i<4;i++){bar(d[i]*25+3,e[i]*25+3,d[i]*25+24,e[i]*25+24);}/*画豆子*/for(j=1;j<18;j++)for(i=1;i<24;i++) {if(a[i][j]==6) {setfillstyle(1,14);pieslice(i*25+13,j*25+13,0,360,9);}} /*游戏的循环体开始了*/  /*游戏的循环体开始了*/do{int flag=0;        /*flag记录游戏状态,1输,2豆子未吃完,继续游戏,0游戏胜利*/int x,y,s=0;int key;/*判断一段时间内是否有按键按下,按下去执行按键判断部分,否则去执行敌人移动部分,用参数S来控制*/for(i=0;i<50;i++){delay(1);if(bioskey(1)!=0){           s=1;            break;             }       }if(s==1){ key=bioskey(0);switch(key){               /*按键判断:前四个方向,最后一个炸弹*/case UP:moveup(&myi,&myj);break;case DOWN:movedown(&myi,&myj);break;case RIGHT:moveright(&myi,&myj);break;case LEFT:moveleft(&myi,&myj);break;case LOWERV:zhadan1(myi,myj);break;}}   /*判游戏是否输了*/    for(i=0;i<4;i++){        if(myi==d[i]&&myj==e[i])flag=1;    }    if(flag==1){printf("                                you lose!                                       ");getchar();break;    }/*根据敌人的移动,来设置敌人坐标的变化*/for(z=0;z<4;z++)if (q++%3==0) {    /*每三次里面有一次为向自己移动,另两次随机动,可以把三改掉来修改游戏难度*/x=dmove(d[z],e[z]);if(x==1)d[z]-- ;else if(x==2)d[z]++ ;else  if(x==3)e[z]++ ;else   if(x==4)e[z]-- ;}else{y=dmove2(d[z],e[z]);if(y==1)d[z]-- ;else if(y==2)d[z]++ ;else  if(y==3)e[z]++ ;else   if(y==4)e[z]-- ;}/*左上角显示拥有的豆子数*/setfillstyle(1,8);bar(1,1,150,22);k=number;itoa(k,num,10);settextstyle(1,0,1);outtextxy(1,1,"  your peas: ");outtextxy(120,1,num);/*敌人移动过了,所以再次判断是否输了*/for(i=0;i<4;i++){          if(myi==d[i]&&myj==e[i])flag=1;}if(flag==1){printf("                                you lose!                                       ");getchar();break;}/*判断是否胜利*/for(j=1;j<18;j++)for(i=1;i<24;i++) {if(a[i][j]==6)flag=2;}if(flag==0){printf("                                you win!                                       ");getchar();break;}}while(1);} /*自己向右移动的函数:传地址进来,以便直接在函数中改坐标,而不用像怪移动那样在主函数里改坐标*/int* moveright(int *p1 ,int *p2) {       if(a[*p1+1][*p2]!=1)                    /*右边不是墙体才可以动*/       {            /*这四行画自己,嘴巴向右*/            setfillstyle(1,0);            bar(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);            setfillstyle(1,4);            pieslice(*p1*25+13,*p2*25+13,15,345,11);            /*保存自己的图像,以便于动画*/            size2=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);            buffer2=malloc(size2);            getimage(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25,buffer2);            /*向右移动时的动画*/for(i=0;i<25;i++){setfillstyle(1,0);bar(*p1*25+i+1,*p2*25+1,*p1*25+i+2,*p2*25+25);   /*每次把最左边一条竖线擦掉*/putimage(*p1*25+i+2,*p2*25+1,buffer2,0);      /*每次图像显示向右一个像素*/delay(TIME2);}(*p1)++;    /*自己的横坐标加1*/if(a[*p1][*p2]==6)      /*移动后有豆子就吃掉,同时参数6被改掉*/a[*p1][*p2]=4,number++;free(buffer2);    /*释放存储图像的指针,不然移动多次后内存不够用,会去侵占number变量的                                       内存,导致number变0,这个问题自己调试了好久*/}}  /*自己向右移动的函数,由于pieslice()函数无法一笔画(反正我自己不会),所以画图像要解释下*/ int* moveleft(int *p1,int *p2) {if(a[*p1-1][*p2]!=1) {        setfillstyle(1,0);               /*先把当前一格变成背景黑色 */        bar(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);        setfillstyle(1,4);             /*画个红色的圆,默认白色边界*/        fillellipse(*p1*25+13,*p2*25+13,11,11);        setfillstyle(1,0);        /*画个黑色扇形,这个可以一笔画,但是边界是白色,相当于嘴巴被白色封了*/        pieslice(*p1*25+13,*p2*25+13,162,202,11);      /*至于为什么是162°到202°,因为160-200显示的时                                                                           候多个角,不知道为什么*/        setcolor(0);      /*设置 黑色*/        arc(*p1*25+13,*p2*25+13,157,200,11);   /*用黑色的线画一条弧,用来覆盖原来的白色*/        setcolor(15);    /*把前景色还原为白色,不然以后画出来的都要黑色了*/       /*这些跟上面函数一样,不罗嗦了,之后的两个函数也一样*/        size3=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);        buffer3=malloc(size3);        getimage(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25,buffer3);for(i=0;i<25;i++){setfillstyle(1,0);bar(*p1*25+24-i,*p2*25+1,*p1*25+25-i,*p2*25+25);putimage(*p1*25-i,*p2*25+1,buffer3,0);delay(TIME2);}        (*p1)--;if(a[*p1][*p2]==6)a[*p1][*p2]=4,number++;        free(buffer3);    }} int* moveup(int* p1,int* p2){     if(a[myi][myj-1]!=1) {         setfillstyle(1,0);         bar(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);         setfillstyle(1,4);         fillellipse(*p1*25+13,*p2*25+13,11,11);         setfillstyle(1,0);         pieslice(*p1*25+13,*p2*25+13,70,110,11);         setcolor(0);         arc(*p1*25+13,*p2*25+13,70,110,11); setcolor(15);         size4=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);         buffer4=malloc(size4);         getimage(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25,buffer4);         for(i=0;i<25;i++) {setfillstyle(1,0);bar(*p1*25+1,*p2*25+24-i,*p1*25+25,*p2*25+25-i);putimage(*p1*25+1,*p2*25-i,buffer4,0);delay(TIME2); }         (*p2)--;         if(a[*p1][*p2]==6)number++,a[*p1][*p2]=4;         free(buffer4);    }} int* movedown(int *p1,int *p2){    if(a[myi][myj+1]!=1){        setfillstyle(1,0);        bar(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);        setfillstyle(1,4);        fillellipse(*p1*25+13,*p2*25+13,11,11);        setfillstyle(1,0);        pieslice(*p1*25+13,*p2*25+13,250,290,11);        setcolor(0);        arc(*p1*25+13,*p2*25+13,247,288,11);        setcolor(15);        size5=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);        buffer5=malloc(size5);        getimage(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25,buffer5);        for(i=0;i<25;i++){setfillstyle(1,0);bar(*p1*25+1,*p2*25+1+i,*p1*25+25,*p2*25+i+1);putimage(*p1*25+1,*p2*25+2+i,buffer5,0);delay(TIME2);        }        (*p2)++;        if(a[*p1][*p2]==6)            number++,a[*p1][*p2]=4;        free(buffer5);}}  /*怪的移动:向自己靠近*/int  dmove(d,e){    if(d-myi>0&&a[d][e]==6&&a[d-1][e]!=1){     /*怪在自己的右方&&怪现在的坐标有豆子&&左边一格不                                                                   是墙*//* 怪移动的动画*/            for(i=0;i<25;i++){setfillstyle(1,0);         /*每次用背景黑色擦掉最右边一竖线*/bar(d*25+25-i,e*25+1,d*25+26-i,e*25+25);setfillstyle(8,2);   /*每次在左边画一条线,怪设计成正方形方便(不用图像存储),偷个懒*/bar(d*25-i,e*25+1,d*25+1-i,e*25+25);delay(TIME);            }/*因为有豆子,所以添上豆子*/setfillstyle(1,14);pieslice(d*25+13,e*25+13,0,360,9);return 1;      /*1传回去表示让怪的横坐标要减一*/    }    else if(d-myi>0&&a[d-1][e]!=1&&a[d][e]!=6){/*没豆子的情况:本来可以和上面合并,不改了*/            for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+25-i,e*25+1,d*25+26-i,e*25+25);setfillstyle(8,2);bar(d*25-i,e*25+1,d*25+1-i,e*25+25);delay(TIME);            }return 1;    }if(d-myi<0&&a[d][e]==6&&a[d+1][e]!=1){/*怪在自己的左方,有豆子,其他都同上上面那个*/for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1+i,e*25+1,d*25+2+i,e*25+25);setfillstyle(8,2);bar(d*25+25+i,e*25+1,d*25+26+i,e*25+25);delay(TIME);}        setfillstyle(1,14);pieslice(d*25+13,e*25+13,0,360,9);return 2;}else if(d-myi<0&&a[d+1][e]!=1&&a[d][e]!=6){      /*怪在自己左方,没豆子*/            for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1+i,e*25+1,d*25+2+i,e*25+25);setfillstyle(8,2);bar(d*25+25+i,e*25+1,d*25+26+i,e*25+25);delay(TIME);}return 2;}    /*如果横坐标和自己同或者左右移动时碰到墙了,就要动纵坐标了,和上面几乎一样*/if(d==myi||(d-myi<0&&a[d+1][e]==1)||(d-myi>0&&a[d-1][e]==1)){if(e-myj<0&&a[d][e]==6&&a[d][e+1]!=1){            for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1,e*25+1+i,d*25+25,e*25+2+i);setfillstyle(8,2);bar(d*25+1,e*25+25+i,d*25+25,e*25+26+i);delay(TIME);}setfillstyle(1,14);pieslice(d*25+13,e*25+13,0,360,9);return 3;}else if(e-myj<0&&a[d][e+1]!=1&&a[d][e]!=6){            for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1,e*25+1+i,d*25+25,e*25+2+i);setfillstyle(8,2);bar(d*25+1,e*25+25+i,d*25+25,e*25+26+i);delay(TIME);}return 3;}if(e-myj>0&&a[d][e]==6&&a[d][e-1]!=1){for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1,e*25+24-i,d*25+25,e*25+25-i);setfillstyle(8,2);bar(d*25+1,e*25-i,d*25+25,e*25+1-i) ;delay(TIME);}setfillstyle(1,14);pieslice(d*25+13,e*25+13,0,360,9);return 4;}else if(e-myj>0&&a[d][e-1]!=1&&a[d][e]!=6){for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1,e*25+24-i,d*25+25,e*25+25-i);setfillstyle(8,2);bar(d*25+1,e*25-i,d*25+25,e*25+1-i);delay(TIME);}return 4;}}} /*怪随机动,其实和前面那个一样,就是和自己坐标myi,myj比较变成了和随机产生的坐标(a1,b)比较,既然一样,就不多说,产生随机数解释下*/int dmove2(d,e){    int a1,b;    srand(seed++);     /*种子每次要变,不然产生的随机数会相同*/    a1=rand()%24;       /*取余数才能使坐标落在我游戏画面内*/    b=rand()%18;    if(d-a1>0&&a[d][e]==6&&a[d-1][e]!=1){for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+25-i,e*25+1,d*25+26-i,e*25+25);setfillstyle(8,2);bar(d*25-i,e*25+1,d*25+1-i,e*25+25);            delay(TIME);}setfillstyle(1,14);pieslice(d*25+13,e*25+13,0,360,9);return 1;    }    else if(d-a1>0&&a[d-1][e]!=1&&a[d][e]!=6){               for(i=0;i<25;i++){        setfillstyle(1,0);        bar(d*25+25-i,e*25+1,d*25+26-i,e*25+25);        setfillstyle(8,2);        bar(d*25-i,e*25+1,d*25+1-i,e*25+25);        delay(TIME);    }        return 1;      }    if(d-a1<0&&a[d][e]==6&&a[d+1][e]!=1){for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1+i,e*25+1,d*25+2+i,e*25+25);setfillstyle(8,2);bar(d*25+25+i,e*25+1,d*25+26+i,e*25+25);delay(TIME);}        setfillstyle(1,14);pieslice(d*25+13,e*25+13,0,360,9);return 2;    }    else if(d-a1<0&&a[d+1][e]!=1&&a[d][e]!=6){        for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1+i,e*25+1,d*25+2+i,e*25+25);setfillstyle(8,2);bar(d*25+25+i,e*25+1,d*25+26+i,e*25+25);delay(TIME);}return 2;    }if(d==a1||(d-a1<0&&a[d+1][e]==1)||(d-a1>0&&a[d-1][e]==1)){if(e-b<0&&a[d][e]==6&&a[d][e+1]!=1){for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1,e*25+1+i,d*25+25,e*25+2+i);setfillstyle(8,2);bar(d*25+1,e*25+25+i,d*25+25,e*25+26+i) ;delay(TIME);}setfillstyle(1,14);pieslice(d*25+13,e*25+13,0,360,9);            return 3;        }else if(e-b<0&&a[d][e+1]!=1&&a[d][e]!=6){            for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1,e*25+1+i,d*25+25,e*25+2+i);setfillstyle(8,2);bar(d*25+1,e*25+25+i,d*25+25,e*25+26+i) ;delay(TIME);}return 3;}if(e-b>0&&a[d][e]==6&&a[d][e-1]!=1){for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1,e*25+24-i,d*25+25,e*25+25-i);setfillstyle(8,2);bar(d*25+1,e*25-i,d*25+25,e*25+1-i);delay(TIME);}setfillstyle(1,14);pieslice(d*25+13,e*25+13,0,360,9);return 4;}else if(e-b>0&&a[d][e-1]!=1&&a[d][e]!=6){for(i=0;i<25;i++){setfillstyle(1,0);bar(d*25+1,e*25+24-i,d*25+25,e*25+25-i);setfillstyle(8,2);bar(d*25+1,e*25-i,d*25+25,e*25+1-i) ;delay(TIME);}return 4;}}}  /*炸弹的函数*/int zhadan1(myi,myj){if(number<3)      /*豆子数比三大才能炸*/return 0;else{number=number-3;     /*炸一次消耗三个豆子*//*保存自己的图像*/size6=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);buffer6=malloc(size6);getimage(myi*25+1,myj*25+1,myi*25+25,myj*25+25,buffer6);         /*判断怪是否在炸弹的威力范围里面,若在,怪的坐标变掉,用随机数产生,但是不能产生在墙里,也不能靠自己太近*/for(i=0;i<4;i++){if(myi-1==d[i]&&myj==e[i]){do{srand(seed2++);d[i]=rand()%24;e[i]=rand()%18;}while(a[d[i]][e[i]]==1||(d[i]-myi)*(d[i]-myi)+(e[i]-myj)*(e[i]-myj)<5);setfillstyle(1,7);bar(d[i]*25+1,e[i]*25+1,d[i]*25+25,e[i]*25+25);}else  if(myi+1==d[i]&&myj==e[i]){do{srand(seed2++);d[i]=rand()%24;e[i]=rand()%18;}while(a[d[i]][e[i]]==1||d[i]==myi&&e[i]==myj);setfillstyle(1,7);bar(d[i]*25+1,e[i]*25+1,d[i]*25+25,e[i]*25+25);}else  if(myi==d[i]&&myj-1==e[i]){do{srand(seed2++);d[i]=rand()%24;e[i]=rand()%18;}while(a[d[i]][e[i]]==1||d[i]==myi&&e[i]==myj) ;setfillstyle(1,7);bar(d[i]*25+1,e[i]*25+1,d[i]*25+25,e[i]*25+25);}else  if(myi==d[i]&&myj+1==e[i]){do{srand(seed2++);d[i]=rand()%24;e[i]=rand()%18;}while(a[d[i]][e[i]]==1||d[i]==myi&&e[i]==myj);setfillstyle(1,7);bar(d[i]*25+1,e[i]*25+1,d[i]*25+25,e[i]*25+25);}elseseed2++;} /*画一个方格的炸弹作为动画的开始*/setfillstyle(7,13);bar(myi*25+1,myj*25+1,myi*25+25,myj*25+25);/*炸弹的动画,每次在上一步的基础上,上下左右各添一条线*/for(i=0;i<24;i++){setfillstyle(7,13);bar(myi*25-1-i,myj*25+1,myi*25-i,myj*25+25);bar(myi*25+26+i,myj*25+1,myi*25+27+i,myj*25+25);bar(myi*25+1,myj*25-1-i,myi*25+25,myj*25+25);bar(myi*25+1,myj*25+26+i,myi*25+25,myj*25+27+i);delay(2000);}delay(10000);/*炸弹动画结束以后把炸弹炸到的区域清成背景黑色*/setfillstyle(1,0);bar(myi*25-24,myj*25+1,myi*25+50,myj*25+25);bar(myi*25+1,myj*25-24,myi*25+25,myj*25+50);/*如果该范围里面有墙体,要重新补上*/for(i=myi-1;i<=myi+1;i++)for(j=myj-1;j<=myj+1;j++){if(a[i][j]==1){if(i==0||i==24||j==0||j==18)setfillstyle(1,6),bar(i*25+1,j*25+1,25*i+25,25*j+25);elsesetfillstyle(1,7),bar(i*25+1,j*25+1,25*i+25,25*j+25);}}/*炸弹范围内的豆子被炸掉,所以参数6要被改掉,索性非墙的方格参数全设为5*/for(i=myi-1;i<=myi+1;i++) {if(a[i][myj]!=1)a[i][myj]=5;}for(i=myj-1;i<=myj+1;i++){if(a[myi][i]!=1)a[myi][i]=5;}/*最后把自己的图像补上*/putimage(myi*25+1,myj*25+1,buffer6,0);free(buffer6);}}



 

二、鼠标中断的设计

例程如下:

头文件例程

/*鼠标中断设计*/#ifndef __KEY_MOU_H__#define __KEY_MOU_H__#include<stdio.h>#include<graphics.h>#include<dos.h>#include<stdlib.h>union REGS regs;void shubiao(int x,int y);int init(int xmin,int xmax,int ymin,int ymax);void read();void cursor(int x,int y);void newxy();void mouse_scan1(int * x,int * y,int * buttons,int * done1,int * help);void mouse_scan2(int * x,int * y,int * buttons,int * done2,int *done);#define KB_S_N_DOWN         80       //定义各功能键的扫描码#define KB_S_N_UP           72 #define KB_S_N_HOME         71 #define KB_S_N_END          79#define KB_S_N_ENTER        28 #define KB_S_N_F1           59 #define KB_S_N_D            32 #define KB_S_N_H            35 #define KB_S_N_O            24 #define KB_S_N_Q            16#define KB_S_N_X            45#define KB_S_N_B            0x3062int getkey();void key_scan1(int it_num,int * done1,int * hp,void * buffer);void key_scan2(int it_num,int * done2,int * done,void *buffer);int row=0;extern int a;int help();void quit(void * buffer);#endif


 

函数体例程

/*鼠标中断设计*/#include"key_mou.h"/*************鼠标函数*********************/void shubiao(int x,int y){int xmin=2;int xmax=638;int ymin=2;int ymax=478;setwritemode(XOR_PUT);if(init(xmin,xmax,ymin,ymax)==0){printf("Mouse or Mouse Driver Absent,Please Install!");delay(5000);exit(1);}cursor(x,y);delay(5);}int init(int xmin,int xmax,int ymin,int ymax){int retcode;regs.x.ax=0;//鼠标复位及取状态int86(51,®s,®s);retcode=regs.x.ax;if(retcode==0){return 0;//返回0表示鼠标或鼠标驱动程序未安装}regs.x.ax=7;//设置水平位置最大值regs.x.cx=xmin;regs.x.dx=xmax;int86(51,®s,®s);regs.x.ax=8;//设置垂直位置最大值regs.x.cx=ymin;regs.x.dx=ymax;int86(51,®s,®s);     //表示鼠标器和安装程序已安装return retcode;}void  read(int *px,int *py,int *mbutt)//读鼠标的按键位置和按键状态{regs.x.ax=3;//取按钮状态和鼠标位置int86(51,®s,®s);* px=regs.x.cx;* py=regs.x.dx;* mbutt=regs.x.bx;delay(100);}void cursor(int x,int y)//画十字光标函数{    setwritemode(1);    setcolor(BLUE);    setlinestyle(0,0,1);    line(x,y,x,y+11);    line(x+1,y+1,x+1,y+10);    line(x+2,y+2,x+2,y+9);    line(x+3,y+3,x+8,y+8);    line(x+3,y+4,x+7,y+8);    line(x+3,y+5,x+6,y+8);    line(x+3,y+6,x+5,y+8);    line(x+3,y+7,x+4,y+8);    line(x+3,y+8,x+3,y+8);    setwritemode(0);}   void newxy(int * x,int * y,int * mbutt){int xx0=* x,yy0=* y;int mx,my;read(&mx,&my,mbutt);cursor(xx0,yy0);cursor(mx,my);delay(5);* x=mx;* y=my;}  /***************菜单一中扫描鼠标**********************/void mouse_scan1(int * x,int * y,int * buttons,int * done1,int * hp){int k=0;/*读鼠标*/newxy(x,y,buttons);if(* x>=210&&* x<=435&&* y>=215&&* y<=260&&* buttons==1){* done1=1;}else if(* x>=210&&* x<=435&&* y>=260&&* y<=305&&* buttons==1){k=help();if(k==1){cleardevice();* done1=1;* hp=1;}}else if(* x>=210&&* x<=435&&* y>=305&&* y<=350&&* buttons==1){cleardevice();closegraph();exit(0);//回到系统}}/*****************菜单二中扫描鼠标*************************/void mouse_scan2(int * x,int * y,int * buttons,int * done2,int *done){/*读鼠标*/newxy(x,y,buttons);if(*x>=400&&* x<=530&&*y>=160&&* y<=200&&* buttons==1){a=1;    //进入单人游戏* done2=1;* done=1;}else if(* x>=400&&* x<=530&&* y>=220&&* y<=260&&* buttons==1){a=2;    //进入双人游戏* done2=1;* done=1;}else if(* x>=400&&* x<=530&&* y>=220&&* y<=320&&* buttons==1){cleardevice();* done2=1;}}/*******************键盘函数*************************/int getkey(){union REGS rg;rg.h.ah=0;int86(0x16,&rg,&rg);return rg.h.ah;}/*****菜单一中扫描键盘*******/void key_scan1(int it_num,int * done1,int * hp,void * buffer)                {int key=0;int k=0;key=getkey();switch(key){case KB_S_N_UP:putimage(180,220+row*45,buffer,XOR_PUT);     //消除原来的光标row-=1;if(row==-1){row=it_num-1;}putimage(180,220+row*45,buffer,XOR_PUT);           //光标上移并显示break;case KB_S_N_DOWN:putimage(180,220+row*45,buffer,XOR_PUT);     //消除原来的光标row+=1;if(row==3){row=0;}putimage(180,220+row*45,buffer,XOR_PUT);           //光标下移并显示break;case KB_S_N_F1:k=help();if(k==1){cleardevice();* done1=1;* hp=1;}break;case KB_S_N_X:quit(buffer);break;case KB_S_N_ENTER:switch(row){case 0: * done1=1;break;case 1: k=help();    if(k==1)    {   cleardevice();   * done1=1;   * hp=1;    }break;case 2: quit(buffer);break;}break;case 0:break;}}/*******菜单二中键盘扫描键盘*********/void key_scan2(int it_num,int * done2,int * done,void *buffer){int key=0;key=getkey();switch(key){case KB_S_N_UP:putimage(375,170+row*60,buffer,XOR_PUT);     //消除原来的光标row-=1;if(row==-1){row=it_num-1;}putimage(375,170+row*60,buffer,XOR_PUT);           //光标上移并显示break;case KB_S_N_DOWN:putimage(375,170+row*60,buffer,XOR_PUT);     //消除原来的光标row+=1;if(row==3){row=0;}putimage(375,170+row*60,buffer,XOR_PUT);           //光标下移并显示break;case KB_S_N_ENTER:switch(row){case 0: a=1;            //进入单人模式* done2=1;* done=1;break;case 1: a=2;          //进入双人模式* done2=1;* done=1;break;case 2: cleardevice();setbkcolor(BLACK);* done2=1;break;}break;case 0:break;}}


 

三、禁用鼠标中断或键盘中断的设计

例程如下:

/*禁用键盘中断或鼠标中断的设计*/#define   _WIN32_WINNT   0x0400#include   <windows.h>       HHOOK        mouseHook = NULL;HHOOK        keyboardHook = NULL;   HINSTANCE    hInst = NULL;       int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved){    switch(dwReason)    {    case DLL_PROCESS_ATTACH:        hInst = hInstance;        break;    case DLL_PROCESS_DETACH:        if (keyboardHook)        {            UnhookWindowsHookEx(keyboardHook);        }        if (mouseHook)        {            UnhookWindowsHookEx(mouseHook);        }        break;    case DLL_THREAD_ATTACH:        break;    case DLL_THREAD_DETACH:        break;    }    return 1;}long CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam){    return 1;}long CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam){    return 1;}BOOL CALLBACK LockKeyboard(BOOL bDisable){    if (bDisable)    {        if (keyboardHook == NULL)        {            keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardProc, hInst, NULL);        }        if (mouseHook == NULL)        {            mouseHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)MouseProc, hInst, NULL);        }        return keyboardHook != NULL && mouseHook != NULL;    }    else    {        if (keyboardHook && UnhookWindowsHookEx(keyboardHook))        {            keyboardHook = NULL;        }        return keyboardHook == NULL && mouseHook == NULL;    }}//调用事例 C/C++ code#include <windows.h>#define DLLFILENAME    TEXT("locklib.dll")typedef BOOL (__stdcall *LockKeyboard)(BOOL);LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){     static TCHAR szAppName[] = TEXT ("AutoUpgrade") ;     MSG          msg ;     HWND         hwnd ;     WNDCLASS     wndclass ;          wndclass.style         = CS_HREDRAW | CS_VREDRAW ;     wndclass.lpfnWndProc   = WndProc ;     wndclass.cbClsExtra    = 0 ;     wndclass.cbWndExtra    = 0 ;     wndclass.hInstance     = hInstance ;     wndclass.hIcon         = LoadIcon (hInstance, szAppName) ;     wndclass.hCursor       = NULL     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;     wndclass.lpszMenuName  = szAppName ;     wndclass.lpszClassName = szAppName ;          if (!RegisterClass (&wndclass))     {            return 0 ;     }          hwnd = CreateWindow (szAppName,                        TEXT ("AutoUpgrade"),                        WS_OVERLAPPEDWINDOW,                        CW_USEDEFAULT, CW_USEDEFAULT,                        CW_USEDEFAULT, CW_USEDEFAULT,                        NULL, NULL, hInstance, NULL) ;          ShowWindow (hwnd, iCmdShow) ;     UpdateWindow (hwnd) ;     ShowCursor(FALSE);          while (GetMessage (&msg, NULL, 0, 0))     {          TranslateMessage (&msg) ;          DispatchMessage (&msg) ;     }     return msg.wParam ;}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){    static HINSTANCE hInstance;    static LockKeyboard lockKeyboard;    switch (message)    {    case WM_CREATE:        hInstance = LoadLibrary(DLLFILENAME);        if (hInstance)        {            lockKeyboard = (LockKeyboard)GetProcAddress(hInstance, TEXT("LockKeyboard"));            if (lockKeyboard != NULL)            {                (lockKeyboard)(TRUE);            }        }        break;    case WM_DESTROY :        if (lockKeyboard)        {            (lockKeyboard)(FALSE);        }        if (hInstance)        {            FreeLibrary(hInstance);        }        PostQuitMessage (0);        return 0 ;    }    return DefWindowProc (hwnd, message, wParam, lParam) ;}