6 显示窗口(harib19f)

用应用程序显示字符已经玩腻了,这次我们来挑战让应用程序显示窗口吧。这要如何实现呢?我们只要编写一个用来显示窗口的API就可以了,听起来很简单吧。

这个API应该写成什么样呢?考虑了一番之后,我们决定这样设计。

EDX = 5

EBX = 窗口缓冲区

ESI = 窗口在x轴方向上的大小(即窗口宽度)

EDI = 窗口在y轴方向上的大小(即窗口高度)

EAX = 透明色

ECX = 窗口名称

调用后,返回值如下:

EAX =用于操作窗口的句柄(用于刷新窗口等操作)

确定思路之后,新的问题又来了:我们没有考虑如何在调用API之后将值存入寄存器并返回给应用程序。

不过说起来,在asm_hrb_api中我们执行了两次PUSHAD,第一次是为了保存寄存器的值,第二次是为了向hrb_api传递值。因此如果我们查出被传递的变量的地址,在那个地址的后面应该正好存放着相同的寄存器的值。然后只要修改那个值,就可以由POPAD获取修改后的值,实现将值返回给应用程序的功能。

我们来按这种思路编写程序。

本次的console.c节选

  1. int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
  2. {
  3. int ds_base = *((int *) 0xfe8);
  4. struct TASK *task = task_now();
  5. struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);
  6. struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); /*从此开始*/
  7. struct SHEET *sht;
  8. int *reg = &eax + 1; /* eax后面的地址*/
  9. /*强行改写通过PUSHAD保存的值*/
  10. /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */
  11. /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ /*到此结束*/
  12. if (edx == 1) {
  13. cons_putchar(cons, eax & 0xff, 1);
  14. } else if (edx == 2) {
  15. cons_putstr0(cons, (char *) ebx + ds_base);
  16. } else if (edx == 3) {
  17. cons_putstr1(cons, (char *) ebx + ds_base, ecx);
  18. } else if (edx == 4) {
  19. return &(task->tss.esp0);
  20. } else if (edx == 5) { /*从此开始*/
  21. sht = sheet_alloc(shtctl);
  22. sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax);
  23. make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0);
  24. sheet_slide(sht, 100, 50);
  25. sheet_updown(sht, 3); /*背景层高度3位于task_a之上*/
  26. reg[7] = (int) sht; /*到此结束*/
  27. }
  28. return 0;
  29. }

shtctl的值是bootpack.c的HariMain中的变量,因此我们可以从0x0fe4地址获得。reg就是我们为了向应用程序返回值所动的手脚。

窗口我们就暂且显示在(100, 50)这个位置上,背景层高度3。

bootpack.c中也添加了1行。

本次的bootpack.c节选

  1. void HariMain(void)
  2. {
  3. (中略)
  4. *((int *) 0x0fe4) = (int) shtctl;
  5. (中略)
  6. }

■■■■■

我们编写这样一个应用程序来测试。

本次的a_nask.nas节选

  1. _api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
  2. PUSH EDI
  3. PUSH ESI
  4. PUSH EBX
  5. MOV EDX,5
  6. MOV EBX,[ESP+16] ; buf
  7. MOV ESI,[ESP+20] ; xsiz
  8. MOV EDI,[ESP+24] ; ysiz
  9. MOV EAX,[ESP+28] ; col_inv
  10. MOV ECX,[ESP+32] ; title
  11. INT 0x40
  12. POP EBX
  13. POP ESI
  14. POP EDI
  15. RET

本次的winhelo.c

  1. int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
  2. void api_end(void);
  3. char buf[150 * 50];
  4. void HariMain(void)
  5. {
  6. int win;
  7. win = api_openwin(buf, 150, 50, -1, "hello");
  8. api_end();
  9. }

这些程序应该不用解释了吧?

■■■■■

我们来“make run”,好,快出现吧,窗口!……出来了!

6 显示窗口(harib19f) - 图1

显示出来了哦!