本是
银牌会员
积分 2201
发帖 789
注册 2005-1-27
状态 离线
|
『楼 主』:
QBASIC对QB中断调用的移植及绝对地址调用的扩展
''''本程序只能运行于QBASIC.exe解释环境下!
''''此程序不能在QB.exe或VBDOS.exe等编译环境下运行!
'
' 关于QBASIC对QB中断调用的移植及绝对地址调用的扩展
'
' 近来,市场上出现了不少如何使用QBASIC的书,理由一般有二:一、QBASIC为
'高版本MS-DOS自动搭售,不需要另外花钱购买,只要购买了MS-DOS,
'就不会产生版权之争;二、它是QB编译版稍经简化的解释版本,简便易学,功能
'强大,既向下兼容GW-BASIC,又向上兼容面向窗口编程的VB,又对目前流行的 C或
' C++语言程序设计的结构化练兵,其兼容性和扩展性俱佳。当然,另外还有一点:
'BASIC语言的长寿和普及早已成为不争的事实。
' 但是,不论是这些书中还是QBASIC的在线帮助的未支持的关键词中都说
'1)QBASIC不支持IntXXXXX系列的关键词--中断调用成为泡影;
'2)QBASIC提供内部支持的Absolute关键词,常常因Declare申明中参数数量、类型
'及顺序的不确定性,使申明异常困难--绝对地址调用也不能顺畅。这就大大减弱
'了QBASIC的编程实用性。
' 笔者通过对QBASIC与汇编语言的连接接口规范及相关关键词的深入研究,发现
'通过以本程序中最大数量的参数表进行ANY型申明(使用时,参数数量小于最大数
'量的,要对Absolute中开始的共(参数数量最大值-本调用参数数量值)个参数填
'入任意值)的方法解决了第二个问题,以通过对QB.LIB中INTRPT.obj模块的库操作
'和反汇编,结合Absolute调用,解决了第一个问题。
' 从此,本来只有在QB编译版中可以很方便地调用的中断调用如今在解释版的
'QBASIC中也能如意了----也就是说, QBASIC中也可以实现多个汇编语言子程序对
'QBASIC功能的扩展。而且,这种扩展在国内外尚属首次!
'
' 后面附上QBASIC源程序一和汇编子程序二与三。
'
'
'程序一
''$INCLUDE: "QB.BI" '此行QBASIC中无效,故行首加'
' 在 QBASIC 中,我们可以用
' DEF SEG = 汇编子程序段地址%
' CALL ABSOLUTE (中断号%,
' inreg AS RegTypeX,
' outreg AS RegTypeX
' 汇编子程序偏移地址%)
'
' 入口:
' 中断号% = 0 到 255
' inreg 和 outreg 为寄存器变量, 必须事先申明作自定义数据类型
' RegTypeX, 方法如下:
'
'自定义变量类型申明
'TYPE RegTypeX
' AX AS INTEGER
' BX AS INTEGER
' CX AS INTEGER
' DX AS INTEGER
' BP AS INTEGER
' SI AS INTEGER
' DI AS INTEGER
' FLAGS AS INTEGER
' DS AS INTEGER
' ES AS INTEGER
'END TYPE
'
' 技巧:
' 如果有必须保留值的寄存器变量, 只要将相应的INreg/OUTreg赋值为 -1,
' 或 NA [= Non-Applicable未使用, 但是要先有 CONST NA = -1 行], 即可.
'
' 出口:
' 若成功:
' 中断号% = 值不变 (0 到 255)
' outreg: 成为调用后寄存器值的保存数组. 其结构同 inreg.
' 若出错:
' 中断号% = -1
' outreg 不变. 不执行中断调用.
' 出错情况:
' 第一个参数值不在 0 到 255 (2^8-1) 范围中
' 第二,三个参数值不在 0 到 1048575 (2^20-1) 范围中
' (VARPTR 的值总是不出这个范围)
'
' 寄存器的变动情况:
' 全部, 除 BP%, DS%, 和 flags (标志寄存器).
' 当然, 也不能避免中断调用本身带来的副作用.
'
' 例外情况:
' 可能出现调用 INT 21H MS-DOS 某些功能时带出的INT 24H 调用.
'自定义变量类型申明
TYPE RegTypeX
ax AS INTEGER
BX AS INTEGER
CX AS INTEGER
DX AS INTEGER
BP AS INTEGER
SI AS INTEGER
DI AS INTEGER
FLAGS AS INTEGER
DS AS INTEGER
ES AS INTEGER
END TYPE
'汇编子程序申明: 注意REM掉的申明与再下一行在数量和类型上的差异.
'实际使用时,应以一段程序内所有调用中最大的参数数量来进行,类型应申明作ANY,
'这样,% & ! # $各种类型的数据都可以作为实参进行调用了.
'但是,调用时若汇编子程序的参数数量不足最大值,一定要注意形参表中虚实参数的
'对应关系和数量差异,具体操作,请注意本程序的做法.
'DECLARE SUB ABSOLUTE (IntNo%, INreg AS RegTypeX, OUTreg AS RegTypeX, OfsAddr%)
'DECLARE SUB ABSOLUTE (P1%, P2%, numberInWord%, nTHbitFlag%, OfsAddr%)
DECLARE SUB ABSOLUTE (P1 AS ANY, P2 AS ANY, P3 AS ANY, P4 AS ANY, OfsAddr%)
DECLARE FUNCTION SADDr% (SSEGm%, s$)
DECLARE SUB InterruptX (IntNo%, InRegs AS ANY, OutRegs AS ANY)
DECLARE SUB Mouse (aax%, bbx%, ccx%, ddx%)
'常量申明
CONST NA = -1
'变量的自定义类型申明
DIM SHARED INreg AS RegTypeX
DIM SHARED OUTreg AS RegTypeX
'汇编子程序的数组定义
ASMnBytes = 260 '汇编子程序的的字节型长度
DIM SHARED intrpt%(INT(ASMnBytes / 2 + .5)) '使它成为字型长度,偶数化字节数量
RESTORE intrptData ' 数据指针指向intrptData汇编程序代码区
'poke 到内存中
DEF SEG = VARSEG(intrpt%(0)) ' 改段址.
intPtr% = VARPTR(intrpt%(0))
FOR i% = 0 TO ASMnBytes - 1
READ vlu$: POKE intPtr% + i%, VAL("&H" + vlu$)
NEXT
DEF SEG
intrptData: '= 260 字节
DATA 55,8B,EC,83,C4,E2,C7,46,FA,0A,00,89,76,E4,89,7E
DATA E2,8C,5E,FC,9C,8F,46,FE,8B,76,08,8D,7E,E6,8B,4E
DATA FA,FC,16,07,F3,A5,55,8B,76,0A,8B,1C,0A,FF,0F,84
DATA 03,00,E9,B9,00,80,FB,25,0F,84,07,00,80,FB,26,0F
DATA 85,0E,00,B8,08,00,50,B8,02,CA,50,B8,83,C4,50,EB
DATA 07,33,C0,50,B8,CA,06,50,8A,E3,B0,CD,50,0E,B8,A5
DATA 00,50,16,8B,C4,05,06,00,50,8B,46,F4,25,D5,0F,50
DATA 8B,46,E6,8B,5E,E8,8B,4E,EA,8B,56,EC,8B,76,F0,8B
DATA 7E,F2,83,7E,FA,08,0F,84,16,00,83,7E,F6,FF,0F,84
DATA 03,00,8E,5E,F6,83,7E,F8,FF,0F,84,03,00,8E,46,F8
DATA 8B,6E,EE,9D,CB,55,8B,EC,8B,6E,02,9C,8F,46,F4,FF
DATA 76,FE,9D,89,46,E6,89,5E,E8,89,4E,EA,89,56,EC,8B
DATA 46,DE,89,46,EE,89,76,F0,89,7E,F2,8C,5E,F6,8C,46
DATA F8,8E,5E,FC,8D,76,E6,1E,07,8B,7E,06,8B,4E,FA,FC
DATA F3,A5,8B,76,E4,8B,7E,E2,8B,E5,5D,CA,06,00,8B,76
DATA 0A,C7,04,FF,FF,8B,76,E4,8B,7E,E2,8E,5E,FC,8B,E5
DATA 5D,CA,06,00
'
IntNo% = &H11 '按位编码的设备信息列表
InterruptX IntNo%, INreg, OUTreg
CLS
LOCATE 18, 1: PRINT "类Interrupt[X]的中断调用"
PRINT "和数量及类型多变情况下的绝对地址调用"
PRINT "在QBASIC环境下的实现"
LOCATE 2, 1: PRINT CHR$(13); DATE$; CHR$(13); TIME$
' OUTreg.AX% 现在存放着由DOS返回的按位编码的设备信息列表.
' 屏蔽掉不相关的位信息只留下与协处理器相关的第二位.
CoProcessor = OUTreg.ax% AND &H2
' 打印相关信息.
PRINT CHR$(13); CHR$(13); "80x87";
IF OUTreg.ax AND 2 = 2 THEN PRINT "已"; ELSE PRINT "未";
PRINT "找到."
msTest:
aax% = 0
Mouse aax%, -1, -1, -1
PRINT CHR$(13); "鼠标";
IF aax% = -1 THEN PRINT "已"; ELSE PRINT "未"; : msFlag% = -1
PRINT "找到----"
IF msFlag% = -1 THEN PRINT "跳过功能测试.": GOTO testBit
Mouse 1, -1, -1, -1
PRINT "鼠标已打开..."
SLEEP 2
Mouse 2, -1, -1, -1
PRINT "鼠标已关闭."
testBit:
ASMnBytes = 45
DIM SHARED tBit%(INT(ASMnBytes / 2 + .5))
DEF SEG = VARSEG(tBit%(0))
RESTORE tBitData
tPtr% = VARPTR(tBit%(0))
FOR i% = 0 TO ASMnBytes - 1
READ vlu$: POKE tPtr% + i%, VAL("&H" + vlu$)
NEXT
DEF SEG
tBitData: '=45 字节
DATA 55,8B,EC,8B,7E,08,8B,1D,8B,7E,06,8B,0D,32,ED,FE
DATA C9,E3,02,D3,C3,33,C0,F7,D3,F7,C3,00,80,74,02,EB
DATA 01,40,8B,7E,06,89,05,8B,E5,5D,CA,04,00
hzData:
DATA &H0004,&H7FFE,&H4444,&H4444,&H4444,&H7FFC,&H4204,&H0200
DATA &H07F0,&H0810,&H1420,&H62C0,&H0100,&H0600,&H1800,&HE000
RESTORE hzData
PRINT CHR$(13); "移位测值显示汉字:"; CHR$(13); " 罗 ="
P1% = -1
P2% = -1
OfsAddr% = VARPTR(tBit%(0))
DEF SEG = VARSEG(tBit%(0))
FOR i% = 1 TO 16
READ v%
FOR j% = 1 TO 16
jj% = j%
'原来 CALL testBitFlag (v%, jj%, OfsAddr%)
CALL ABSOLUTE(P1%, P2%, v%, jj%, OfsAddr%)
IF jj% THEN cc$ = "#" ELSE cc$ = "."
LOCATE i%, j% + 22: PRINT cc$;
NEXT
NEXT
DEF SEG
SLEEP 3
'DECLARE FUNCTION SADDr% (SSEGm%, s$)
s1$ = "这是用来测试SADDr%函数功能的第一个字符串。"
s2$ = "这是第二个字符串。"
CLS
LOCATE 4, 1: PRINT "s1$ = "; s1$
PRINT "s2$ = "; s2$
PRINT
SADDr1% = SADDr%(SSEGm1%, s1$)
PRINT "SSEGm1% ="; SSEGm1%
PRINT "SADDr1% ="; SADDr1%
PRINT
PRINT "44 = 42 + 1 + 1"
PRINT " 42 = s1$字符串的长度,"
PRINT " 1 = QBasic字符串描述符的段地址,"
PRINT " 1 = QBasic字符串描述符的偏移地址."
PRINT
SADDr2% = SADDr%(SSEGm2%, s2$)
PRINT "SSEGm2% ="; SSEGm2%
PRINT "SADDr2% ="; SADDr2%
PRINT
PRINT "SSEGm1% = SSEGm2%,"
PRINT "SADDr1% + 44 = SADDr2%"
SLEEP 4
END
'
'程序二
'
'DATA 55 :'0100 PUSH BP
'DATA 8B,EC :'0101 MOV BP,SP
'DATA 83,C4,E2 :'0103 ADD SP,-1E
'DATA C7,46,FA,0A,00 :'0106 MOV WORD PTR [BP-06],0A
'DATA 89,76,E4 :'010B MOV [BP-1C],SI
'DATA 89,7E,E2 :'010E MOV [BP-1E],DI
'DATA 8C,5E,FC :'0111 MOV [BP-04],DS
'DATA 9C :'0114 PUSHF
'DATA 8F,46,FE :'0115 POP [BP-02]
'DATA 8B,76,08 :'0118 MOV SI,[BP+08]
'DATA 8D,7E,E6 :'011B LEA DI,[BP-1A]
'DATA 8B,4E,FA :'011E MOV CX,[BP-06]
'DATA FC :'0121 CLD
'DATA 16 :'0122 PUSH SS
'DATA 07 :'0123 POP ES
'DATA F3A5 :'0125 REPZ MOVSW
'DATA 55 :'0126 PUSH BP
'DATA 8B,76,0A :'0127 MOV SI,[BP+0A]
'DATA 8B,1C :'012A MOV BX,[SI]
'DATA 0A,FF :'012C OR BH,BH
'DATA 0F,84,03,00 :'012E DB F,84,03,00
'DATA E9,B9,00 :'0132 JMP 01EE
'DATA 80,FB,25 :'0135 CMP BL,25
'DATA 0F,84,07,00 :'0138 DB F,84,07,00
'DATA 80,FB,26 :'013c CMP BL,26
'DATA 0F,85,0E,00 :'013F DB F,85,E,00
'DATA B8,08,00 :'0143 MOV AX,8
'DATA 50 :'0146 PUSH AX
'DATA B8,02,CA :'0147 MOV AX,CA02
'DATA 50 :'014A PUSH AX
'DATA B8,83,C4 :'014B MOV AX,C483
'DATA 50 :'014E PUSH AX
'DATA EB,07 :'014F JMP 0158
'DATA 33,C0 :'0151 XOR AX,AX
'DATA 50 :'0153 PUSH AX
'DATA B8,CA,06 :'0154 MOV AX,06CA
'DATA 50 :'0157 PUSH AX
'DATA 8A,E3 :'0158 MOV AH,BL
'DATA B0,CD :'015A MOV AL,CD
'DATA 50 :'015C PUSH AX
'DATA 0E :'015D PUSH CS
'DATA B8,A5,00 :'015E MOV AX,00A5
'DATA 50 :'0161 PUSH AX
'DATA 16 :'0162 PUSH SS
'DATA 8B,C4 :'0163 MOV AX,SP
'DATA 05,06,00 :'0165 ADD AX,0006
'DATA 50 :'0168 PUSH AX
'DATA 8B,46,F4 :'0169 MOV AX,[BP-0C]
'DATA 25,D5,0F :'016C AND AX,0FD5
'DATA 50 :'016F PUSH AX
'DATA 8B,46,E6 :'0170 MOV AX,[BP-1A]
'DATA 8B,5E,E8 :'0173 MOV BX,[BP-18]
'DATA 8B,4E,EA :'0176 MOV CX,[BP-16]
'DATA 8B,56,EC :'0179 MOV DX,[BP-14]
'DATA 8B,76,F0 :'017C MOV SI,[BP-10]
'DATA 8B,7E,F2 :'017F MOV DI,[BP-0E]
'DATA 83,7E,FA,08 :'0182 CMP WORD PTR [BP-06],08
'DATA 0F,84,16,00 :'0186 DB F,84,16,00
'DATA 83,7E,F6,FF :'018a CMP WORD PTR [BP-0A],FFFF
'DATA 84,03,00 :'018F DB F,84,03,00
'DATA 8E,5E,F6 :'0192 MOV DS,[BP-0A]
'DATA 83,7E,F8,FF :'0195 CMP WORD PTR [BP-08],-01
'DATA 0F,84,03,00 :'0199 DB F,84,03,00
'DATA 8E,46,F8 :'019D MOV ES,[BP-08]
'DATA 8B,6E,EE :'01A0 MOV BP,[BP-12]
'DATA 9D :'01A3 POPF
'DATA CB :'01A4 RETF
'DATA 55 :'01A5 PUSH BP
'DATA 8B,EC :'01A6 MOV BP,SP
'DATA 8B,6E,02 :'01A8 MOV BP,[BP+02]
'DATA 9C :'01AB PUSHF
'DATA 8F,46,F4 :'01AC POP [BP-0C]
'DATA FF,76,FE :'01AF PUSH [BP-02]
'DATA 9D :'01B2 POPF
'DATA 89,46,E6 :'01B3 MOV [BP-1A],AX
'DATA 89,5E,E8 :'01B6 MOV [BP-18],BX
'DATA 89,4E,EA :'01B9 MOV [BP-16],CX
'DATA 89,56,EC :'01BC MOV [BP-14],DX
'DATA 8B,46,DE :'01BF MOV AX,[BP-22]
'DATA 89,46,EE :'01C2 MOV [BP-12],AX
'DATA 89,76,F0 :'01C5 MOV [BP-10],SI
'DATA 89,7E,F2 :'01C8 MOV [BP-0E],DI
'DATA 8C,5E,F6 :'01CB MOV [BP-0A],DS
'DATA 8C,46,F8 :'01CE MOV [BP-08],ES
'DATA 8E,5E,FC :'01D1 MOV DS,[BP-04]
'DATA 8D,76,E6 :'01D4 LEA SI,[BP-1A]
'DATA 1E :'01D7 PUSH DS
'DATA 07 :'01D8 POP ES
'DATA 8B,7E,06 :'01D9 MOV DI,[BP+06]
'DATA 8B,4E,FA :'01DC MOV CX,[BP-06]
'DATA FC :'01DF CLD
'DATA F3,A5 :'01E0 REPZ MOVSW
'DATA 8B,76,E4 :'01E2 MOV SI,[BP-1C]
'DATA 8B,7E,E2 :'01E5 MOV DI,[BP-1E]
'DATA 8B,E5 :'01E8 MOV SP,BP
'DATA 5D :'01EA POP BP
'DATA CA,06,00 :'01EB RETF 0006
'DATA 8B,76,0A :'01EE MOV SI,[BP+0A]
'DATA C7,04,FF,FF :'01F1 MOV WORD PTR [SI],FFFF
'DATA 8B,76,E4 :'01F5 MOV SI,[BP-1C]
'DATA 8B,7E,E2 :'01F8 MOV DI,[BP-1E]
'DATA 8E,5E,FC :'01FB MOV DS,[BP-04]
'DATA 8B,E5 :'01FE MOV SP,BP
'DATA 5D :'0200 POP BP
'DATA CA,06,00 :'0201 RETF 0006
'
'
'程序三
'
'DATA 55 :'0100 PUSH BP
'DATA 8B,EC :'0101 MOV BP,SP
'DATA 8B,7E,08 :'0103 MOV DI,[BP+08]
'DATA 8B,1D :'0106 MOV BX,[DI]
'DATA 8B,7E,06 :'0108 MOV DI,[BP+06]
'DATA 8B,0D :'010B MOV CX,[DI]
'DATA 32,ED :'010D XOR CH,CH
'DATA FE,C9 :'010F DEC CL
'DATA E3,02 :'0111 JCXZ 0115
'DATA D3,C3 :'0113 ROL BX,CL
'DATA 33,C0 :'0115 XOR AX,AX
'DATA F7,D3 :'0117 NOT BX
'DATA F7,C3,00,80 :'0119 TEST BX,8000
'DATA 74,02 :'011D JZ 0121
'DATA EB,01 :'011F JMP 0122
'DATA 40 :'0121 INC AX
'DATA 8B,7E,06 :'0122 MOV DI,[BP+06]
'DATA 89,05 :'0125 MOV [DI],AX
'DATA 8B,E5 :'0127 MOV SP,BP
'DATA 5D :'0129 POP BP
'DATA CA,04,00 :'012A RETF 0004
'
'
'这是对UCDOS特显功能的模拟,需要运行UCDOS及其特显功能模块才能调用!!
SUB ETX (TxCmd$)
INreg.ax = &HE0E: InterruptX &H10, INreg, OUTreg ' CHR$(14)
INreg.ax = &HE5B: InterruptX &H10, INreg, OUTreg ' "["
FOR i = 1 TO LEN(TxCmd$)
INreg.ax = &HE00 + ASC(MID$(TxCmd$, i, 1))
InterruptX &H10, INreg, OUTreg
NEXT
INreg.ax = &HE5D: InterruptX &H10, INreg, OUTreg ' "]"
END SUB
SUB InterruptX (IntNo%, InRegs AS RegTypeX, OutRegs AS RegTypeX)
P1% = -1 ' 未被调用 的参数请赋值为 -1
OfsAddr% = VARPTR(intrpt%(0))
DEF SEG = VARSEG(intrpt%(0))
'CALL Absolute( IntNo%, INreg, OUTreg, OfsAddr%)
'原CALL InterruptX (IntNo%, INreg, OUTreg)
CALL ABSOLUTE(P1%, IntNo%, INreg, OUTreg, OfsAddr%)
DEF SEG
END SUB
SUB Mouse (aax%, bbx%, ccx%, ddx%)
INreg.ax% = aax%
INreg.BX% = bbx%
INreg.CX% = ccx%
INreg.DX% = ddx%
InterruptX &H33, INreg, OUTreg
aax% = OUTreg.ax%
bbx% = OUTreg.BX%
ccx% = OUTreg.CX%
ddx% = OUTreg.DX%
END SUB
FUNCTION SADDr% (SSEGm%, s$)
SSEGm% = CVI(CHR$(PEEK(0)) + CHR$(PEEK(1)))
DEF SEG = VARSEG(s$)
ofs% = VARPTR(s$)
sad% = CVI(CHR$(PEEK(ofs% + 2)) + CHR$(PEEK(ofs% + 3)))
SADDr% = sad%
IF sad% < 0 THEN SADDr% = 32767 + sad%
DEF SEG
END FUNCTION
[ Last edited by 本是 on 2009-7-7 at 04:56 ]
|
my major is english----my love is dos----my teacher is the buddha----my friends--how about U |
|