標籤:pipe redirect 管道 重新導向 stdout
stdin是標準輸入,stdout是標準輸出,stderr是標準錯誤輸出。大多數的命令列程式從stdin輸入,輸出到stdout或stderr,有時我們需要重新導向stdout,stderr,stdin。比如:將輸出寫入檔案,又或者我們要將命令列程式輸出結果顯示到Windows對話方塊中。
在Windows編程中,重新導向需要用到管道(Pipe)的概念。管道是一種用於在進程間共用資料的機制。一個管道類似於一個管子的兩端,一端是寫入的,一端是讀出的。由一個進程從寫入端寫入、另一個進程從讀出端讀出,從而實現通訊,就向一個“管道”一樣。
重新導向的原理是:
首先聲明兩個概念:主程式(重新導向的操縱者)、子進程(被重新導向的子進程)
- 如果要重新導向stdout的話,先產生一個管道, 管道的寫入端交給子進程去寫,主程式從管道的讀出端讀資料,然後可以把資料寫成檔案、顯示等等。重新導向stderr和stdout是相同的。
- 同理,要重新導向stdin的話,產生一個管道, 管道的寫入端由主程式寫,子進程從管道的讀出端讀資料。
下面是一個輸出重新導向的例子:將一個命令列Ping的結果展示在編輯框裡。
核心代碼如下:
#define MSG_DATAREC WM_USER +0x400BEGIN_MESSAGE_MAP(CStudyStdOut_RedirectGuiDlg, CDialog)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()//}}AFX_MSG_MAPON_BN_CLICKED(IDC_BUTTON1, &CStudyStdOut_RedirectGuiDlg::OnBnClickedButton1)ON_MESSAGE(MSG_DATAREC,&CStudyStdOut_RedirectGuiDlg::OnDataRec)END_MESSAGE_MAP()void CStudyStdOut_RedirectGuiDlg::OnBnClickedButton1(){// TODO: Add your control notification handler code hereSECURITY_ATTRIBUTES sa; ZeroMemory(&sa,sizeof(sa)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; //預設的安全性描述元 sa.bInheritHandle = TRUE; //這個必須要設定TRUE,參考資料:《windows核心編程》第三章 HANDLE hRead, hWrite;if( !CreatePipe(&hRead, &hWrite, &sa, 0) ) { MessageBox(" CreatePipe return FALSE."); return; } m_hReadPipe = hRead;AfxBeginThread(ReadPipeProc,this,NULL); STARTUPINFO siStartInfo;PROCESS_INFORMATION piProcInfo;ZeroMemory(&siStartInfo,sizeof(STARTUPINFO));siStartInfo.cb =sizeof(STARTUPINFO);siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;siStartInfo.dwFlags |= STARTF_USESTDHANDLES;siStartInfo.hStdOutput = hWrite;siStartInfo.hStdError = hWrite;TCHAR szCmdPar[256] = "ping www.baidu.com"; if(!CreateProcess(NULL, szCmdPar,NULL,NULL,TRUE,NULL,NULL,NULL,&siStartInfo, &piProcInfo)) { MessageBox("CreateProcess failed!"); return; }CloseHandle(piProcInfo.hProcess);CloseHandle(piProcInfo.hThread);}UINT ReadPipeProc( LPVOID pParam ) { CStudyStdOut_RedirectGuiDlg * pAttachWnd = static_cast<CStudyStdOut_RedirectGuiDlg *>(pParam); HANDLE hRead = pAttachWnd->m_hReadPipe; HWND hWnd = pAttachWnd->GetSafeHwnd(); DWORD bytesRead; while( 1 ) { int len = sizeof(pAttachWnd->m_szData); ZeroMemory(&pAttachWnd->m_szData,len); if( !ReadFile(hRead, pAttachWnd->m_szData, len-1, &bytesRead, NULL) ) break; SendMessage(hWnd,MSG_DATAREC,0,0); } return 0; } HRESULT CStudyStdOut_RedirectGuiDlg::OnDataRec( WPARAM wParam, LPARAM lParam ){m_strEdit += m_szData;UpdateData(FALSE);return 1;}
Windows管道與StdIn、StdOut重新導向