2013-07-14 4 views
18

문서를 시작하려면 VC++에서 ShellExecute를 사용해야합니다. 이제 일부 인수를받는 명령 줄 도구를 실행하고 배경에서 실행 (최소화되지 않은 숨김)하고 프로그램 흐름을 차단하여 끝날 때까지 기다릴 수 있습니다. . 어떻게의 명령 줄을 변경합니다 :ShellExecute가 실행될 때까지 기다리는 방법?

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

문제는 내가 PDF로 HTML 변환 도구를 가지고, 내가 도구가 완료되면 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); 

결정적인 포인트는 as MSDN says

사용이 나타내는 플래그 SEE_MASK_NOCLOSEPROCESS이며, 그 hProcess 구성원이 프로세스 핸들을 수신합니다. 이 핸들은 일반적으로 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 반환이 포함됩니다. (포함하는 것이 완벽하지 않을 수도 있습니다).

Notes : 필자가 사용하는 것으로는 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; 
}