Profi_GMan
@Profi_GMan

Как запустить команду cmd.exe без окна и получить вывод?

Доброго времени суток!
Перерыл весь рунет и западный интернет в поисках сабжа. Но все способы не предполагают получения вывода(stdout).
Нашёл пример с popen(https://qanda.tech/c/1015629/c-popen-command-witho... но он компилируется
С изменениями скомпилировался этот способ, но он всё равно выводит консоль
зы В winapi я - полный нуб. Программировал под linux
Огромнейшее спасибо! Убил на поиски уже 4 дня

upd Нарыл ещё один способ, но он у меня не компилируется и с его помощью я не знаю, как получить возвращаемое значение:
Код
//
// Execute a command and get the results. (Only standard output)
//
CStringA ExecCmd(
    const wchar_t* cmd              // [in] command to execute
)
{
    CStringA strResult;
    HANDLE hPipeRead, hPipeWrite;

    SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) };
    saAttr.bInheritHandle = TRUE;   //Pipe handles are inherited by child process.
    saAttr.lpSecurityDescriptor = NULL;

    // Create a pipe to get results from child's stdout.
    if ( !CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0) )
        return strResult;

    STARTUPINFO si = { sizeof(STARTUPINFO) };
    si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.hStdOutput  = hPipeWrite;
    si.hStdError   = hPipeWrite;
    si.wShowWindow = SW_HIDE;       // Prevents cmd window from flashing. Requires STARTF_USESHOWWINDOW in dwFlags.

    PROCESS_INFORMATION pi  = { 0 };

    BOOL fSuccess = CreateProcessW( NULL, (LPWSTR)cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
    if (! fSuccess)
    {
        CloseHandle( hPipeWrite );
        CloseHandle( hPipeRead );
        return strResult;
    }

    bool bProcessEnded = false;
    for (; !bProcessEnded ;)
    {
        // Give some timeslice (50ms), so we won't waste 100% cpu.
        bProcessEnded = WaitForSingleObject( pi.hProcess, 50) == WAIT_OBJECT_0;

        // Even if process exited - we continue reading, if there is some data available over pipe.
        for (;;)
        {
            char buf[1024];
            DWORD dwRead = 0;
            DWORD dwAvail = 0;

            if (!::PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwAvail, NULL))
                break;

            if (!dwAvail) // no data available, return
                break;

            if (!::ReadFile(hPipeRead, buf, min(sizeof(buf) - 1, dwAvail), &dwRead, NULL) || !dwRead)
                // error, the child process might ended
                break;

            buf[dwRead] = 0;
            strResult += buf;
        }
    } //for

    CloseHandle( hPipeWrite );
    CloseHandle( hPipeRead );
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
    return strResult;
} //ExecCmd
  • Вопрос задан
  • 691 просмотр
Решения вопроса 1
Profi_GMan
@Profi_GMan Автор вопроса
И так, после дня мучений и разучивания winapi(а писал ранее всегда на линуксе), я написал рабочее решение:
код
DWORD _res = 22;
    QString strResult;
       HANDLE hPipeRead, hPipeWrite;

       SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) };
       saAttr.bInheritHandle = TRUE;   //Pipe handles are inherited by child process.
       saAttr.lpSecurityDescriptor = NULL;

       // Create a pipe to get results from child's stdout.
       if ( !CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0) ) {
           qCritical() << QObject::tr("Cannot create thread");
           return;
       }
       qDebug() << QObject::tr("Thread successfully created");

       STARTUPINFO si = { sizeof(STARTUPINFO) };
       si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
       si.hStdOutput  = hPipeWrite;
       si.hStdError   = hPipeWrite;
       si.wShowWindow = SW_HIDE;       // Prevents cmd window from flashing. Requires STARTF_USESHOWWINDOW in dwFlags.

       PROCESS_INFORMATION pi  = { 0 };

       BOOL fSuccess = CreateProcessW( NULL, (LPWSTR)command.toStdWString().c_str(), NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
       if (! fSuccess)
       {
           CloseHandle( hPipeWrite );
           CloseHandle( hPipeRead );
           qCritical() << QObject::tr("Cannot create procces");
           return;
       }
       qDebug() << QObject::tr("Proccess successfully created");

       int i = 0;
       bool bProcessEnded = false;
       for (; !bProcessEnded ;)
       {
           // Give some timeslice (50ms), so we won't waste 100% cpu.
           bProcessEnded = WaitForSingleObject( pi.hProcess, 50) == WAIT_OBJECT_0;

           // Even if process exited - we continue reading, if there is some data available over pipe.
           for (;;)
           {
               i++;
               char buf[1024];
               DWORD dwRead = 0;
               DWORD dwAvail = 0;

               if (!::PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwAvail, NULL))
                   break;

               if (!dwAvail) // no data available, return
                   break;

               DWORD temp = sizeof(buf) - 1;
               if (!::ReadFile(hPipeRead, buf, qMin(temp, dwAvail), &dwRead, NULL) || !dwRead)
                   // error, the child process might ended
                   break;

               buf[dwRead] = 0;
               strResult += buf;
           }
       } //for

    if(GetExitCodeProcess(pi.hProcess, &_res) == 0) _res = GetLastError();
       CloseHandle( hPipeWrite );
       CloseHandle( hPipeRead );
       CloseHandle( pi.hProcess );
       CloseHandle( pi.hThread );

Кому нужно, вот класс с этой функцией и под винду, и под линукс.

Я пишу на qt. Если вы не пишете на нём, то QString можно заменить на std::string, от этого ничего не изменится. Также можно убрать qDebug(), это логирование с помощью фреймворка qt, если вы на нём не программируете их надо заменить или удалить. И qMin() можно заменить на std::min()
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы