Win32 - 进程间通信(IPC)管道
1、匿名管道
匿名管道是一个没有命名的单向管道,本质上就是一个共享的内存,抽象成是管道。
通常用来在父进程和子进程之间通信。只能实现本地两个进程之间的通信。不能实现网络通信。
匿名管道(Anonymous Pipe):
匿名管道是一种无名称的管道,仅限于在父子进程或者兄弟进程之间进行通信。
匿名管道只能在同一个计算机上的相关进程之间进行通信,不能跨网络使用。
匿名管道是单向的,只能支持单向的数据流传输,例如从父进程到子进程。
匿名管道一般用于简单的进程间通信需求,例如父进程将数据传递给子进程进行处理。
实现功能:父进程启动子进程
示例代码:
// ParentDlg.h: 头文件
//
#pragma once
// CParentDlg 对话框
class CParentDlg : public CDialogEx
{
// 构造
public:
CParentDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_PARENT_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
HANDLE m_hRead ;
HANDLE m_hWrite ;
afx_msg void OnBnClickedBtnCreate();
};
// ParentDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "Parent.h"
#include "ParentDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CParentDlg 对话框
CParentDlg::CParentDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_PARENT_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CParentDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CParentDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_Create, &CParentDlg::OnBnClickedBtnCreate)
END_MESSAGE_MAP()
// CParentDlg 消息处理程序
BOOL CParentDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CParentDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CParentDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
// 启动子进程
void CParentDlg::OnBnClickedBtnCreate()
{
//创建匿名管道
//第1,2个参数:读写句柄
//第3个参数:安全描述符
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;//子进程继承父进程的句柄
sa.lpSecurityDescriptor = NULL;//安全描述符
sa.nLength = sizeof(SECURITY_ATTRIBUTES);//结构体大小
//第4个参数:缓冲区大小
if (!CreatePipe(&m_hRead, &m_hWrite, &sa, 0))
{
MessageBox(L"创建匿名管道失败", L"提示");
return;
}
TCHAR szCmdLine[MAX_PATH] = L"Sub.exe";
//启动信息
STARTUPINFO si = { 0 };
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;//标准输入输出
si.hStdInput = m_hRead;//标准输入
si.hStdOutput = m_hWrite;//写入
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);//标准输入输出错误句柄
//进程信息
PROCESS_INFORMATION pi = { 0 };
if (!CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(m_hRead);
CloseHandle(m_hWrite);
m_hRead = NULL;
m_hWrite = NULL;
MessageBox(L"创建子进程失败", L"提示");
return;
}
}
再创建一个Sub的MFC测试程序,然后编译运行将子进程的*.exe放到父进程中

运行结果:

实现功能:父进程写入数据、子进程读出数据,注:子进程写入数据、父进程读取数据原理一致
父进程:
// ParentDlg.h: 头文件
//
#pragma once
// CParentDlg 对话框
class CParentDlg : public CDialogEx
{
// 构造
public:
CParentDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_PARENT_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
HANDLE m_hRead ;
HANDLE m_hWrite ;
afx_msg void OnBnClickedBtnCreate();
afx_msg void OnBnClickedBtnWrite();
CString m_str;// 绑定编辑框
};
// ParentDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "Parent.h"
#include "ParentDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CParentDlg 对话框
CParentDlg::CParentDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_PARENT_DIALOG, pParent)
, m_str(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CParentDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_str);
}
BEGIN_MESSAGE_MAP(CParentDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_Create, &CParentDlg::OnBnClickedBtnCreate)
ON_BN_CLICKED(IDC_BTN_Write, &CParentDlg::OnBnClickedBtnWrite)
END_MESSAGE_MAP()
// CParentDlg 消息处理程序
BOOL CParentDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CParentDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CParentDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
// 启动子进程
void CParentDlg::OnBnClickedBtnCreate()
{
//创建匿名管道
//第1,2个参数:读写句柄
//第3个参数:安全描述符
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;//子进程继承父进程的句柄
sa.lpSecurityDescriptor = NULL;//安全描述符
sa.nLength = sizeof(SECURITY_ATTRIBUTES);//结构体大小
//第4个参数:缓冲区大小
if (!CreatePipe(&m_hRead, &m_hWrite, &sa, 0))
{
MessageBox(L"创建匿名管道失败", L"提示");
return;
}
TCHAR szCmdLine[MAX_PATH] = L"Sub.exe";
//启动信息
STARTUPINFO si = { 0 };
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;//标准输入输出
si.hStdInput = m_hRead;//标准输入
si.hStdOutput = m_hWrite;//写入
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);//标准输入输出错误句柄
//进程信息
PROCESS_INFORMATION pi = { 0 };
if (!CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(m_hRead);
CloseHandle(m_hWrite);
m_hRead = NULL;
m_hWrite = NULL;
MessageBox(L"创建子进程失败", L"提示");
return;
}
}
void CParentDlg::OnBnClickedBtnWrite()
{
if (m_hWrite == NULL)
{
MessageBox(L"请先点击【创建子进程】", L"提示", MB_ICONWARNING);
return;
}
// 从编辑框获取用户输入
UpdateData(TRUE); // 将界面输入同步到 m_str
if (m_str.IsEmpty())
{
MessageBox(L"请输入要发送的内容", L"提示", MB_ICONINFORMATION);
return;
}
// 写入管道(宽字符,包含结尾的 L'\0')
DWORD dwWrite = 0;
// 字节数 = (字符数 + 1) * sizeof(wchar_t)
DWORD dwBytesToWrite = (m_str.GetLength() + 1) * sizeof(wchar_t);
BOOL bRet = WriteFile(m_hWrite, (LPCVOID)(LPCTSTR)m_str, dwBytesToWrite, &dwWrite, NULL);
if (!bRet || dwWrite != dwBytesToWrite)
{
MessageBox(L"写入管道失败", L"错误", MB_ICONERROR);
return;
}
// 可选:清空输入框表示已发送(保留也可以)
// m_str.Empty();
// UpdateData(FALSE);
MessageBox(L"数据已发送", L"提示", MB_OK);
}
子进程:
// SubDlg.h: 头文件
//
#pragma once
// CSubDlg 对话框
class CSubDlg : public CDialogEx
{
// 构造
public:
CSubDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_SUB_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
HANDLE m_hRead;
HANDLE m_hWrite;
afx_msg void OnBnClickedBtnRead();
CString m_str; // 绑定编辑框,用于显示接收的内容
};
// SubDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "Sub.h"
#include "SubDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CSubDlg 对话框
CSubDlg::CSubDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_SUB_DIALOG, pParent)
, m_str(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CSubDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_str);
}
BEGIN_MESSAGE_MAP(CSubDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_Read, &CSubDlg::OnBnClickedBtnRead)
END_MESSAGE_MAP()
// CSubDlg 消息处理程序
BOOL CSubDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CSubDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CSubDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CSubDlg::OnBnClickedBtnRead()
{
m_hRead = GetStdHandle(STD_INPUT_HANDLE); // 获取被父进程重定向的标准输入句柄(管道读端)
m_hWrite = GetStdHandle(STD_OUTPUT_HANDLE);
if (m_hRead == INVALID_HANDLE_VALUE || m_hRead == NULL)
{
MessageBox(L"无法获取标准输入句柄", L"错误", MB_ICONERROR);
return;
}
// 读取数据(宽字符)
wchar_t buffer[256] = { 0 };
DWORD dwRead = 0;
// 读取缓冲区大小(字节)
// 读取缓冲区大小(字节)
if (!ReadFile(m_hRead, buffer, sizeof(buffer) - sizeof(wchar_t), &dwRead, NULL))
{
DWORD err = GetLastError();
if (err == ERROR_BROKEN_PIPE)
MessageBox(L"管道已被父进程关闭", L"提示", MB_ICONWARNING);
else
MessageBox(L"读取管道失败", L"错误", MB_ICONERROR);
return;
}
// 确保读到的数据以 null 结尾(ReadFile 不会自动添加)
buffer[dwRead / sizeof(wchar_t)] = L'\0';
// 显示到编辑框
m_str = buffer;
UpdateData(FALSE); // 刷新界面
// 可选:弹出提示框(非必须)
// MessageBox(buffer, L"收到数据", MB_OK);
}
运行结果:

2、命名管道
与Socket相似,支持网络之间进程的通信。
命名管道(Named Pipe):
命名管道是具有唯一名称的管道,可以通过该名称在不同进程之间进行通信。
命名管道可以在本地机器上的不同进程之间进行通信,也可以在网络上的不同计算机之间进行通信。
命名管道支持全双工通信,可以同时进行读取和写入操作。
命名管道可以被多个进程打开和使用,允许多个读取者和写入者同时进行操作。
命名管道通常用于需要持久性连接和长期通信的场景,例如服务器和客户端之间的通信。
服务器代码:
// pipServerDlg.h: 头文件
//
#pragma once
// CpipServerDlg 对话框
class CpipServerDlg : public CDialogEx
{
// 构造
public:
CpipServerDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_PIPSERVER_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
HANDLE m_hPipe;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedBtnCreate();
afx_msg void OnBnClickedBtnWrite();
afx_msg void OnBnClickedBtnRead();
};
// pipServerDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "pipServer.h"
#include "pipServerDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CpipServerDlg 对话框
CpipServerDlg::CpipServerDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_PIPSERVER_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CpipServerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CpipServerDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_Create, &CpipServerDlg::OnBnClickedBtnCreate)
ON_BN_CLICKED(IDC_Btn_Write, &CpipServerDlg::OnBnClickedBtnWrite)
ON_BN_CLICKED(IDC_Btn_Read, &CpipServerDlg::OnBnClickedBtnRead)
END_MESSAGE_MAP()
// CpipServerDlg 消息处理程序
BOOL CpipServerDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CpipServerDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CpipServerDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CpipServerDlg::OnBnClickedBtnCreate()
{
//第一个参数:名字,名字格式:\\.\pipe\pipename
//第二个参数:打开模式 PIPE_ACCESS_DUPLEX双工模式,FILE_FLAG_OVERLAPPED 在读写过程中会发送一个信号
//第三个参数:管道模式 PIPE_TYPE_MESSAGE 消息的方式
//第四个参数:最大实例个数
//第五个参数:输出的缓冲大小
//第六个参数:输入的缓冲区大小
//第七个参数:默认的超时时间
//第八个参数:安全描述
m_hPipe = CreateNamedPipe(L"\\\\.\\pipe\\test", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE, 1, 1024, 1024, 0, NULL);
if (m_hPipe == INVALID_HANDLE_VALUE)
{
MessageBox(L"创建命名管道失败");
return;
}
//创建匿名事件对象
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//异步 I/O 操作的参数和状态信息
OVERLAPPED ol = { 0 };
ol.hEvent = hEvent;
//等待客户端的链接
//ConnectNamedPipe 等待客户端有没有连接管道
if (FALSE == ConnectNamedPipe(m_hPipe, &ol))
{
if (GetLastError() != ERROR_IO_PENDING)
{
MessageBox(L"等待客户端链接失败");
return;
}
}
//判断有没有信号
if (WaitForSingleObject(hEvent, INFINITE) == WAIT_FAILED)
{
MessageBox(L"等待对象失败");
CloseHandle(m_hPipe);
CloseHandle(hEvent);
m_hPipe = NULL;
return;
}
CloseHandle(hEvent);
}
void CpipServerDlg::OnBnClickedBtnWrite()
{
wchar_t szBuff[100] = L"12345678";
DWORD dwWrite = 0;
if (FALSE == WriteFile(m_hPipe, szBuff, wcslen(szBuff) * 2 + 1, &dwWrite, NULL))
{
MessageBox(L"写入数据失败", L"错误", MB_ICONERROR);
return;
}
}
void CpipServerDlg::OnBnClickedBtnRead()
{
wchar_t szBuff[100];
DWORD dwRead = 0;
if (FALSE == ReadFile(m_hPipe, szBuff, sizeof(szBuff), &dwRead, NULL))
{
MessageBox(L"读取数据失败", L"错误", MB_ICONERROR);
return;
}
MessageBox(szBuff);
}
客户端代码:
// pipClientDlg.h: 头文件
//
#pragma once
// CpipClientDlg 对话框
class CpipClientDlg : public CDialogEx
{
// 构造
public:
CpipClientDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_PIPCLIENT_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
HANDLE m_hPipe;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedBtnConnect();
afx_msg void OnBnClickedBtnRead();
afx_msg void OnBnClickedBtnWrite();
};
// pipClientDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "pipClient.h"
#include "pipClientDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CpipClientDlg 对话框
CpipClientDlg::CpipClientDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_PIPCLIENT_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CpipClientDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CpipClientDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_Btn_Connect, &CpipClientDlg::OnBnClickedBtnConnect)
ON_BN_CLICKED(IDC_Btn_Read, &CpipClientDlg::OnBnClickedBtnRead)
ON_BN_CLICKED(IDC_Btn_Write, &CpipClientDlg::OnBnClickedBtnWrite)
END_MESSAGE_MAP()
// CpipClientDlg 消息处理程序
BOOL CpipClientDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CpipClientDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CpipClientDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CpipClientDlg::OnBnClickedBtnConnect()
{
//判断有没有可以用的管道
if (FALSE == WaitNamedPipe(L"\\\\.\\pipe\\test", NMPWAIT_WAIT_FOREVER))
{
MessageBox(L"当前没有可以利用的命名管道");
return;
}
//打开管道
//第一个参数:管道名
//第二个参数:读写模式
//第三个参数:共享模式 0表示不共享
//第四个参数:安全属性
//第五个参数:创建方式
//第六个参数:文件属性
//第七个参数:提供文件的拓展属性
m_hPipe = CreateFile(L"\\\\.\\pipe\\test", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (m_hPipe == INVALID_HANDLE_VALUE)
{
MessageBox(L"打开管道失败");
m_hPipe = NULL;
return;
}
}
void CpipClientDlg::OnBnClickedBtnRead()
{
wchar_t szBuff[100];
DWORD dwRead = 0;
if (FALSE == ReadFile(m_hPipe, szBuff, sizeof(szBuff), &dwRead, NULL))
{
MessageBox(L"读取数据失败", L"错误", MB_ICONERROR);
return;
}
MessageBox(szBuff);
}
void CpipClientDlg::OnBnClickedBtnWrite()
{
wchar_t szBuff[100] = L"12345678";
DWORD dwWrite = 0;
if (FALSE == WriteFile(m_hPipe, szBuff, wcslen(szBuff) * 2 + 1, &dwWrite, NULL))
{
MessageBox(L"写入数据失败", L"错误", MB_ICONERROR);
return;
}
}
服务器命名管道的创建
//命名管道
void CServerDlg::OnBnClickedBtnCreate()
{
//第一个参数:名字,名字格式:\\.\pipe\pipename
//第二个参数:打开模式 PIPE_ACCESS_DUPLEX双工模式,FILE_FLAG_OVERLAPPED 在读写过程中会发送一个信号
//第三个参数:管道模式 PIPE_TYPE_MESSAGE 消息的方式
//第四个参数:最大实例个数
//第五个参数:输出的缓冲大小
//第六个参数:输入的缓冲区大小
//第七个参数:默认的超时时间
//第八个参数:安全描述
m_hPipe=CreateNamedPipe(L"\\\\.\\pipe\\test", PIPE_ACCESS_DUPLEX| FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE,1,1024,1024,0,NULL);
if (m_hPipe == INVALID_HANDLE_VALUE)
{
MessageBox(L"创建命名管道失败");
return;
}
//创建匿名事件对象
HANDLE hEvent=CreateEvent(NULL, TRUE, FALSE,NULL);
//异步 I/O 操作的参数和状态信息
OVERLAPPED ol = {0};
ol.hEvent = hEvent;
//等待客户端的链接
//ConnectNamedPipe 等待客户端有没有连接管道
if (FALSE == ConnectNamedPipe(m_hPipe, &ol))
{
if (GetLastError() != ERROR_IO_PENDING)
{
MessageBox(L"等待客户端链接失败");
return;
}
}
//判断有没有信号
if (WaitForSingleObject(hEvent, INFINITE) == WAIT_FAILED)
{
MessageBox(L"等待对象失败");
CloseHandle(m_hPipe);
CloseHandle(hEvent);
m_hPipe = NULL;
return;
}
CloseHandle(hEvent);
}
客户端管道的连接
void CClientDlg::OnBnClickedBtnConnect()
{
//判断有没有可以用的管道
if (FALSE == WaitNamedPipe(L"\\\\.\\pipe\\test", NMPWAIT_WAIT_FOREVER))
{
MessageBox(L"当前没有可以利用的命名管道");
return;
}
//打开管道
//第一个参数:管道名
//第二个参数:读写模式
//第三个参数:共享模式 0表示不共享
//第四个参数:安全属性
//第五个参数:创建方式
//第六个参数:文件属性
//第七个参数:提供文件的拓展属性
CClientDlg::m_hPipe=CreateFile(L"\\\\.\\pipe\\test", GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
if (m_hPipe == INVALID_HANDLE_VALUE)
{
MessageBox(L"打开管道失败");
m_hPipe = NULL;
return;
}
}
运行结果:


浙公网安备 33010602011771号