编写自己的IDE:如何在图形界面中实时捕获控制台程序的标准输出
2008-01-19 20:24:39 来源:WEB开发网核心提示:我写的中介程序名字叫wSpawn,这个名字来自Visual Studio里完成类似功能的中介程序VcSpawn(你可以在Visual Studio的安装目录中找到它),编写自己的IDE:如何在图形界面中实时捕获控制台程序的标准输出(3),我的wSpawn非常简单,它利用系统调用_popen()同时完成创建子进程和输入输
我写的中介程序名字叫wSpawn,这个名字来自Visual Studio里完成类似功能的中介程序VcSpawn(你可以在Visual Studio的安装目录中找到它)。我的wSpawn非常简单,它利用系统调用_popen()同时完成创建子进程和输入输出重定向两件工作。GUI程序则使用一种特殊的命令行方式调用wSpawn:
wspawn –h <n> <command> [arg1] [arg2] ...
其中,-h后跟的是GUI程序提供的管道句柄,由GUI程序自动将其转换为十进制数字,wSpawn运行时将信息写入该句柄中,随后的内容是GUI程序真正要执行的命令行,例如调用C++编译器cl.exe的方式大致如下:
wspawn –h 1903 cl /Id:\myInclude Test.cpp
wspawn.cpp的程序清单如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <windows.h>
using namespace std;
void exit_friendly(void)
{
puts("请不要单独运行wSpawn.");
exit(0);
}
int main( int argc, char *argv[] )
{
HANDLE hWrite = NULL;
DWORD dwWrited;
int i = 0, ret = 0, len = 0;
char psBuffer[256];
FILE* child_output;
string command_line = "";
// 检查命令行,如存在管道句柄,则将其转换为HANDLE类型
if (argc < 2)
exit_friendly();
if (!stricmp(argv[1], "-h"))
{
if (argc < 4)
exit_friendly();
hWrite = (HANDLE)atoi(argv[2]);
i = 3;
}
else
i = 1;
// 提取要执行的命令
for (; i < argc; i++)
{
command_line += argv[i];
command_line += " ";
}
// 使用_popen创建子进程并重定向其标准输出到文件指针中
if( (child_output = _popen( command_line.c_str(), "rt" )) == NULL )
exit( 1 );
while( !feof( child_output ) )
{
if( fgets( psBuffer, 255, child_output ) != NULL )
{
if (hWrite)
{
// 将子进程的标准输出写入管道,提供给自己的父进程
// 格式是先写数据块长度(0表示结束),再写数据块内容
len = strlen(psBuffer);
WriteFile(hWrite, &len, sizeof(int), &dwWrited, NULL);
WriteFile(hWrite, psBuffer, len, &dwWrited, NULL);
}
else
// 如命令行未提供管道句柄,则直接打印输出
printf(psBuffer);
}
}
// 写“0”表示所有数据都已写完
len = 0;
if (hWrite)
WriteFile(hWrite, &len, sizeof(int), &dwWrited, NULL);
return _pclose( child_output );
}
下面,我们就利用wSpawn程序,写一个简单的“IDE”工具。我们选择Visual Studio 6.0作为开发环境(本文给出的代码也在Visual Studio.NET 7.0中做过测试)。首先,创建Visual C++工程myIDE,工程类型为MFC AppWizard(EXE)中的Dialog based类型,即创建了一个主窗口为对话框的GUI程序。工程myIDE的主对话框类是CMyIDEDlg。现在我们要在资源编辑器中为主对话框添加一个足够大的多行编辑框(Edit Box),它的控制ID是IDC_EDIT1,必须为IDC_EDIT1设置以下属性:
[]
赞助商链接