2013-07-14 19 views
18

Udało mi się użyć powłoki ShellExecute w VC++ w celu uruchomienia dokumentu. Teraz chcę uruchomić narzędzie wiersza poleceń, które odbiera pewne argumenty i działa w tle (jako ukryte, nie zminimalizowane) i niech blokuje przepływ mojego programu, dzięki czemu będę mógł czekać na jego zakończenie . Jak mogę zmienić wiersza polecenia:Jak czekać na uruchomienie powłoki ShellExecute?

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

Problemem jest to, że mają narzędzie, które konwertuje HTML do PDF i życzę, że gdy narzędzie zakończeniu aka pdf jest gotowy, aby mieć inną ShellExecute do Zobacz.

Odpowiedz

35

Jest CodeProject article, który pokazuje w jaki sposób, przy użyciu ShellExecuteEx zamiast 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); 

Zasadniczą kwestią jest flaga SEE_MASK_NOCLOSEPROCESS, które as MSDN says

Służy do wskazania, że ​​hProcess element otrzymuje uchwyt procesu. Uchwyt ten jest zazwyczaj stosowany w celu umożliwienia aplikacji, aby dowiedzieć się, gdy proces stworzony z ShellExecuteEx kończy

Należy również pamiętać, że:

aplikacji wywołującej jest odpowiedzialny za zamykanie uchwytu, gdy nie jest już potrzebne.

+1

dziękuję. Spojrzę głębiej tam. to działa :) – buddy123

+3

Czy musisz CloseHandle (info.hProcess); potem? (Jest to zaznaczone tutaj: http://www.codingnotebook.com/2012/02/wait-on-process-launched-by.html) – Robin

+0

@Robin To prawda, dziękuję - poprawiłem moją odpowiedź, aby to zrobić wyraźny. –

0

Możesz również użyć CreateProcess zamiast ShellExecute/ShellExecuteEx. Ta funkcja obejmuje opcję opakowującą cmd.exe, zwracającą kod zakończenia i zwracającą stdout. (Załączniki mogą nie być idealne).

Uwagi: W moim użyciu wiedziałem, że muszą istnieć standardowe wyniki, ale funkcja PeekedNamePipe nie zawsze zwróci liczbę bajtów za pierwszym razem, stąd pętla. Być może ktoś może to zrozumieć i opublikować poprawkę? Ponadto może być produkowana alternatywna wersja, która zwraca stderr oddzielnie?

#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; 
} 
Powiązane problemy