How to wait for ShellExecute to run?

前端 未结 3 1150
难免孤独
难免孤独 2020-12-05 10:34

I have manages to use ShellExecute in VC++ in order to launch a document. Now I wish to run a command-line tool that receives some arguments, and to run in the background (a

3条回答
  •  甜味超标
    2020-12-05 11:01

    You can also use CreateProcess instead of ShellExecute/ShellExecuteEx. This function includes a cmd.exe wrapper option, returning the exit code, and returning stdout. (The includes may not be perfect).

    Notes: In my use, I knew that there had to be stdout results, but the PeekedNamePipe function wouldn't always return the bytes count on the first try, hence the loop there. Perhaps, someone can figure this out and post a revision? Also, maybe an alternate version should be produced which returns stderr separately?

    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    /*
    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 *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;
    }
    

提交回复
热议问题