匿名管道與重定向技術
正文
首先我們得了解一個定義:重定向
何謂重定向?可以先字面了解為:重新決定方向!在控制台程式中,将标準的輸入、輸出句柄用管道的讀、寫句柄替換,而控制台程式本身并不知道它的輸入、輸出句柄已發生了變化,它依然将相關句柄(實為管道的讀寫句柄)作為标準的輸入、輸出句柄來看待。當父程序和子程序進行資料通信時的情形是這樣的:父程序将标準的輸出端重定向匿名管道的寫句柄,啟動子程序,因為繼承關系,子程序也具有了這一特點,它的标準輸出也與管道的寫句柄聯系在一起了。此時的父程序在關閉管道寫句柄之後(一定要關閉),就可以通過讀句柄來取得子程序發出的資料了。
為了說明這個實事,我小舉一例子,說明如何在圖形界面中調用控制台的标準輸出。程式運作的結果如下圖:
程式按如下步驟實作:
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中測試通過。