官方参考https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
由于我并不需要读取子进程的输出,所以简化了一下过程,改动不多
代码流程并不复杂:
- 父进程向管道写入数据
- 子进程从管道读取数据到标准输入
直接贴出代码:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <iostream>
using namespace std;
#pragma comment(lib,"winmm.lib")
#define BUFSIZE 4096
HANDLE g_hChildStd_IN_Rd = NULL; //管道读端作为子进程标准输入
HANDLE g_hChildStd_IN_Wr = NULL;
void CreateChildProcess(void);
void WriteToPipe(void);
void ErrorExit(PTSTR);
int _tmain(int argc, TCHAR* argv[])
{
SECURITY_ATTRIBUTES saAttr;
// 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 STDIN.
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
ErrorExit(TEXT(PTSTR)("Stdin CreatePipe"));
// Ensure the write handle to the pipe for STDIN is not inherited.
// 设置g_hChildStd_IN_Wr句柄不可继承
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
ErrorExit(TEXT(PTSTR)("Stdin SetHandleInformation"));
// Create the child process.
CreateChildProcess();
// Get a handle to an input file for the parent.
// This example assumes a plain text file and uses string output to verify data flow.
//向管道写入‘q’
printf("\n->Enter 'q': ");
while (1)
{
if (cin.get() == 'q')
{
DWORD start = timeGetTime();
WriteToPipe();//往管道写数据
DWORD end = timeGetTime();
cout << (end - start) << "ms!" << endl;
}
}
// Read from pipe that is the standard output for child process.
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;
}
void CreateChildProcess()
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
//TCHAR szCmdline[] = TEXT(".\\child\\child.exe");
TCHAR szCmdline[] = TEXT(".\\ffmpeg.exe -stream_loop -1 -re -i swt.mp3 -codec copy -y faj.mp3");
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
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.
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; //使用hStdInput、hStdOutput 和hStdError 成员
// Create the child process.
bSuccess = CreateProcess(NULL,
szCmdline, // 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 an error occurs, exit the application.
if (!bSuccess)
ErrorExit(TEXT(PTSTR)("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);
// Close handles to the stdin and stdout pipes no longer needed by the child process.
// If they are not explicitly closed, there is no way to recognize that the child process has ended.
CloseHandle(g_hChildStd_IN_Rd);
}
}
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;
BOOL bSuccess = FALSE;
CHAR tchBuf[BUFSIZE] = "q\r\n";
//数据写进管道 - 管道另一端是子进程的标准输入
bSuccess = WriteFile(g_hChildStd_IN_Wr, tchBuf, strlen(tchBuf), &dwWritten, NULL);
if (!bSuccess)
{
ErrorExit(TEXT(PTSTR)("WriteFile"));
}
return;
// Close the pipe handle so the child process stops reading.
//if (!CloseHandle(g_hChildStd_IN_Wr))
// ErrorExit(TEXT(PTSTR)("StdInWr CloseHandle"));
}
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);
}