Создание стандартного процесса с перекрытием CreateNamedPipe - PullRequest
0 голосов
/ 09 октября 2019

Я пытаюсь прочитать вывод std внешнего процесса (pgdump), который я начал с CreateProcess. Я получил это, работая с анонимными каналами, но затем вывод блокируется, и не так, когда я выполняю его через командную строку (отсутствует конечный вывод). Я прочитал множество постов и обнаружил, что мне нужно CreateNamedPipes с WaitForSingleObject, но я не могу заставить его работать. Это мой рабочий код с анонимным каналом, но он заблокирован, и мне не хватает конца вывода

#include <QDebug>
#include <QString>

#include <windows.h>
#include <sstream>
#include <iostream>
#include <random>

int main()
{   
    #define BUFFERSIZE 256

    std::string program = "\"C:\\Program Files (x86)\\PostgreSQL\\10\\bin\\pg_dump.exe\"" +
            std::string( " --dbname=postgresql://postgresUser:PostGresql13@127.0.0.1:5432/employee -j1 -Fd -b -v -f "
                         "C:\\development\\myproject\\Build\\debug\\1-export.psql");

    HANDLE hReadStdOut = NULL;
    HANDLE hWriteStdOut = NULL;


    SECURITY_ATTRIBUTES saAttr;
    PROCESS_INFORMATION piProcInfo;
    STARTUPINFO siStartInfo;

    ZeroMemory( &saAttr, sizeof( SECURITY_ATTRIBUTES ));
    ZeroMemory( &piProcInfo, sizeof( PROCESS_INFORMATION ));
    ZeroMemory( &siStartInfo, sizeof( STARTUPINFO ));

    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    OVERLAPPED sOverlap;


    if( !CreatePipe(&hReadStdOut, &hWriteStdOut, &saAttr, 0) )
    {
        std::ostringstream os;
        os << GetLastError();

        qDebug() << "create pipe error : " << QString::fromStdString( os.str());
    }


    TCHAR* szCmdline = new TCHAR[ program.size() + 1];
    szCmdline[ program.size()] = 0;
    std::copy( program.begin(), program.end(), szCmdline );

    siStartInfo.cb = sizeof(STARTUPINFO);
    siStartInfo.hStdError = hWriteStdOut;
    siStartInfo.hStdOutput = hWriteStdOut;
    siStartInfo.hStdInput = NULL;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

    BOOL bSuccess = CreateProcess( NULL, szCmdline, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &siStartInfo,&piProcInfo );

    if ( ! bSuccess )
    {
        std::ostringstream os;
        os << GetLastError();

        qDebug() << "create process error : " << QString::fromStdString( os.str());
    }
    else
    {
        CloseHandle( hWriteStdOut );

        DWORD err;
        DWORD nBytesRead;
        char buf[BUFFERSIZE + 1];

        int i(1);

        for(;;)
        {
            std::cout << "iteration " << std::to_string( i ) << std::endl;

            if( !ReadFile( hReadStdOut, buf, sizeof( buf), &nBytesRead, NULL) || !nBytesRead )
            {}

            if( GetLastError() == ERROR_SUCCESS )
            {
            }

            std::cout.flush();
            buf[nBytesRead] = '\0';
            std::string string_ = buf;
            std::cout << string_ << std::endl;

            std::size_t found = string_.find("contents of");

            if( !nBytesRead )
                break;

            i++;
        }

        CloseHandle(piProcInfo.hProcess);
        CloseHandle(piProcInfo.hThread);
    }

    return 0;
}

1 Ответ

0 голосов
/ 09 октября 2019

Например, если ваш pg_dump.exe просто напишите одну строку в стандартный вывод. Есть несколько способов:

  1. std::cout << "Hello World!\n";
  2. printf("Hello World!\n");
  3. std::cout << "Hello World!\n"<< std::endl;
  4. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "Hello World!\n", 14, &dwWritten, NULL);

Если pg_dump.exe завершит работу после записи строки, ReadFile не будет заблокирован и вернется со строкой «Hello World!».

Однако, если pg_dump. exe не завершает работу после записи строки и продолжения другой работы. Первые два способа записи ( 1. , 2. ) приведут к блокировке ReadFile. Но если вы используете третий или четвертый способ, ReadFile будет блокироваться и возвращаться со строкой «Hello World!».

В чем разница между двумя первыми способами записи (std::cout << "Hello World!\n"; и printf("Hello World!\n");) не имеет операции очистки в конце записи, но третий или четвертый способ имеет. std::endl и WriteFile очистить буфер вывода.

Сводка :

Очистить вывод , чтобы вызвать егобыть записанным в основной поток (который может быть файлом, терминалом или каналом). Стандартный вывод сбрасывается при следующих условиях:

  1. Когда программа завершается нормально.
  2. Используйте std::endl в конце.
  3. Используйте WriteFile.

Вы можете проверить, если это ваш случай.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...