gpt4 book ai didi

c++ - 无法从挂起进程的单独线程中读取管道

转载 作者:行者123 更新时间:2023-11-28 03:34:37 25 4
gpt4 key购买 nike

我正在尝试使用处于挂起状态的 CreateProcess 创建进程,并从它的标准输出中读取。对于基础,我采用了 MSDN 代码。创建进程后,我将在进程上设置作业限制(尚未实现),然后我开始从 STDOUT 管道读取单独的线程。在线程启动之前,我恢复挂起的进程。结果我没有从 ReadFile 调用中得到任何东西,它只是停止并等待数据到达,即使该过程已完成。这是代码

#include <windows.h> 
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

#define BUFSIZE 4096

HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_RdDup = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hSavedStd_OUT_Wr = NULL;

HANDLE g_hInputFile = NULL;

DWORD WINAPI CreateChildProcess(LPVOID param);
void WriteToPipe(void);
DWORD WINAPI ReadFromPipe(LPVOID param);
void ErrorExit(PTSTR);
PROCESS_INFORMATION piProcInfo;

int _tmain(int argc, TCHAR *argv[])
{
SECURITY_ATTRIBUTES saAttr;

printf("\n->Start of parent execution.\n");

// Set the bInheritHandle flag so pipe handles are inherited.

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

// Create a pipe for the child process's STDOUT.

if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) )
ErrorExit(TEXT("StdoutRd CreatePipe"));

// Ensure the read handle to the pipe for STDOUT is not inherited.

if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdout SetHandleInformation"));

// Create a pipe for the child process's STDIN.

if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
ErrorExit(TEXT("Stdin CreatePipe"));

// Ensure the write handle to the pipe for STDIN is not inherited.

if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdin SetHandleInformation"));

STARTUPINFO siStartInfo;
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
//CreateThread(&saAttr,0, CreateChildProcess, &siStartInfo, 0, NULL);
CreateChildProcess(&siStartInfo);
ResumeThread(piProcInfo.hThread);

printf( "\n->Contents of child process STDOUT:\n\n", argv[1]);
//ReadFromPipe(NULL);
HANDLE thread = CreateThread(&saAttr,0, ReadFromPipe, &siStartInfo, 0, NULL);
WaitForSingleObject(thread, INFINITE);

printf("\n->End of parent execution.\n");

// The remaining open handles are cleaned up when this process terminates.
// To avoid resource leaks in a larger application, close handles explicitly.

return 0;
}

DWORD WINAPI CreateChildProcess(LPVOID param)
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
TCHAR szCmdline[]=TEXT("C:\\GnuWin32\\bin\\ls.exe");

STARTUPINFO *siStartInfo = (STARTUPINFO*)param;

BOOL bSuccess = FALSE;

// Set up members of the PROCESS_INFORMATION structure.

ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.


// Create the child process.

bSuccess = CreateProcess(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_SUSPENDED | CREATE_SEPARATE_WOW_VDM | CREATE_NO_WINDOW, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
//If resumethread is here - it works well

// If an error occurs, exit the application.
if ( ! bSuccess )
ErrorExit(TEXT("CreateProcess"));
else
{
// Close handles to the child process and its primary thread.
// Some applications might keep these handles to monitor the status
// of the child process, for example.

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

void WriteToPipe(void)

// Read from a file and write its contents to the pipe for the child's STDIN.
// Stop when there is no more data.
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;

for (;;)
{
bSuccess = ReadFile(g_hInputFile, chBuf, BUFSIZE, &dwRead, NULL);
if ( ! bSuccess || dwRead == 0 ) break;

bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
if ( ! bSuccess ) break;
}

// Close the pipe handle so the child process stops reading.

if ( ! CloseHandle(g_hChildStd_IN_Wr) )
ErrorExit(TEXT("StdInWr CloseHandle"));
}

DWORD WINAPI ReadFromPipe(LPVOID param)

// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT.
// Stop when there is no more data.
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

for (;;)
{
bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if( ! bSuccess || dwRead == 0 ) break;

bSuccess = WriteFile(hParentStdOut, chBuf,
dwRead, &dwWritten, NULL);
if (! bSuccess ) break;
}
return 0;
}

void ErrorExit(PTSTR lpszFunction)

// Format a readable error message, display a message box,
// and exit from the application.
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );

lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(1);
}

如果我调用 ResumeThread(piProcInfo.hThread);就在 CreateProcess 函数之后 - 它运行良好。但是无论如何我都需要在单独的函数中进行创建,然后调用 ResumeThread 几个函数。所以,我想知道如何使程序在单独的线程中获得暂停进程的输出。

最佳答案

始终检查返回值。

您正在尝试在已关闭的句柄上调用 ResumeThread。如果您检查了返回值,您会注意到此函数没有成功,这会告诉您问题出在哪里。

CreateChildProcess 中删除 CloseHandle(piProcInfo.hThread) 并且对 ResumeThread 的调用将起作用。

您可能还应该在创建子进程后关闭 g_hChildStd_OUT_Wrg_hChildStd_IN_Rd,以便您可以知道子进程何时退出。

关于c++ - 无法从挂起进程的单独线程中读取管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11371585/

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