mov dx,resend ;Set Data Offset to Resend
sub dx,resstart ;Subtract Resstart
shr dx,4h ;Shift Right 4 Bits for Paragraph
inc dx ;One Extra Paragraph for PSP
在此 .COM 程序中,您将正确保存并设置中断向量。但是,您没有准确计算 DOS.TerminateAnd StayResident 函数要保留的段落数量。
The inc dx
需要向上舍入到最接近的段落。当然不是为了占PSP。由于 PSP 有 256 字节,因此需要 16 个段落。
分配给该 .COM 程序的内存从 PSP 开始,因此DX
计数也必须从那里开始。
mov dx, resend
shr dx, 4
inc dx
mov ax, 3100h ; DOS.TerminateAndStayResident
int 21h
Tip如果你对齐这个resend段落边界的标签,inc dx
不再需要。
如果您当前的代码在像 virtualbox 这样的模拟器中部分工作,那是因为您的程序以前占用的内存尚未被例如程序覆盖。程序外壳。与 DOS 不同,仿真器可以远程执行命令解释器。
尽管系统挂起,但使用 virtualbox 屏幕确实充满了蓝色
如果有人在我写东西的时候关掉灯,我也会挂掉!这就是你的处理程序在突然改变视频模式时所做的事情......
对于TSR程序,我们通常会跳过需要常驻的部分,这样一次性设置占用的空间就可以被系统回收。
您可以使用的另一个技巧是将旧中断向量的偏移量和段直接写入将恢复向量的指令中。处理程序中的段寄存器不再有问题。
这是我对你的程序的重写:
org 100h
Start:
jmp Setup
MyInt28:
push ax
push es
push di
push cx
push ds
push dx
mov ax, 0013h ; BIOS.SetVideoMode
int 10h
mov ax, 0A000h
mov es, ax
xor di, di
mov cx, 64000/2
mov ax, 0909h
cld
rep stosw
PatchA:
mov ax, 0 ; Don't change this to 'xor ax,ax'
mov ds, ax
PatchB:
mov dx, 0 ; Don't change this to 'xor dx,dx'
mov ax, 2528h ; DOS.SetInterruptVector
int 21h
pop dx
pop ds
pop cx
pop di
pop es
pop ax
iret
Setup: ; Resident part ends here.
mov ax, 3528h ; DOS.GetInterruptVector
int 21h ; -> ES:BX
mov [PatchA + 1], es
mov [PatchB + 1], bx
mov dx, MyInt28
mov ah, 25h ; DOS.SetInterruptVector
int 21h
mov dx, (256+Setup-Start+15)/16
mov ax, 3100h ; DOS.TerminateAndStayResident
int 21h