自从用上LINUX后就用够了WINDOWS,但是好多研发还脱离不开DOS,真是没办法! 早就听说FREEDOS和MSDOS完全兼容,而且遵循的是GPL协议,所以下定决心脱离WINDOWS ,装了个FREEDOS!研发工具当然不能再用TURBO C啊等等原先商业化的东西了,用就用 个纯GNU的平台!好,就把TURBO C换成DJGPP吧,更有MASM和TASM,全部给我扔掉 ,换 成NASM!编辑器呢?用着EDIT根本就不爽,换成了DOS版的VIM,也是GNU工具!不好意思 ,中文平台还是得用UCDOS,因为似乎还没有GPL协议的中文化DOS平台呢,还好UCDOS是免 费的了,不会让我的系统中存在D版软件了,我也没有做贼的感觉了!^-^

OK,这一切都搞定了,可是面对DJGPP和NASM突然发觉自己什么都不会了,以前用 TURBO C和MASM写代码的时候调用中断啊,交互编程啊,现在都不知道怎么做了,靠,和 当初刚刚接触LINUX怎么相同啊!只好到http://delorie.com/djgpp去看了,全他妈的E 文的,硬着头皮看吧!总算找到了一些用户指南,读懂了,基本上能够解决以上问题了! 想一想,那么多和自己相同的家伙们肯定也是相同的头疼,所以写出来和大家一起分享, 并非是翻译的,因为我没有耐心去翻译那些洋话连篇的东西,还是根据我的理解来写一份 教程吧,但是大牛们就不必看了! 另外,本教程假设您对turbo c或DOS下的其他C/C 有一定了解并且作过一些中断 调用,中断驻留,显存映射操作连同C/C 和ASM混合编程!
OK,废话少说,本教程分为如下四个部分:
1 如何调用中断;
2 如何往VIDEO RAM中写入数据;
3 如何写中断驻留程式;
4 如何调用NASM写的汇编函数;
5 相关协议连同免责声明及其他
_____________________________________________________________________________________
1 如何调用中断: 在DJGPP中调用实模式中断和在TURBO C中使用INT86调用中断在形式上是很类似的,看 下面的例子(来自http://delorie.com/djgpp): #include void main(void){ __dpmi_regs r; r.x.ax = 0x13; r.d.ebx = 0x10000; r.h.cl = 4; r.h.dh = 5; __dpmi_int(0x10, &r); } __dpmi_regs是个结构,其中包含任何的80386用到的寄存器,假如您要使用8位寄存器 能够这样 __dpmi_regs.h.xx能够是ah, al, bh, bl等寄存器),假如您要使用16位寄存器 能够这样__dpmi_regs.x.即用x替换掉h即可),假如要使用32位寄存器,把h用d替 换就可 以了! 上面的代码就是调用int10中断,把显示模式配置为0x13(320*200 256)。 当中断执行完毕时,传给__dpmi_int的__dpmi_regs类型参数中将包含寄存器的新值,您 能够通过检测这些新值来分析中断的执行情况!注意,这些中断调用都是实模式下的! _____________________________________________________________________________________
2 如何往VIDEO RAM中写入数据: 往VIDEO RAM中写入数据有两种方法,这两种方法个有优缺点,您需要根据情况选择使用! 第一种方法: 下面是代码: #include void main(void){ char *screen; __dpmi_regs r; r.x.ax = 0x13; r.d.ebx = 0x10000; r.h.cl = 4; r.h.dh = 5; __dpmi_int(0x10, &r);/*配置为0x13显示模式*/ if (__djgpp_nearptr_enable() == 0) return 0; /* 有可能发生 */ screen = 0xa0000 __djgpp_conventional_base; screen[0] = 4;/*将屏幕左上角的一个点配置为红色*/ __djgpp_nearptr_disable(); } 这个例子在屏幕的左上角画一个红色的点。这种方法有下面两种缺点: <1>在调用一些特定的DPMI过程后,您必须重新计算video ram的近指针值! <2>在windows NT下不能用(至少在XP下是不能用的,但是在纯DOS下没问题)! 因此,一般并不推荐使用这种方法! 下面是第二种方法: #include #include int main(){ int x=0,y=0; char * screen; __dpmi_regs r; r.x.ax = 0x13; __dpmi_int(0x10, &r); _farsetsel(_dos_ds); _farnspokeb(0xA0000, 4); return 1; } 这个例子在屏幕的左上角画一个红色的点。他也有一个缺点,那就是比第一种方法要稍 微慢一点。但是他比较安全,据说能够在NT下使用(但是我在XP上验证的效果很糟糕),而 且不必重新计算VIDEO RAM的指针,在Allegro库中就是使用的这种方法,所以他的速度也是 比较不错的,所以推荐使用这种方法! _____________________________________________________________________________________
3 如何写中断驻留程式: 这儿有个程式,汉化自DJGPP的用户指南,不多说了,看程式,里面的注释已很清楚了!
#include
#include
#include
#include
#define LOCK_VARIABLE(x) _go32_dpmi_lock_data((void *)&x,(long)sizeof(x)); #define LOCK_FUNCTION(x) _go32_dpmi_lock_code(x,(long)sizeof(x));
#define TIMER 8/*时钟中断8每18.2 ms产生一次*/
int counter = 0;/*计数器初始值*/
void TickHandler(void){/*新的时钟中断处理程式*/ counter ; }
int main(void)
{ /*含有中断地址(selector:offset)信息的结构体*/
_go32_dpmi_seginfo OldISR, NewISR; printf("将要把新的中断处理程式连结到旧的中断处理程式上..n"); getkey(); /*锁住函数和变量*/ LOCK_FUNCTION(TickHandler); LOCK_VARIABLE(counter); /*把旧的中断地址写入OldISR结构变量中*/ _go32_dpmi_get_protected_mode_interrupt_vector(TIMER, &OldISR); /*把NewISR指向函数TickHandler的地址*/ NewISR.pm_offset = (int)TickHandler; NewISR.pm_selector = _go32_my_cs(); /*把NewISR指向的地址连接到中断8的地址上*/ _go32_dpmi_chain_protected_mode_interrupt_vector(TIMER,&NewISR); while (!kbhit()) printf("%dn",counter); printf("正在恢复原有的时钟中断。。。。。。n"); /*恢复原有的时钟中断*/ _go32_dpmi_set_protected_mode_interrupt_vector(TIMER, &OldISR); return 0; } _____________________________________________________________________________________

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!