2013-07-14 79 views
18

我有管理才能發動一個文檔時使用的ShellExecute在VC++。 現在我想運行接收一些參數的命令行工具,並在後臺運行(如隱蔽,沒有最小化),並讓它擋住了我的程序流程,這樣我就可以等待它完成。 如何我改變的命令行:如何等待ShellExecute運行?

ShellExecute(NULL,"open",FULL_PATH_TO_CMD_LINE_TOOL,ARGUMENTS,NULL,SW_HIDE); 

的問題是,我的工具,轉換HTML到PDF,我希望,一旦工具完成,又名PDF是準備好了,有另一種的ShellExecute來查看它。

回答

35

有一個CodeProject article演示瞭如何通過使用ShellExecuteEx代替ShellExecute

SHELLEXECUTEINFO ShExecInfo = {0}; 
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); 
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; 
ShExecInfo.hwnd = NULL; 
ShExecInfo.lpVerb = NULL; 
ShExecInfo.lpFile = "c:\\MyProgram.exe";   
ShExecInfo.lpParameters = ""; 
ShExecInfo.lpDirectory = NULL; 
ShExecInfo.nShow = SW_SHOW; 
ShExecInfo.hInstApp = NULL; 
ShellExecuteEx(&ShExecInfo); 
WaitForSingleObject(ShExecInfo.hProcess,INFINITE); 

的關鍵點是標誌SEE_MASK_NOCLOSEPROCESSas MSDN says

使用來指示,該hProcess成員收到進程句柄。該手柄通常用於允許應用程序發現時ShellExecuteEx創建一個進程終止

另外,還要注意:

調用應用程序負責關閉手柄時不再需要。

+1

感謝。我會更深入地看。它的工作原理:) – buddy123

+3

你一定要CloseHandle的(info.hProcess);之後? (這是在此間表示:http://www.codingnotebook.com/2012/02/wait-on-process-launched-by.html) – Robin

+0

@Robin這是正確的,感謝 - 我已經修改了我的答案因此使它明確。 –

0

您也可以使用CreateProcess而不是ShellExecute/ShellExecuteEx。該函數包含一個cmd.exe包裝選項,返回退出代碼並返回stdout。 (包括可能不完美)。

注:在我的使用,我知道,必須有標準輸出的結果,但PeekedNamePipe函數並不總是返回字節數在第一次嘗試,因此循環那裏。也許,有人可以弄清楚併發布修訂?另外,也許應該生成一個替代版本,它會分別返回stderr?

#include <stdio.h> 
#include <iostream> 
#include <fstream> 
#include <sstream> 
#include <Shellapi.h> 


/* 
Note: 
    The exitCode for a "Cmd Process" is not the exitCode 
    for a sub process launched from it! That can be retrieved 
    via the errorlevel variable in the command line like so: 
    set errorlevel=&[launch command]&echo.&echo exitCode=%errorlevel%&echo. 
    The stdOut vector will then contain the exitCode on a seperate line 
*/ 
BOOL executeCommandLine(const CStringW &command, 
         DWORD &exitCode, 
         const BOOL asCmdProcess=FALSE, 
         std::vector<CStringW> *stdOutLines=NULL) 
{ 
    // Init return values 
    BOOL bSuccess = FALSE; 
    exitCode = 0; 
    if(stdOutLines) stdOutLines->clear(); 

    // Optionally prepend cmd.exe to command line to execute 
    CStringW cmdLine((asCmdProcess ? L"cmd.exe /C " : L"") + 
         command); 

    // Create a pipe for the redirection of the STDOUT 
    // of a child process. 
    HANDLE g_hChildStd_OUT_Rd = NULL; 
    HANDLE g_hChildStd_OUT_Wr = NULL; 
    SECURITY_ATTRIBUTES saAttr; 
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL; 
    bSuccess = CreatePipe(&g_hChildStd_OUT_Rd, 
          &g_hChildStd_OUT_Wr, &saAttr, 0); 
    if(!bSuccess) return bSuccess;   
    bSuccess = SetHandleInformation(g_hChildStd_OUT_Rd, 
            HANDLE_FLAG_INHERIT, 0); 
    if(!bSuccess) return bSuccess;   

    // Setup the child process to use the STDOUT redirection 
    PROCESS_INFORMATION piProcInfo; 
    STARTUPINFO siStartInfo;  
    ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); 
    ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); 
    siStartInfo.cb = sizeof(STARTUPINFO); 
    siStartInfo.hStdError = g_hChildStd_OUT_Wr; 
    siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; 
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES; 

    // Execute a synchronous child process & get exit code 
    bSuccess = CreateProcess(NULL, 
     cmdLine.GetBuffer(), // command line 
     NULL,     // process security attributes 
     NULL,     // primary thread security attributes 
     TRUE,     // handles are inherited 
     0,     // creation flags 
     NULL,     // use parent's environment 
     NULL,     // use parent's current directory 
     &siStartInfo,   // STARTUPINFO pointer 
     &piProcInfo);  // receives PROCESS_INFORMATION  
    if(!bSuccess) return bSuccess;   
    WaitForSingleObject(piProcInfo.hProcess, (DWORD)(-1L)); 
    GetExitCodeProcess(piProcInfo.hProcess, &exitCode); 
    CloseHandle(piProcInfo.hProcess); 
    CloseHandle(piProcInfo.hThread); 

    // Return if the caller is not requesting the stdout results 
    if(!stdOutLines) return TRUE; 

    // Read the data written to the pipe 
    DWORD bytesInPipe = 0; 
    while(bytesInPipe==0){ 
     bSuccess = PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, 0, NULL, 
            &bytesInPipe, NULL); 
     if(!bSuccess) return bSuccess; 
    } 
    if(bytesInPipe == 0) return TRUE; 
    DWORD dwRead; 
    CHAR *pipeContents = new CHAR[ bytesInPipe ];  
    bSuccess = ReadFile(g_hChildStd_OUT_Rd, pipeContents, 
         bytesInPipe, &dwRead, NULL); 
    if(!bSuccess || dwRead == 0) return FALSE; 

    // Split the data into lines and add them to the return vector 
    std::stringstream stream(pipeContents); 
    std::string str; 
    while(getline(stream, str)) 
     stdOutLines->push_back(CStringW(str.c_str())); 

    return TRUE; 
}