2013-07-14 24 views
18

Tôi đã quản lý để sử dụng ShellExecute trong VC++ để khởi chạy một tài liệu. Bây giờ tôi muốn chạy một công cụ dòng lệnh nhận một số đối số và chạy ở chế độ nền (dưới dạng ẩn, không được thu nhỏ) và để nó chặn luồng chương trình của tôi, để tôi có thể đợi nó kết thúc . Làm thế nào để tôi thay đổi dòng lệnh của:Làm thế nào để chờ ShellExecute chạy?

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

Vấn đề là, tôi có công cụ chuyển đổi html sang pdf, và tôi muốn rằng một khi công cụ này hoàn tất, aka pdf đã sẵn sàng, để có một ShellExecute để xem nó.

Trả lời

35

Có một CodeProject article cho thấy như thế nào, bằng cách sử dụng ShellExecuteEx thay vì 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); 

Điểm quan trọng là lá cờ SEE_MASK_NOCLOSEPROCESS, trong đó, as MSDN says

Sử dụng để chỉ ra rằng hProcess thành viên nhận được quy trình xử lý. xử lý này thường được sử dụng để cho phép một ứng dụng để tìm hiểu khi một quá trình tạo ra với ShellExecuteEx chấm dứt

Ngoài ra, lưu ý rằng:

Ứng dụng gọi điện thoại có trách nhiệm đóng xử lý khi nó không còn cần thiết.

+1

cảm ơn. Tôi sẽ nhìn sâu hơn ở đó. nó hoạt động :) – buddy123

+3

Bạn có phải CloseHandle (info.hProcess); sau đó? (Điều này được chỉ ra ở đây: http://www.codingnotebook.com/2012/02/wait-on-process-launched-by.html) – Robin

+0

@Robin Đó là chính xác, cảm ơn - Tôi đã sửa đổi câu trả lời của tôi cho phù hợp để làm cho nó rõ ràng. –

0

Bạn cũng có thể sử dụng CreateProcess thay vì ShellExecute/ShellExecuteEx. Hàm này bao gồm tùy chọn trình bao bọc cmd.exe, trả lại mã thoát và trả về giá trị xuất chuẩn. (Bao gồm có thể không hoàn hảo).

Lưu ý: Trong sử dụng của tôi, tôi biết rằng có phải có kết quả xuất sắc, nhưng hàm PeekedNamePipe không phải lúc nào cũng trả về số byte trong lần thử đầu tiên, do đó vòng lặp đó. Có lẽ, ai đó có thể hình dung điều này và đăng một bản sửa đổi? Ngoài ra, có lẽ một phiên bản thay thế nên được sản xuất mà trả về stderr riêng biệt?

#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; 
} 
Các vấn đề liên quan