2013-07-14 61 views
18

私は、ドキュメントを起動するためにVC++でShellExecuteを使用することを管理しています。 私はいくつかの引数を受け取るコマンドラインツールを実行し、バックグラウンドで(隠されていない、最小化されていないように)実行し、プログラムフローをブロックさせて、それが完了するのを待つことができるようにしたい。 はどのようにコマンドラインを変更する:ShellExecuteが実行されるのを待つ方法は?

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

問題は、私はHTMLをPDFに変換するツールを持っている、と私はツールが終了したら、PDFの準備ができている、別名、別のShellExecuteのを持っていることを望む、ありますそれを見る。

答えて

35

CodeProject articleShellExecuteEx代わりに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); 

重要な点は、as MSDN says

使用していることHPROCESSを示すために、フラグSEE_MASK_NOCLOSEPROCESS、ありますメンバーがプロセスハンドルを受け取ります。このハンドルは、通常、ShellExecuteExで作成したプロセスはまた

終了すると、アプリケーションが知ることを可能に注意するのに使用されている:

それはなくなったときに呼び出し元のアプリケーションは、ハンドルを閉じるための責任がありません必要です。

+1

ありがとう。私はそこでもっと深く見ていきます。それは動作します:) – buddy123

+3

あなたはCloseHandle(info.hProcess)する必要がありますか?その後? (これはここに表示されています:http://www.codingnotebook.com/2012/02/wait-on-process-launched-by.html) – Robin

+0

@Robinそれは正しいです、ありがとう - 私はそれに応じて私の答えを修正しました明示的。 –

0

また、ShellExecute/ShellExecuteExの代わりにCreateProcessを使用することもできます。この関数には、cmd.exeラッパーオプションが含まれ、終了コードが返され、stdoutが返されます。 (インクルードが完璧でないかもしれない)。

注:私の使用では、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; 
} 
関連する問題