Win32 命名管道

命名管道简单封装

CNamedPipe.h

#pragma once
#include <string>
#include <windows.h>
#include <tchar.h>#pragma warning(disable:4200)class CNamedPipe
{
public:CNamedPipe();~CNamedPipe();CNamedPipe(const CNamedPipe& r) = delete;CNamedPipe& operator = (const CNamedPipe& r) = delete;//// @brief: 创建命名管道// @param: lpName           管道名// @ret: bool               true: 创建成功 false: 创建失败bool Create(LPCTSTR lpName);//// @brief: 等待客户端连接命名管道// @param: nTimeOut         超时等待(毫秒)// @ret: bool               true: 连接成功 false: 连接失败bool WaitConnect(DWORD nTimeOut = INFINITE);//// @brief: 关闭由Create 创建的管道// @param: void// @ret: bool               true: 关闭 成功 false: 关闭 失败bool Disconnect();//// @brief: 打开已存在的命名管道// @param: lpName           管道名// @ret: bool               true: 打开成功 false: 打开失败bool Open(LPCTSTR lpName, DWORD nTimeOut = INFINITE);//// @brief: 管道是否有效// @param: void// @ret: bool               true: 可用 false: 无效bool IsValid();//// @brief: 关闭管道// @param: void// @ret: voidvoid Close(void);//// @brief: 从读取管道数据// @param: lpData           数据存放缓冲// @param: nSize            缓冲大小(字节)// @param: lpBytesRead      指向实际读取大小(字节)的指针// @param: nTimeOut         读取超时(毫秒)// @ret: bool               true: 读取成功 false: 读取失败bool Read(LPVOID lpData, DWORD nSize, LPDWORD lpBytesRead = nullptr, DWORD nTimeOut = INFINITE);//// @brief: 向管道写入数据// @param: lpData           写入数据指针// @param: nSize            写入数据大小(字节)// @param: lpBytesWritten   指向实际写入大小(字节)的指针// @param: nTimeOut         写入超时(毫秒)// @ret: bool               true: 写入成功 false: 写入失败bool Write(LPCVOID lpData, DWORD nSize, LPDWORD lpBytesWritten = nullptr, DWORD nTimeOut = INFINITE);private://// @brief: 初始化对象占用// @param: void// @ret: voidbool Initialize();//// @brief: 释放对象占用// @param: void// @ret: voidvoid Uninitialize();private:HANDLE m_hNamedPipe;HANDLE m_hReadEvent;HANDLE m_hWriteEvent;LPVOID m_pBuffer;bool m_bInit;bool m_bConnected;
};

CNamedPipe.cpp

#include "CNamedPipe.h"
#include <StrSafe.h>
#include <tchar.h>#define PIPE_NAME_PREFIX             TEXT(R"(\\.\pipe\)")    //管道前缀名
#define PIPE_MAX_TIMEOUT             (3000)                  //管道打开超时
#define PIPE_BUF_MAX_SIZE            (1024 * 1024)           //管道发送缓冲大小(字节)
#define PIPE_MAX_CONNECT             (16)                    //IPC最大连接数typedef struct _PIPE_DATA
{DWORD dwSize = 0;BYTE data[0];
}PIPE_DATA, * PPIPE_DATA;CNamedPipe::CNamedPipe() :m_hNamedPipe(INVALID_HANDLE_VALUE),m_hReadEvent(NULL),m_hWriteEvent(NULL),m_bConnected(false),m_bInit(false)
{//初始化读写缓冲与事件句柄Initialize();
}CNamedPipe::~CNamedPipe()
{//释放读写缓冲与事件句柄Uninitialize();
}bool CNamedPipe::Create(LPCTSTR lpName)
{TCHAR szPipeName[MAX_PATH];SECURITY_ATTRIBUTES sa = { 0 };SECURITY_DESCRIPTOR sd = { 0 };bool isSuccess = false;sa.nLength = sizeof(sa);sa.bInheritHandle = FALSE;sa.lpSecurityDescriptor = &sd;if (INVALID_HANDLE_VALUE != m_hNamedPipe){return true;}//设置权限, 防止低权限进程不能打开高权限进程创建的管道(void)::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);(void)::SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);(void)::StringCchPrintf(szPipeName, _countof(szPipeName), TEXT("%s%s"), PIPE_NAME_PREFIX, lpName);do{m_hNamedPipe = ::CreateNamedPipe(szPipeName,PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,PIPE_MAX_CONNECT,PIPE_BUF_MAX_SIZE,PIPE_BUF_MAX_SIZE,PIPE_MAX_TIMEOUT,&sa);if (INVALID_HANDLE_VALUE == m_hNamedPipe){break;}isSuccess = true;} while (false);if (!isSuccess){this->Close();}return isSuccess;
}bool CNamedPipe::Open(LPCTSTR lpName, DWORD nTimeOut/* = INFINITE*/)
{TCHAR szPipeName[MAX_PATH] = { 0 };bool isSuccess = false;(void)::StringCchPrintf(szPipeName, _countof(szPipeName), TEXT("%s%s"), PIPE_NAME_PREFIX, lpName);if (INVALID_HANDLE_VALUE != m_hNamedPipe){return true;}ULONGLONG ullCurTick = ::GetTickCount64();do{m_hNamedPipe = ::CreateFile(szPipeName,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL);//管道句柄有效则终止循环if (INVALID_HANDLE_VALUE != m_hNamedPipe){isSuccess = true;break;}//若错误原因不是因为所有管道范例都在使用中, 则退出循环if (ERROR_PIPE_BUSY != ::GetLastError()){break;}//等待命名管道的实例可用于连接if (::WaitNamedPipe(szPipeName, 1000)){continue;}//无限等待则不需要检查超时if (INFINITE == nTimeOut){continue;}//执行操作超时则退出循环if (::GetTickCount64() - ullCurTick > nTimeOut){break;}} while (INVALID_HANDLE_VALUE == m_hNamedPipe);if (!isSuccess){this->Close();}return isSuccess;
}bool CNamedPipe::WaitConnect(DWORD nTimeOut)
{OVERLAPPED Overlapped = { 0 };bool isConnected = false;if (INVALID_HANDLE_VALUE == m_hNamedPipe){return false;}Overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);if (NULL == Overlapped.hEvent){return false;}isConnected = ::ConnectNamedPipe(m_hNamedPipe, &Overlapped);if (!isConnected){DWORD dwError = ::GetLastError();//管道关闭中if (ERROR_NO_DATA == dwError){isConnected = false;}//操作处于挂起状态if (ERROR_IO_PENDING == dwError){if (WAIT_OBJECT_0 == ::WaitForSingleObject(Overlapped.hEvent, nTimeOut)){isConnected = true;}}//管道已经连接if (ERROR_PIPE_CONNECTED == dwError){isConnected = true;}}if (NULL != Overlapped.hEvent){::CloseHandle(Overlapped.hEvent);}m_bConnected = isConnected;return isConnected;
}bool CNamedPipe::Disconnect()
{if (INVALID_HANDLE_VALUE == m_hNamedPipe){return false;}//参数句柄必须由 CreateNamedPipe 函数创建return ::DisconnectNamedPipe(m_hNamedPipe);
}void CNamedPipe::Close()
{if (INVALID_HANDLE_VALUE != m_hNamedPipe){if (m_bConnected){::FlushFileBuffers(m_hNamedPipe);::DisconnectNamedPipe(m_hNamedPipe);m_bConnected = false;}::CloseHandle(m_hNamedPipe);m_hNamedPipe = INVALID_HANDLE_VALUE;}
}bool CNamedPipe::IsValid()
{return INVALID_HANDLE_VALUE != m_hNamedPipe;
}bool CNamedPipe::Read(LPVOID lpData, DWORD nSize, LPDWORD lpBytesRead/* = nullptr*/, DWORD nTimeOut)
{OVERLAPPED Overlapped = { 0 };Overlapped.hEvent = m_hReadEvent;DWORD dwBytesTransferred = 0;bool isSuccess = false;if (nullptr == m_pBuffer ||nullptr == lpData ||0 == nSize ||nSize > PIPE_BUF_MAX_SIZE){return false;}PPIPE_DATA pData = (PPIPE_DATA)m_pBuffer;if (!::ReadFile(m_hNamedPipe, &pData->dwSize, sizeof(PIPE_DATA), NULL, &Overlapped)){//管道已结束if (ERROR_BROKEN_PIPE == ::GetLastError()){return false;}if (ERROR_IO_PENDING != ::GetLastError()){return false;}if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut)){return false;}}if (pData->dwSize > PIPE_BUF_MAX_SIZE){return false;}if (!::ReadFile(m_hNamedPipe, pData->data, pData->dwSize, NULL, &Overlapped)){if (ERROR_IO_PENDING != ::GetLastError()){return false;}if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut)){return false;}}if (::GetOverlappedResult(m_hNamedPipe, &Overlapped, &dwBytesTransferred, true)){isSuccess = true;if (lpBytesRead){*lpBytesRead = dwBytesTransferred;}}if (isSuccess){if (nSize < pData->dwSize){::memcpy_s(lpData, nSize, pData->data, nSize);}else{::memcpy_s(lpData, nSize, pData->data, pData->dwSize);}}return isSuccess;
}bool CNamedPipe::Write(LPCVOID lpData, DWORD nSize, LPDWORD lpBytesWritten/* = nullptr*/, DWORD nTimeOut)
{OVERLAPPED Overlapped = { 0 };Overlapped.hEvent = m_hWriteEvent;DWORD dwBytesTransferred = 0;bool isSuccess = false;if (nullptr == m_pBuffer ||nullptr == lpData ||0 == nSize ||nSize > PIPE_BUF_MAX_SIZE){return false;}PPIPE_DATA pData = (PPIPE_DATA)m_pBuffer;DWORD dwBytesToWrite = nSize + sizeof(PIPE_DATA);pData->dwSize = nSize;::memcpy_s(pData->data, PIPE_BUF_MAX_SIZE, lpData, nSize);if (::WriteFile(m_hNamedPipe, pData, dwBytesToWrite, NULL, &Overlapped)){return true;}//管道正在被关闭if (ERROR_NO_DATA == ::GetLastError()){return false;}//管道已结束if (ERROR_BROKEN_PIPE == ::GetLastError()){return false;}//重叠if (ERROR_IO_PENDING != ::GetLastError()){return false;}if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut)){return false;}if (::GetOverlappedResult(m_hNamedPipe, &Overlapped, &dwBytesTransferred, true)){isSuccess = true;if (lpBytesWritten){*lpBytesWritten = dwBytesTransferred;}}return isSuccess;
}bool CNamedPipe::Initialize()
{bool isSuccess = false;if (m_bInit){return true;}do{if (nullptr == m_pBuffer){m_pBuffer = ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, PIPE_BUF_MAX_SIZE + sizeof(PIPE_DATA));}if (nullptr == m_pBuffer){break;}if (NULL == m_hReadEvent){m_hReadEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);}if (NULL == m_hReadEvent){break;}if (NULL == m_hWriteEvent){m_hWriteEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);}if (NULL == m_hWriteEvent){break;}isSuccess = true;} while (false);if (!isSuccess){Uninitialize();}m_bInit = isSuccess;return m_bInit;
}void CNamedPipe::Uninitialize()
{if (!m_bInit){return;}//关闭管道this->Close();//释放读写缓冲if (nullptr != m_pBuffer){::HeapFree(::GetProcessHeap(), 0, m_pBuffer);m_pBuffer = nullptr;}//关闭事件if (m_hReadEvent){CloseHandle(m_hReadEvent);m_hReadEvent = NULL;}if (m_hWriteEvent){CloseHandle(m_hWriteEvent);m_hWriteEvent = NULL;}m_bInit = false;
}

main.cpp

#include <iostream>
#include "Utils/CNamedPipe.h"
#include <thread>
#include <future>int main()
{std::promise<bool> p;std::future<bool> f = p.get_future();std::thread([&p]() {static char szBuf[1024 * 64] = { 0 };CNamedPipe pipe;if (!pipe.Create(_T("FlameCyclone"))){std::cout << "Create failed!" << std::endl;p.set_value(false);return;}p.set_value(true);if (!pipe.WaitConnect()){std::cout << "WaitConnect failed!" << std::endl;return;}while (true){bool isSuccess = pipe.Read(szBuf, sizeof(szBuf));if (isSuccess){std::cout << "recv: " << szBuf << std::endl;}//另一端断开则重新等待连接if (ERROR_BROKEN_PIPE == ::GetLastError()){pipe.Disconnect();if (!pipe.WaitConnect()){std::cout << "WaitConnect failed!" << std::endl;return;}}}}).detach();if (!f.get()){return -1;}CNamedPipe pipe;if (!pipe.Open(_T("FlameCyclone"), 5000)){std::cout << "Open failed!" << std::endl;return -1;}std::string strMsg;while (true){std::cin >> strMsg;std::cout << "send: " << strMsg << std::endl;if (!pipe.Write(strMsg.c_str(), strMsg.size() + 1)){std::cout << "Write failed!" << std::endl;break;}}system("pause");return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/115322.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙状态栏设置

鸿蒙状态栏设置 基于鸿蒙 ArkTS API9&#xff0c;设置状态栏颜色&#xff0c;隐藏显示状态栏。 API参考文档 参考文档 新建项目打开之后发现状态栏是黑色的&#xff0c;页面颜色设置完了也不能影响状态栏颜色&#xff0c;如果是浅色背景&#xff0c;上边有个黑色的头&#…

众和策略:题材股什么意思?

题材股是股票商场上的一个术语&#xff0c;许多刚接触股票出资的人可能对它不太熟悉。那么&#xff0c;题材股什么意思呢&#xff1f;在本文中&#xff0c;咱们将从多个角度剖析这个问题&#xff0c;帮忙读者更好地了解。 一、什么是题材股 题材股是指某个工作或主题的股票集结…

机器学习笔记 - 深度学习中跳跃连接的直观解释

一、概述 如今人们利用深度学习做无数的应用。然而,为了理解在许多作品中看到的大量设计选择(例如跳过连接),了解一点反向传播机制至关重要。 如果你在 2014 年尝试训练神经网络,你肯定会观察到所谓的梯度消失问题。简单来说:你在屏幕后面检查网络的训练过程,你看到的只…

跨越单线程限制:Thread类的魅力,引领你进入Java并发编程的新纪元

线程的概述 线程是一个程序的多个执行路径&#xff0c;执行调度的单位&#xff0c;依托于进程存在。 线程不仅可以共享进程的内存&#xff0c;而且还拥有一个属于自己的内存空间&#xff0c;这段内存空间也叫做线程栈&#xff0c;是在建立线程时由系统分配的&#xff0c;主要用…

【C++】不是用new生成的对象调用析构函数

2023年10月23日&#xff0c;周一上午 #include <iostream>class Book{ private:int price; public:~Book(){std::cout<<"调用析构函数"<<std::endl; } };int main(){Book b1;b1.~Book(); } 从运行结果可以看出&#xff1a; 手动调用b1.~Book()时&…

Python笔记

Python基础 一、数据类型 类型值文本类型str数值类型int&#xff0c;float&#xff0c;complex序列类型list&#xff0c;tuple&#xff0c;range映射类型dict集合类型set&#xff0c;frozenset布尔类型bool二进制类型bytes&#xff0c;bytearray&#xff0c;memoryview 1.基…

Leetcode 第 364 场周赛题解

Leetcode 第 364 场周赛题解 Leetcode 第 364 场周赛题解题目1&#xff1a;2864. 最大二进制奇数思路代码复杂度分析 题目2&#xff1a;美丽塔 I思路代码复杂度分析 题目3&#xff1a;美丽塔 II思路代码复杂度分析 题目4&#xff1a;统计树中的合法路径数目思路代码复杂度分析 …

机器人系统 ROS 常用命令行工具

1. 启动ros 主节点 roscore roscore运行成功如图&#xff1a; 1.1 rosrun 启动服务节点 例子&#xff1a;启动一个小乌龟节点 rosrun turtlesim turtlesim_node运行结果如图&#xff1a; 1.2 启动键盘控制 打开新的命令窗口&#xff0c;启动turtle_teleop_key 节点 rosr…

单窗口单IP适合炉石传说游戏么?

游戏道具制作在炉石传说中是一个很有挑战的任务&#xff0c;但与此同时&#xff0c;它也是一个充满机遇的领域。在这篇文章中&#xff0c;我们将向您展示如何在炉石传说游戏中使用动态包机、多窗口IP工具和动态IP进行游戏道具制作。 作者与主题的关系&#xff1a;作为一名热爱炉…

JSX看着一篇足以入门

JSX 介绍 学习目标&#xff1a; 能够理解什么是 JSX&#xff0c;JSX 的底层是什么 概念&#xff1a; JSX 是 javaScriptXML(HTML) 的缩写&#xff0c;表示在 JS 代码中书写 HTML 结构 作用&#xff1a; 在 React 中创建 HTML 结构&#xff08;页面 UI 结构&#xff09; 优势&a…

监控易一体化运维:打造机房环境监控的卓越典范

随着信息技术的飞速发展&#xff0c;机房作为企业数据和业务的中心&#xff0c;其运行状态和管理的重要性日益凸显。为确保机房的稳定性和可靠性&#xff0c;越来越多的企业选择使用一体化运维管理软件来进行实时监控。在这方面&#xff0c;监控易品牌提供了一款全面而高效的机…

VM虚拟机 13.5 for Mac

VMware Fusion Pro for Mac是一款强大的虚拟机软件&#xff0c;可以在Mac操作系统中创建、运行和管理多个虚拟机&#xff0c;使用户可以在一台Mac电脑上同时运行多个操作系统和应用程序。 以下是VMware Fusion Pro for Mac的主要特点&#xff1a; 1. 支持多种操作系统&#xff…

【数据结构】线性表(九)队列:链式队列及其基本操作(初始化、判空、入队、出队、存取队首元素)

文章目录 一、队列1. 定义2. 基本操作 二、顺序队列三、链式队列0. 链表1. 头文件2. 队列结构体3. 队列的初始化4. 判断队列是否为空5. 入队6. 出队7. 存取队首元素8. 主函数9. 代码整合 堆栈Stack 和 队列Queue是两种非常重要的数据结构&#xff0c;两者都是特殊的线性表&…

【Java 进阶篇】深入浅出:Bootstrap 轮播图

在现代网页设计中&#xff0c;轮播图是一个常见的元素。它们可以用于展示图片、广告、新闻、产品或任何您希望吸引用户注意力的内容。要实现一个轮播图&#xff0c;您通常需要一些复杂的HTML、CSS和JavaScript代码&#xff0c;这对于初学者来说可能会感到困难。但幸运的是&…

React环境初始化

环境初始化 学习目标&#xff1a; 能够独立使用React脚手架创建一个React项目 1.使用脚手架创建项目 官方文档&#xff1a;(https://create-react-app.bootcss.com/)    - 打开命令行窗口    - 执行命令      npx create-react-app projectName    说明&#xff1a…

四、网络请求与路由

一、网络请求 1、Axios请求 Axios是一个基于promise的网络请求库 &#xff08;1&#xff09;安装 npm install --save axios&#xff08;2&#xff09;引入 import axios from "axios"全局引入 import axios from "axios" import { createApp } from …

Github 2FA绑定中国+86手机号码实现两步验证

GitHub宣布&#xff0c;到 2023 年底&#xff0c;所有用户都必须要启用双因素身份验证 (2FA)&#xff0c;不能只用密码. GitHub开启2FA后&#xff0c;除了输入密码外&#xff0c;还需要通过一次性密码&#xff08;OTP&#xff09;等方式做第二级身份验证&#xff0c;才能成功登…

靶机 DC_1

DC_1 信息搜集 存活检测 详细扫描 网页目录扫描 网页信息搜集 cms 为 Drupal 漏洞利用 使用 msf 搜索 drupal 的漏洞 启动 msfconsole搜索 search drupal尝试编号为 0 的漏洞 失败 利用编号为 1 的漏洞 use 1查看需要配置的选项 show options设置目标 ip set rhost 10…

监控易101:全方位解读运维的核心功能与特性

在数字化时代&#xff0c;企业IT环境的复杂性日益增加&#xff0c;给运维工作带来了前所未有的挑战。面对这一情况&#xff0c;监控易作为一款一体化运维监控管理平台&#xff0c;凭借其全面的监控覆盖、智能的告警机制、强大的数据分析工具以及灵活的扩展能力&#xff0c;赢得…

【Linxu工具】:vim使用及简单配置

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关Linux工具&#xff1a;vim的使用&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从…