6 增加命令行窗口(2)(harib22f)
到底应该改哪里呢?其实笔者已经心里有数了,函数hrb_api()中的这句:
struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);
应该就是问题所在了,这里的cons变量是用来判断“要向哪个命令行窗口输出字符”的关键。该变量的值是从内存地址0x0fec读取出来的,而无论从哪个任务读取这个内存地址中的值,得到的肯定都是同一个值,因此不管在哪个窗口中运行a.hrb,都只能在固定的其中一个窗口中显示字符。
harib22e中,无论在哪个窗口运行,结果都一样
那么该如何解决这个问题呢?嗯,看看这种方法怎么样。
本次的bootpack.h节选
struct TASK {
int sel, flags; /* sel代表GDT编号*/
int level, priority;
struct FIFO32 fifo;
struct TSS32 tss;
struct CONSOLE *cons; /*从此开始*/
int ds_base; /*到此结束*/
};
每个任务都拥有各自的TASK结构,只要我们将cons保存在TASK结构中,就可以由不同的任务读取出不同的值了。此外,我们将ds_base也放到了TASK结构中,理由和上面的cons是相同的。ds_base之前是从内存地址0x0fe8处读取的,但很明显,cons[0]的应用程序数据段地址和cons[1]的地址肯定是不同的,如果不在这里区分开的话,字符串的显示就会出问题。
■■■■■
接下来我们只要将代码中的((int ) 0x0fec)和((int ) 0x0fe8)全部改为使用TASK结构中的cons和ds_base成员就可以了,需要修改的只有console.c一个文件。
本次的console.c节选
void console_task(struct SHEET *sheet, int memtotal)
{
(中略)
task->cons = &cons; /*修改前:*((int *) 0x0fec) = (int) &cons;*/
(中略)
}
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{
(中略)
if (finfo != 0) {
(中略)
if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) {
(中略)
task->ds_base = (int) q; /*修改前:*((int *) 0x0fe8) = (int) &q;*/
} else {
(中略)
}
(中略)
}
(中略)
}
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
(中略)
int ds_base = task->ds_base; /*这里!*/
struct CONSOLE *cons = task->cons; /*这里!*/
(中略)
}
int *inthandler0c(int *esp)
{
(中略)
struct CONSOLE *cons = task->cons; /*这里!*/
(中略)
}
int *inthandler0d(int *esp)
{
(中略)
struct CONSOLE *cons = task->cons; /*这里!*/
(中略)
}
好,完工啦。现在无论在哪个窗口运行a.hrb,应该会在相应的窗口中显示出字符……了吧……
■■■■■
我们来试验一下吧。“make run”,在两边的窗口分别运行a.hrb!哦哦,成功了,太棒了!(要是这样还不行的话,笔者真的不知道该怎么办了,小捏了一把汗)
a.hrb运行成功!
趁热打铁,我们来运行color.hrb和color2.hrb试试看。哇!成功了!现在我们可以把两个窗口并排对比了,终于实现了当初的夙愿。
color.hrb vs color2.hrb
接下来我们来做点别的试验吧,比如说把color.hrb和color2.hrb的窗口关闭(注:Shift+F1和“×”按钮点击的处理我们还没有改好,记得按回车键退出程序哦)……咦?哐叽,QEMU出错退出了1!
1 这是由于color.hrb和color2.hrb的启动顺序、各从哪个命令行窗口运行的、以及先关闭的哪一个窗口等不同情况导致的,出错的方式貌似也不一样。应用程序没有bug,也没有故意捣乱,这是由于“纸娃娃系统”本身所引发的异常。
因此,在两个color程序PK之后,我们的下一个目标就是要使窗口能够正常关闭。