6 显示窗口(harib19f)
用应用程序显示字符已经玩腻了,这次我们来挑战让应用程序显示窗口吧。这要如何实现呢?我们只要编写一个用来显示窗口的API就可以了,听起来很简单吧。
这个API应该写成什么样呢?考虑了一番之后,我们决定这样设计。
EDX = 5
EBX = 窗口缓冲区
ESI = 窗口在x轴方向上的大小(即窗口宽度)
EDI = 窗口在y轴方向上的大小(即窗口高度)
EAX = 透明色
ECX = 窗口名称
调用后,返回值如下:
EAX =用于操作窗口的句柄(用于刷新窗口等操作)
确定思路之后,新的问题又来了:我们没有考虑如何在调用API之后将值存入寄存器并返回给应用程序。
不过说起来,在asm_hrb_api中我们执行了两次PUSHAD,第一次是为了保存寄存器的值,第二次是为了向hrb_api传递值。因此如果我们查出被传递的变量的地址,在那个地址的后面应该正好存放着相同的寄存器的值。然后只要修改那个值,就可以由POPAD获取修改后的值,实现将值返回给应用程序的功能。
我们来按这种思路编写程序。
本次的console.c节选
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
int ds_base = *((int *) 0xfe8);
struct TASK *task = task_now();
struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);
struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); /*从此开始*/
struct SHEET *sht;
int *reg = &eax + 1; /* eax后面的地址*/
/*强行改写通过PUSHAD保存的值*/
/* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */
/* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ /*到此结束*/
if (edx == 1) {
cons_putchar(cons, eax & 0xff, 1);
} else if (edx == 2) {
cons_putstr0(cons, (char *) ebx + ds_base);
} else if (edx == 3) {
cons_putstr1(cons, (char *) ebx + ds_base, ecx);
} else if (edx == 4) {
return &(task->tss.esp0);
} else if (edx == 5) { /*从此开始*/
sht = sheet_alloc(shtctl);
sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax);
make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0);
sheet_slide(sht, 100, 50);
sheet_updown(sht, 3); /*背景层高度3位于task_a之上*/
reg[7] = (int) sht; /*到此结束*/
}
return 0;
}
shtctl的值是bootpack.c的HariMain中的变量,因此我们可以从0x0fe4地址获得。reg就是我们为了向应用程序返回值所动的手脚。
窗口我们就暂且显示在(100, 50)这个位置上,背景层高度3。
bootpack.c中也添加了1行。
本次的bootpack.c节选
void HariMain(void)
{
(中略)
*((int *) 0x0fe4) = (int) shtctl;
(中略)
}
■■■■■
我们编写这样一个应用程序来测试。
本次的a_nask.nas节选
_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
PUSH EDI
PUSH ESI
PUSH EBX
MOV EDX,5
MOV EBX,[ESP+16] ; buf
MOV ESI,[ESP+20] ; xsiz
MOV EDI,[ESP+24] ; ysiz
MOV EAX,[ESP+28] ; col_inv
MOV ECX,[ESP+32] ; title
INT 0x40
POP EBX
POP ESI
POP EDI
RET
本次的winhelo.c
int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_end(void);
char buf[150 * 50];
void HariMain(void)
{
int win;
win = api_openwin(buf, 150, 50, -1, "hello");
api_end();
}
这些程序应该不用解释了吧?
■■■■■
我们来“make run”,好,快出现吧,窗口!……出来了!
显示出来了哦!