天天看點

從匿名管道談重定向技術

                                 匿名管道與重定向技術

 正文

    首先我們得了解一個定義:重定向

何謂重定向?可以先字面了解為:重新決定方向!在控制台程式中,将标準的輸入、輸出句柄用管道的讀、寫句柄替換,而控制台程式本身并不知道它的輸入、輸出句柄已發生了變化,它依然将相關句柄(實為管道的讀寫句柄)作為标準的輸入、輸出句柄來看待。當父程序和子程序進行資料通信時的情形是這樣的:父程序将标準的輸出端重定向匿名管道的寫句柄,啟動子程序,因為繼承關系,子程序也具有了這一特點,它的标準輸出也與管道的寫句柄聯系在一起了。此時的父程序在關閉管道寫句柄之後(一定要關閉),就可以通過讀句柄來取得子程序發出的資料了。

   為了說明這個實事,我小舉一例子,說明如何在圖形界面中調用控制台的标準輸出。程式運作的結果如下圖:

從匿名管道談重定向技術

程式按如下步驟實作:

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中測試通過。