欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(五)Win32进程通信 —— 匿名管道

程序员文章站 2022-04-02 22:57:34
...

此案例使用匿名管道,还有一种叫做命名管道,可以百度了解

匿名管道

匿名管道用于进程之间通信,且仅限于本地父子进程之间通信结构简单,类似于一根非水平状态的水管,一端进水另一端出水(单工)。相对于命名管道,其占用小实现简单


单管道(匿名管道)实现本例原理图:

(五)Win32进程通信 —— 匿名管道

思路解析:

  • 在父进程中创建子进程
  • 进程一是父进程,进程二是子进程(可以隐藏)
  • 进程二的输入端正常,将输出端与 hPWrite相连,实现将数据传输到管道中
  • 关闭 hPWrite(已经没有必要存在了)
  • 在进程一中,利用 hPRead 读取数据

案例效果演示:

(五)Win32进程通信 —— 匿名管道


窗口制作及功能实现步骤:

  1. 窗口搭建及控件自定义ID:

(五)Win32进程通信 —— 匿名管道
两个编辑框控件的ID:
(五)Win32进程通信 —— 匿名管道

  1. 双击执行命令按钮,实现程序功能:

(五)Win32进程通信 —— 匿名管道

每一行代码我都会加以注释,理解思路,不用完全会写代码 ^ - ^

代码部分,可以先看创建子进程部分,然后再看创建管道部分(单管道)


// **********创建管道**********

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

情人节快乐,各位

相关标签: Win32 win32