匿名管道与重定向技术
正文
首先我们得理解一个定义:重定向
何谓重定向?可以先字面理解为:重新决定方向!在控制台程序中,将标准的输入、输出句柄用管道的读、写句柄替换,而控制台程序本身并不知道它的输入、输出句柄已发生了变化,它依然将相关句柄(实为管道的读写句柄)作为标准的输入、输出句柄来看待。当父进程和子进程进行数据通信时的情形是这样的:父进程将标准的输出端重定向匿名管道的写句柄,启动子进程,因为继承关系,子进程也具有了这一特点,它的标准输出也与管道的写句柄联系在一起了。此时的父进程在关闭管道写句柄之后(一定要关闭),就可以通过读句柄来取得子进程发出的数据了。
为了说明这个实事,我小举一例子,说明如何在图形界面中调用控制台的标准输出。程序运行的结果如下图:
程序按如下步骤实现:
1、新建一对话框CMyGUIDlg, 再加入一编辑框,设置好编辑框的属性(多行,水平&&垂直滚动条,自滚动,want return)ID号为:IDC_EDIT1
在ClassWizard中为IDC_EDIT1加入一CEdit型变量。
CEdit m_edit1;
2、加入一工作线程,函数可以为全局,当然也可以作为static型的类成员。我们选择后者。
static UINT TestThread(LPVOID p);
3、在OnOK()消息处理函数中,加入如下代码:
void CMyGUIDlg::OnOK()
{
AfxBeginThread(TestThread, this);
UpdateData(TRUE);
}
4、在线程函数我们加入如下代码:
UINT CMyDUIDlg::TestThread(LPVOID p)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
// 管道读句柄
HANDLE hRead;
// 管道写句柄
HANDLE hWrite;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.lpSecurityDescriptor = 0;
saAttr.bInheritHandle = true;
// 创建匿名管道
if(!CreatePipe(&hRead, &hWrite, &saAttr, 0))
{
AfxMessageBox("创建管道失败!");
return 0;
}
// 得到本进程的当前标准输出
// HANDLE hTemp = GetStdHandle(STD_OUTPUT_HANDLE);
// 设置标准输出到匿名管道
// SetStdHandle(STD_OUTPUT_HANDLE, hWrite);
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si); // 获取本进程的STARTUPINFO结构信息
si.hStdError = hWrite;
si.hStdOutput = hWrite;
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; // 让子进程隐藏、标准输出生效
CString strLine;
strLine.Format("cl -h %d /?", (unsigned int)hWrite); // 命令行参数
// 创建子进程
if (!CreateProcess(NULL, (LPSTR)(LPCTSTR)strLine, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
{
AfxMessageBox("创建子进程失败!");
return 0;
}
// 恢复本进程的标准输出
// SetStdHandle(STD_OUTPUT_HANDLE, hTemp);
CloseHandle(hWrite); // 关闭写句柄(一定要关闭)
CString strOut;
char ReadBuf[100] = {0};
DWORD dwRead;
// 读管道直至管道关闭
while (ReadFile(hRead, ReadBuf,99, &dwRead, NULL))
{
strOut += ReadBuf;
memset(ReadBuf, 0, 99);
}
CMyDUIDlg* plg = (CMyDUIDlg*)p;
plg->m_edit1.SetWindowText(strOut);
plg->InvalidateRect(NULL);
CloseHandle(hRead);
return 0;
}
作如下说明:
1、本程序调用的控制台输出是VC++中的cl.exe运行的结果。当然你也可以自己加入一些控制台的 测试程序,将strLine赋值你想测试的控制台程序名即可。
2、此程序在XP+VC6中测试通过。