Windows进程间通信---匿名管道

前言

匿名管道只能用于父子进程间通信

相关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;
}