前言
匿名管道只能用于父子进程间通信
相关API
1. CreatePipe: 创建匿名管道Anonymous Pipe.
BOOL CreatePipe(
[out] PHANDLE hReadPipe,
[out] PHANDLE hWritePipe,
[in, optional] LPSECURITY_ATTRIBUTES lpPipeAttributes,
[in] DWORD nSize
);
需要注意第三个参数lpPipeAttributes, 该参数的bInheritHandle成员决定了子进程是否能够继承父进程句柄, 必须为TRUE, 否则子进程无法对父进程的匿名管道进行读写操作.
2. PeekNamedPipe: 判断管道中是否有数据, 只是判断,并不会读取数据, 如果读取数据可以用ReadFile等IO函数.
BOOL PeekNamedPipe(
[in] HANDLE hNamedPipe,
[out, optional] LPVOID lpBuffer,
[in] DWORD nBufferSize,
[out, optional] LPDWORD lpBytesRead,
[out, optional] LPDWORD lpTotalBytesAvail,
[out, optional] LPDWORD lpBytesLeftThisMessage
);
代码示例
以下代码展示了创建CMD子进程,并重定向CMD子进程的标准输入和标准输出句柄到匿名管道上面。在终端输入命令,并打印出CMD子进程的执行结果.
#include <windows.h>
#include <iostream>
#include <thread>
int main()
{
HANDLE hReadPipe, hWritePipe;
HANDLE hReadPipeShell, hWritePipeShell;
//设定管道的安全属性
SECURITY_ATTRIBUTES securityAttributes = { 0 };
securityAttributes.bInheritHandle = TRUE;
securityAttributes.nLength = sizeof(securityAttributes);
securityAttributes.lpSecurityDescriptor = NULL;
CreatePipe(&hReadPipe, &hWritePipeShell, &securityAttributes, 0);
CreatePipe(&hReadPipeShell, &hWritePipe, &securityAttributes, 0);
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdError = hWritePipeShell;
si.hStdOutput = hWritePipeShell; //重定向 cmd 的标准输入和输出.
si.hStdInput = hReadPipeShell;
BOOL bRet = CreateProcess("C:\\windows\\system32\\cmd.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
std::jthread jth([&](){
char buf[1024 * 10] = {0};
DWORD BytesRead = 0;
DWORD TotalBytesAvail = 0;
while (PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &TotalBytesAvail, NULL))
{
if (TotalBytesAvail > 0)
{
if (ReadFile(hReadPipe, buf, sizeof(buf), NULL, NULL))
{
std::cout << buf;
memset(buf, 0, sizeof(buf));
continue;
}
}
else
{
Sleep(100);
continue;
}
}
});
std::string cmd;
while (1)
{
std::getline(std::cin, cmd);
cmd += "\r\n";
WriteFile(hWritePipe, cmd.c_str(), cmd.size(), NULL, NULL);
}
system("pause");
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(hWritePipe);
CloseHandle(hReadPipe);
return 0;
}