中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » TC编译的EXE文件,获取当前屏幕显示信息失败
作者:
标题: TC编译的EXE文件,获取当前屏幕显示信息失败 上一主题 | 下一主题
pigglu
新手上路





积分 12
发帖 5
注册 2007-4-30
状态 离线
『楼 主』:  TC编译的EXE文件,获取当前屏幕显示信息失败 [已使用 LLM 解释]

用TC编译生成一个EXE文件(子程序),用于其它程序(主程序)调用,EXE子程序运行时需要先保存主程序原有界面,调用完成后进行界面恢复。
目前实现了:
1、单独一个程序显示图片,将屏幕保存到文件,再通过读文件恢复屏幕;
2、主程序显示图片,主程序将屏幕保存到文件,主程序调用EXE子程序,子程序读文件将屏幕恢复;
需要实现的真正功能:主程序显示图片,主程序调用EXE子程序,子程序将主程序界面保存到文件,调用结束时从文件恢复屏幕显示。
尝试了多次,子程序一运行就进行屏幕保存,但都没有办法成功保存主程序界面。
非常着急,还请高手指教,谢谢。
LLM 解释

问题结论

子程序无法保存主程序界面的核心原因是 system() 调用会导致主程序的图形模式被切换为 DOS 文本模式,子程序执行时已无法访问主程序的图形显存内容。

技术原理与错误分析

  1. system() 函数的执行机制
    DOS 下 system() 函数通过调用 COMMAND.COM 执行外部程序,其过程会:

    • 暂停当前程序(主程序)的执行;
    • 将当前程序的 CPU 上下文(寄存器、堆栈)、内存空间保存到内存;
    • 切换到 DOS 文本模式(80×25 字符,显存地址 0xB8000000);
    • 加载并运行外部程序(子程序);
    • 子程序退出后,恢复主程序的上下文,但不会自动恢复图形模式

    因此,子程序执行时,屏幕已处于文本模式,0xA0000000 显存区域无有效图形数据(通常填充 0xFF 或随机值),导致保存失败。

  2. 显存访问的模式依赖性
    主程序使用 initgraph() 初始化图形模式(如 VGA 256 色 0xA0000000 显存),而子程序执行时处于文本模式,0xA0000000 并非当前有效显存地址。即使子程序尝试访问该地址,读取的也是无意义数据。

  3. 代码中的次要错误
    子程序 Get256Blk() 函数存在显存地址计算错误:

    // 错误:显存偏移量应为 j*MAXX + i(假设 MAXX=640),而非 j*(ey-sy)+i
    *(p+(j*(ey-sy)+i))
    

    该错误会导致保存的图像数据错位,但这并非主问题——即使计算正确,子程序执行时图形模式已丢失,仍无法获取有效数据。

解决方案

需避免使用 system() 调用,改用直接加载并运行子程序的方式(保留主程序的图形模式),具体步骤:

  1. 子程序编译为 .COM 文件(简化内存加载,避免 COMMAND.COM 介入);

  2. 主程序通过 exec() 系列函数(如 execvp()spawnlp())加载子程序,指定 P_WAIT 模式(等待子程序执行完毕);

  3. 子程序执行时,直接访问 0xA0000000 显存(主程序的图形模式未被切换),保存主程序界面。

    示例(主程序中替换 system() 调用):

    #include <process.h>  // 需包含 TC 的 process.h 头文件
    
    // 用 spawnlp 直接加载子程序,保留图形模式
    spawnlp(P_WAIT, "S_new.com", "S_new.com", NULL);
    

历史误解补充

当年开发者常误以为 system() 仅暂停程序执行,忽略了其对显示模式的强制切换,这源于 DOS 单任务环境下“程序切换需重置环境”的设计约束。070 提到的“切换到 DOS”是正确的,但未明确 system() 是导致模式切换的直接原因。

额外注意事项

  • 子程序需避免调用 clrscr()gotoxy() 等文本模式函数,防止破坏主程序的图形显存;
  • 若子程序需输出信息,应直接操作图形模式的显存(如用 outtextxy()),而非文本模式函数。


2010-4-10 18:44
查看资料  发短消息  网志   编辑帖子  回复  引用回复
070
高级用户

苏醒的沉睡者


积分 659
发帖 217
注册 2003-2-15
来自 福建
状态 离线
『第 2 楼』:   使用 LLM 解释/回答一下

目前你的程序保存的屏幕信息是什么样子的,是全屏幕没有内容吗,

有可能主程序在调用外界exe的时候,先切换到 dos,然后再运行exe

个人猜测,估计是错的:)




好久没碰Dos,手都生了,赶紧回来练练.嘿嘿
2010-4-10 21:18
查看资料  发送邮件  发短消息  网志  OICQ (181315400)  编辑帖子  回复  引用回复
pigglu
新手上路





积分 12
发帖 5
注册 2007-4-30
状态 离线
『第 3 楼』:   使用 LLM 解释/回答一下

Originally posted by 070 at 2010-4-10 09:18 PM:
目前你的程序保存的屏幕信息是什么样子的,是全屏幕没有内容吗,

有可能主程序在调用外界exe的时候,先切换到 dos,然后再运行exe

个人猜测,估计是错的:)


子程序(S_new.exe)代码如下:
BYTE far *p;
#define MAXX 640
#define MAXY 480

int Get256Blk(int sx,int sy,int ex,int ey, const char *filename);
int Set256Blk(int sx,int sy,int ex,int ey, const char *filename);
void InitGraph();
void CloseGraph();
void Exit(char *ErrorCode);

int main( int argc, char *argv)
{
int row, line;

Get256Blk(0, 0, MAXX-1, MAXY-1, "DISP");

row =3;
line = 2;
clrscr();
gotoxy(row, line++);
cprintf("Begin...\n");

getch();

InitGraph();
Set256Blk(0, 0, MAXX-1, MAXY-1, "DISP");
getch();

return 0;
}

/***************************************************************
函数名称:Get256Blk(int sx,int sy,int ex,int ey,const char *filename)
函数功能:保存指定矩形区域的屏幕显示信息到文件
***************************************************************/
int Get256Blk(int sx,int sy,int ex,int ey, const char *filename)
{
int j, i;
FILE *fp;

p=(BYTE far*)0xa0000000L;

fp = fopen(filename, "w+");
for(j=sy;j<=ey;j++)
{
for(i=0;i<ex-sx;i++)
{
fputc(*(p+(j*(ey-sy)+i)), fp);
}
}
fclose(fp);
return 0;
}

/***************************************************************
函数名称:Set256Blk(int sx,int sy,int ex,int ey,const char *filename)
函数功能:从文件恢复指定矩形区域的屏幕显示信息
***************************************************************/
int Set256Blk(int sx,int sy,int ex,int ey, const char *filename)
{
int i, j;
FILE *fp;

p=(BYTE far*)0xa0000000L;

fp = fopen(filename, "rb+");
if (fp == NULL)
{
Exit("Can Not Open The File.\n");
return 1;
}
for(j=sy;j<=ey;j++)
{
for(i=0;i<ex-sx;i++)
{
*(p+(j*(ey-sy)+i))=fgetc(fp);
}
}
fclose(fp);
return 0;
}

void InitGraph()
{
int mod;
int dr;
detectgraph(&mod, &dr);
initgraph(&mod,&dr,"");
}

void CloseGraph()
{
closegraph();
}

void Exit(char *ErrorCode)
{
printf("%s",ErrorCode);
getch();
exit(0);
}


主程序代码如下:
void main()
{
InitGraph();

/* 在屏幕上显示BMP图片*/
......

getch();

/* 非调用方式,主程序独立实现存屏幕及恢复 */
/*
Get256Blk(0, 0, MAXX-1, MAXY-1, "DISP");
getch();
clrscr();
Set256Blk(0, 0, MAXX-1, MAXY-1, "DISP");
getch();
*/

/* 调用方式,主程序调用子程序实现存屏幕及恢复 */
system("S_new.exe");

CloseGraph();
}

主程序同样生成一个EXE文件,可直接运行。

“有可能主程序在调用外界exe的时候,先切换到 dos,然后再运行exe”,这个有点不太明白,是不是就是这的原因,应该怎么解决,先谢谢前辈们了~~


2010-4-11 03:55
查看资料  发短消息  网志   编辑帖子  回复  引用回复
pigglu
新手上路





积分 12
发帖 5
注册 2007-4-30
状态 离线
『第 4 楼』:   使用 LLM 解释/回答一下

补充下,现在保存下的屏幕信息里面全是0xff。


2010-4-11 03:58
查看资料  发短消息  网志   编辑帖子  回复  引用回复
070
高级用户

苏醒的沉睡者


积分 659
发帖 217
注册 2003-2-15
来自 福建
状态 离线
『第 5 楼』:   使用 LLM 解释/回答一下

我的意思是,切换到另一个程序的过程中,把显示模式也给切换了,由图形模式变成了文本模式,然后再接着运行那个子程序。。各人估计,我对dos下程序执行外部程序的流程也不大了解。


你那个备选的过程是不是可以正常运行,也就是不调用外界子程序而自己保存图像的?




好久没碰Dos,手都生了,赶紧回来练练.嘿嘿
2010-4-11 08:38
查看资料  发送邮件  发短消息  网志  OICQ (181315400)  编辑帖子  回复  引用回复
pigglu
新手上路





积分 12
发帖 5
注册 2007-4-30
状态 离线
『第 6 楼』:  就是外调程序失败 使用 LLM 解释/回答一下

Originally posted by 070 at 2010-4-11 08:38 AM:
我的意思是,切换到另一个程序的过程中,把显示模式也给切换了,由图形模式变成了文本模式,然后再接着运行那个子程序。。各人估计,我对dos下 ...


不外调程序,模拟的主程序是可以自己保存屏幕的,虽然保持的图像有点变形,但也还是有保持下东西的,如果使用子程序,保存下的就是全oxff。
在主程序进行子程序调用的时候没有操作显示模式,同样子程序运行的时候也没有操作,调用使用的是system函数,难道和这个函数有关系??
好郁闷啊:(


2010-4-11 10:09
查看资料  发短消息  网志   编辑帖子  回复  引用回复
070
高级用户

苏醒的沉睡者


积分 659
发帖 217
注册 2003-2-15
来自 福建
状态 离线
『第 7 楼』:   使用 LLM 解释/回答一下

恩,可能是跟system函数有关。。
这个函数过程到底是怎么个机理,我也不知道。




好久没碰Dos,手都生了,赶紧回来练练.嘿嘿
2010-4-11 10:50
查看资料  发送邮件  发短消息  网志  OICQ (181315400)  编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: