27.1 应用程序运行时关闭命令行窗口
需要实现的功能: 在应用程序运行的时候,可以关闭所对应的命令行窗口。思路:1.先调整bootpack.c中按下"x"按钮时,暂时将窗口隐藏起来,并当fifo接收从console.c发送的关闭窗口请求数据时释放指定的图层。2.由于cons.sht在命令行关闭后会置0,所以将console_task函数中的变量sheet 部分改用变量 cons.sht代替。3.如果FIFO中接收到4这个数据,则表示收到了关闭命令行窗
口的信号,此时取消定时器,并发出清理图层的消息,然后将 cons->sht 置为 0。
/* bootpack.c */
if(sht->bxsize-21 <= x && x < sht->bxsize-5 && 5<= y && y < 19){//点击"x"关闭窗口if((sht->flags & 0x10) != 0){/*该窗口不是应用程序窗口*/task = sht->task;cons_putstr0(task->cons, "\nBreak(mouse) :\n");io_cli();task->tss.eax = (int)&(task->tss.esp0);task->tss.eip = (int) asm_end_app;io_sti();}else{//是命令行窗口task = sht->task;sheet_updown(sht, -1);/*从这里开始*/keywin_off(key_win);key_win = shtctl->sheets[shtctl->top - 1];keywin_on(key_win);/*到这里结束*/io_cli();fifo32_put(&task->fifo, 4);io_sti();}task_run(task, -1, 0);/*为了确实执行结束处理,如果处于休眠状态则唤醒*/
}
(中略)
}else if(2024 <= i && i <= 2279){/*只关闭命令行窗口*/sht2 = shtctl->sheets0+(i-2024);memman_free_4k(memman, (int)sht2->buf, 256*165);sheet_free(sht2);
}/* console.c */
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{(中略)struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec); /*这里!*/(中略)} else if (edx == 15) {for (;;) {(中略)if (i == 4) { /*只关闭命令行窗口*/ /*从此开始*/timer_cancel(cons->timer);io_cli();fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /*2024~2279*/cons->sht = 0;io_sti();} /*到此结束*/(中略)}} else if (edx == 16) {(中略)
}
27.2 保护应用程序
GDT 中的段设置是供所有任务通用的,而LDT中的段设置则只对某个应用程序有效。如果将应用程序段设置在LDT中,其他的任务由于无法使用该LDT,也就不用担心它们来搞破坏了。
/* bootpack.h */
(中略)
#define AR_CODE32_ER 0x409a
#define AR_LDT 0x0082 /*这里!*/
#define AR_TSS32 0x0089
#define AR_INTGATE32 0x008e
/* mtask.c */
(中略)
struct TASK {int sel, flags; /* sel代表GDT编号*/int level, priority;struct FIFO32 fifo;struct TSS32 tss;struct SEGMENT_DESCRIPTOR ldt[2]; /*这里!*/struct CONSOLE *cons;int ds_base, cons_stack;
};
/* mtask.c */
struct TASK *task_init(struct MEMMAN *memman){(中略)for (i = 0; i < MAX_TASKS; i++) {taskctl->tasks0[i].flags = 0;taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;taskctl->tasks0[i].tss.ldtr = (TASK_GDT0 + MAX_TASKS + i) * 8; /*这里!*/set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);set_segmdesc(gdt + TASK_GDT0 + MAX_TASKS + i, 15, (int) taskctl->tasks0[i].ldt, AR_LDT);/*这里!*/}(中略)
}struct TASK *task_alloc(void){(中略)for (i = 0; i < MAX_TASKS; i++) {if (taskctl->tasks0[i].flags == 0) {(中略)task->tss.fs = 0;task->tss.gs = 0;/*删掉原来的task->tss.ldtr = 0;*/task->tss.iomap = 0x40000000;task->tss.ss0 = 0;return task;}}return 0; /*已经全部正在使用*/
}int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline){(中略)if (finfo !=s 0) {/*找到文件的情况*/(中略)if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) {(中略)set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); /*这里!*/set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); /*这里!*/for (i = 0; i < datsiz; i++) {q[esp + i] = p[dathrb + i];}start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0)); /*这里!*/(中略)} else {cons_putstr0(cons, ".hrb file format error.\n");}(中略)}(中略)
}
27.3 优化应用程序的大小
思路:举例, 主要是因为创建 hello3.hrb 时所引用的 a_nask.nas变大了,包含了像 _api_openwin 和_api_linewin这些在这个应用程序中根本用不到的函数,所以将a_nask.nas中的函数都拆开,形成api001.nas~api020.nas。随后将Makefile文件中的a_nask.nas全部按照下述进行更换。
OBJS_API = api001.obj api002.obj (中略) api019.obj api020.obja.bim : a.obj $(OBJS_API) Makefile$(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj $(OBJS_API)
27.4 库
思路: 将很多个 .obj文件打包成一个文件。在 Makefile 中加上下面的代码:
GOLIB = $(TOOLPATH)golib00.exe
apilib.lib : Makefile $(OBJS_API)
$(GOLIB) $(OBJS_API) out:apilib.lib
顺便写一个apilib.h文件,就可以在应用程序开头的 API函数声明:#include "apilib.h" 。
/* apilib.h */
void api_putchar(int c);
void api_putstr0(char *s);
void api_putstr1(char *s, int l);
void api_end(void);
int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_putstrwin(int win, int x, int y, int col, int len, char *str);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
void api_free(char *addr, int size);
void api_point(int win, int x, int y, int col);
void api_refreshwin(int win, int x0, int y0, int x1, int y1);
void api_linewin(int win, int x0, int y0, int x1, int y1, int col);
void api_closewin(int win);
int api_getkey(int mode);
int api_alloctimer(void);
void api_inittimer(int timer, int data);
void api_settimer(int timer, int time);
void api_freetimer(int timer);
void api_beep(int tone);