(五)Win32进程通信 —— 匿名管道
程序员文章站
2022-04-02 22:57:34
...
此案例使用匿名管道,还有一种叫做命名管道,可以百度了解
匿名管道
匿名管道用于进程之间通信,且仅限于本地父子进程之间通信,结构简单,类似于一根非水平状态的水管,一端进水另一端出水(单工)。相对于命名管道,其占用小实现简单。
单管道(匿名管道)实现本例原理图:
思路解析:
- 在父进程中创建子进程
- 进程一是父进程,进程二是子进程(可以隐藏)
- 进程二的输入端正常,将输出端与 hPWrite相连,实现将数据传输到管道中
- 关闭 hPWrite(已经没有必要存在了)
- 在进程一中,利用 hPRead 读取数据
案例效果演示:
窗口制作及功能实现步骤:
- 窗口搭建及控件自定义ID:
两个编辑框控件的ID:
- 双击执行命令按钮,实现程序功能:
每一行代码我都会加以注释,理解思路,不用完全会写代码 ^ - ^
代码部分,可以先看创建子进程部分,然后再看创建管道部分(单管道)
// **********创建管道**********
BOOL bCreate; // 用于判断是否创建成功
HANDLE hPRead, hPWrite; // 两个句柄,分别是管道的两边(读和写)
SECURITY_ATTRIBUTES la; // 管道的安全属性
la.nLength = sizeof(la); // 大小
la.bInheitHandle = TRUE; // 可以被继承
la.lpSecurityDescriptor = NULL; // 安全描述符为默认
// 创建匿名管道,默认大小
bCreate = CreatePipe(&hPRead, &hPWrite, &la, 0); // 管道实际上是一块内存
if(!bCreate) // 判断创建管道否失败
{
MessageBox(_T("CreatePipe error));
}
// **********创建子进程**********
PROCESS_INFORMATION pi{ 0 }; // 进程信息
STARTUPINFO si{ 0 }; // 开始信息
// 初始开始信息的数据
si.cb = sizeof(si); // 设置大小
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); // 标准输入(不变)
si.hStdOutput = si.hStdError = (HANDLE)hPWrite; // 将子进程的输出端连接到管道的一边(写)
si.wShowWindow = SW_HIDE; // 隐藏窗口
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; // 窗口与使用标准句柄
TCHAR scCmd[MAX_PATH * 2] { 0 };// 用于存储要输入的命令,比如 ipconfig
GetDlgItemText(IDC_EDIT_CMD, szCmd, MAX_PATH * 2); // 获取编辑框中输入的命令
// 创建是一个子进程(继承于父进程的子进程)
bCreate = CreateProcess(NULL, szCmd, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi);
CloseHandle(pi.hProcess); // 创建子进程后,关闭句柄(不需要了)
CloseHandle(pi.hThread);
if(!bCreate)
{
CloseHandle(hPWrite); // 创建子进程失败,关闭之前创建管道的两个句柄
CloseHandle(hPRead);
MessageBox(_T("CreateProcess error"));
}
else // 创建子进程成功(开始读取管道中的数据)
{
CloseHandle(hPWrite); // 关闭管道的写(此时已经没有存在的意义)
CString str; // 获取的数据(所有数据)
TCHAR szBuff[4096]; // 读取管道中的数据放到这个数组中,4k的大小
DWORD dwRead; // 实际读到的个数
while(TRUE) // 没有读到底则一直读
{
memset(szBuff, 0, sizeof(szBuff)); // 清空缓冲区里的数据
// 管道实际就是一种虚拟的文件,读取和读取文件的方式一样
if(!ReadFile(hPRead, szBuff, 4096, &dwRead, NULL))
{
break;
}
str += szBuff; // 累加数据
SetDlgItemText(IDC_EDIT_OUTPUT, str); // 将读取到的数据显示到控件中
}
CloseHanle(hPRead); // 关闭管道的读
}
此时已经好了,代码部分看似复杂,实则不然,我们理清思路再看代码会发现这是一个非常有趣的东西.
作者:浪子花梦
Time:2020.02.14
情人节快乐,各位