gpt4 book ai didi

c++ - 与CreateNamedPipe重叠的CreateProcess标准输出

转载 作者:行者123 更新时间:2023-12-02 10:38:25 41 4
gpt4 key购买 nike

我正在尝试读取以CreateProcess开始的外部进程(pgdump)的std输出。我使用匿名管道进行了此操作,但是随后输出被阻止,这与通过命令行执行它不一样(缺少最终输出)。我阅读了许多文章,发现我需要使用带有WaitForSingleObject的CreateNamedPipes,但似乎无法正常工作。这是我使用匿名管道的工作代码,但是被阻止了,而我错过了输出的结尾

#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;
}

最佳答案

例如,如果您的pg_dump.exe只写一行到标准输出。有几种方法:

  • std::cout << "Hello World!\n";
  • printf("Hello World!\n");
  • std::cout << "Hello World!\n"<< std::endl;
  • 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::endlWriteFile 刷新输出缓冲区。

    摘要:

    刷新输出以使其被写入基础流(可以是文件,终端或管道)。在以下条件下冲洗标准输出:
  • 程序正常结束时。
  • 最后使用std::endl
  • 使用WriteFile

  • 您可以检查是否属于您的情况。

    关于c++ - 与CreateNamedPipe重叠的CreateProcess标准输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58294219/

    41 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com