調用命令行程序並獲取返回信息


調用命令行並獲取返回信息是一件很有意思的事情,很多程序都會這么干,比如Visual Studio進行編譯時,也是調用了一些命令行程序進行編譯和鏈接,然后將其反饋信息輸出到編譯日志窗口。不過,調用一個命令行程序很簡單,但獲取其反饋信息並不是那么容易。當然如果知道怎么做,也不會很復雜。

思路如下:

  1. 創建一個匿名管道;
  2. 調用CreateProcess執行命令行程序並將其輸出定位到匿名管道的寫入端;
  3. 從匿名管道的讀取端讀取數據,那么讀取到的數據就是命令行程序的輸出信息;

這兒需要解釋一下何謂管道,我的理解是:管道會提供一對端口,當向寫入端口寫入內容時,那么就可以在讀取端口讀取到相同的內容。匿名管道是管道中最簡單的一種,通過調用CreatePipe函數可以創建一組匿名管道。

下面是一個調用命令行程序並獲得返回值的C++函數源碼:

 

std::string ExeCmd(const char * pszCmd)
{
    //創建匿名管道
    SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
    HANDLE hRead, hWrite;
    if (!CreatePipe(&hRead, &hWrite, &sa, 0))
    {
        return "";
    }

    //設置命令行進程啟動信息(以隱藏方式啟動命令並定位其輸出到hWrite)
    STARTUPINFO si = {sizeof(STARTUPINFO)};
    GetStartupInfo(&si);
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.wShowWindow = SW_HIDE;
    si.hStdError = hWrite;
    si.hStdOutput = hWrite;

    //啟動命令行
    PROCESS_INFORMATION pi;
    if (!CreateProcess(NULL, (char *)pszCmd, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
    {
        return "";
    }

    //立即關閉hWrite
    CloseHandle(hWrite);

    //讀取命令行返回值
    std::string strRet;
    char buff[1024] = {0};
    DWORD dwRead = 0;
    while (ReadFile(hRead, buff, 1024, &dwRead, NULL))
    {
        strRet.append(buff, dwRead);
    }
    CloseHandle(hRead);

    return strRet;
}

 

這兒需要說明的是:為什么需要在啟動命令行之后,會需要立即關閉hWrite?

原因是這樣的:

首先,hWrite是Windows內核對象,內核對象有個特點,只有所有使用者都關閉該內核對象后,該內核對象才會真正關閉。這兒hWrite已經被上面的進程所使用了,所以此處關閉hWrite並不會導致該句柄失效。

其次,這樣做有個好處在於,但命令行程序結束后,hWrite就會隨之真正關閉。這樣的話,才會讓后續的ReadFile函數能夠結束——否則它會一直等待直到hWrite被關閉(由於ReadFile是個同步函數,如果上面不關閉,以后永遠沒有關閉機會了)。

 

我在Visual Studio中,用一個對話框程序,簡單測試一下這個函數:

 

void CTestPipeDlg::OnBnClickedOk()
{
    AfxMessageBox(ExeCmd("ping baidu.com").c_str());
}

 

結果如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM