Windows下 C++ 实现匿名管道的读写操作

时间:2024-11-13 18:04:26

由于刚弄C++没多久,部分还不熟练,最近又由于开发需求要求实现与其他程序进行通信,瞬间就感觉想到了匿名通信。于是自己查阅了一下资料,实现了一个可读可写的匿名管道:

源代码大部分都有注释:

Pipe.h 文件

#pragma once
#include <iostream>
#include <windows.h>
using namespace std; class Pipe // 不可移植类,只限于 WindowsXP 以上 平台
{
private:
HANDLE hpiperead = NULL;   //读入 匿名管道
HANDLE hpipewrite = NULL; //读入 匿名管道
HANDLE hpiperead2 = NULL;   //写出 匿名管道
HANDLE hpipewrite2 = NULL; //写出 匿名管道
HANDLE hProHandle = NULL;
HANDLE hThrLoop = NULL;
HANDLE hThrisLoop = NULL;
SECURITY_ATTRIBUTES ai; //安全属性
PROCESS_INFORMATION pi; //进程信息
STARTUPINFOA si;
BOOL pipe = false;
INT status = 1; // 0 = 异常 1 = 正常 -1 = 错误 、
string errorString;
public:
void loop() ; //循环
void isloop() ; //循环
const BOOL isPipeOff() const; //管道是否是开启
const INT getStatus() const; //获取当前状况
const string & getError() const; //获取当前错误信息
const BOOL sendCommand(const char *); //执行命令
void setPipeOn(const BOOL); //设置管道是否开启
void setStatus(const INT, const char*); //用于设置错误信息
void setStatus(const INT); //重载,用于设置状态
Pipe( char * str); //管道执行的命令
~Pipe();
};

Pipe.cpp 文件

  1 #include "Pipe.h"
2
3
4 DWORD __stdcall ThrPipeThreadRead(void *www)
5 {
6 Pipe * pipe = (Pipe *)www;
7 pipe->loop();
8 return 0;
9 //创建内核对象使用完之后一定记得关闭,有可能会产生内存泄露
10 }
11 DWORD __stdcall WaitPipe(void *www)
12 {
13 Pipe * pipe = (Pipe *)www;
14 pipe->isloop();
15 return 0;
16 }
17
18
19 Pipe::Pipe( char * com)
20 {
21 ai.nLength = sizeof(SECURITY_ATTRIBUTES);
22 ai.bInheritHandle = true;
23 ai.lpSecurityDescriptor = NULL;
24 if (!CreatePipe(&hpiperead, &hpipewrite, &ai, 0)) //创建读入管道
25 {
26
27 this->setStatus(-1, "[0x01]Read 流创建失效");
28 return;
29 }
30
31 if (!CreatePipe(&hpiperead2, &hpipewrite2, &ai, 0)) //创建读入管道
32 {
33
34 this->setStatus(-1, "[0x02]Write 流创建失效");
35 return;
36 }
37 GetStartupInfoA(&si); //获取当前进程的STARTUPINFO
38 si.cb = sizeof(STARTUPINFO);
39 si.hStdError = hpipewrite;
40 si.hStdOutput = hpipewrite;
41 si.hStdInput = hpiperead2;
42 si.wShowWindow = SW_SHOW;
43 si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
44
45 if (!(CreateProcessA(NULL, com, NULL, NULL, true, NULL, NULL, NULL, &si, &pi))) //创建隐藏的CMD进程
46 {
47 this->setStatus(-1, "[0x03] CreateProcess函数执行出错");
48 return;
49 }
50
51
52 DWORD dwThread = FALSE;
53 hThrLoop = CreateThread(NULL, 0, ThrPipeThreadRead, this, 0, &dwThread);//chuangjian
54 if (hThrLoop == false){
55 this->setStatus(-1, "[0x11] 线程创建失败 CreateThread LOOP 失败");
56 return;
57 }
58 hThrLoop = CreateThread(NULL, 0, WaitPipe, this, 0, &dwThread);//chuangjian
59 if (hThrLoop == false){
60 this->setStatus(-1, "[0x12] 线程创建失败 CreateThread ISLOOP失败");
61 return;
62 }
63 }
64
65
66
67
68 Pipe::~Pipe()
69 {
70 //创建内核对象使用完之后一定记得关闭,有可能会产生内存泄露
71 this->setPipeOn(false);
72 this->setStatus(-1);
73 CloseHandle(hThrisLoop);
74 CloseHandle(hThrLoop);
75 CloseHandle(hpipewrite);
76 CloseHandle(hpiperead);
77 CloseHandle(hpiperead2);
78 CloseHandle(hpipewrite2);
79 CloseHandle(pi.hProcess);
80 CloseHandle(pi.hThread);
81
82 }
83 const INT Pipe::getStatus() const
84 {
85 return this->status;
86 }
87
88 const string & Pipe::getError() const
89 {
90 return this->errorString;
91 }
92
93 const BOOL Pipe::isPipeOff() const
94 {
95 return pipe;
96 }
97
98 void Pipe::setPipeOn(const BOOL bools)
99 {
100 this->pipe = bools;
101 }
102
103 void Pipe::setStatus(const INT status, const char * info)
104 {
105 this->errorString = info; //你说会不会有更好的赋值方法?
106 this->status = status;
107 }
108
109 void Pipe::setStatus(const INT status = 1)
110 {
111 this->status = status;
112 }
113
114 const BOOL Pipe::sendCommand(const char * com) //执行命令
115 {
116 DWORD dwWrite = 0;
117 char www[1024];
118 strcpy_s(www,com);
119 strcat_s(www,"\n");
120 return WriteFile(hpipewrite2, www, strlen(www), &dwWrite, NULL);
121 //0x001C7796 处有未经处理的异常(在 ConsoleApplication2.exe 中): 0xC0000005: 读取位置 0x0000000C 时发生访问冲突。
122 }
123
124 void Pipe::loop(){
125 char outbuff[4096]; //输出缓冲
126 DWORD byteread;
127 this->setPipeOn(true);
128 while (true)
129 {
130 memset(outbuff, '\0', 4096);
131 if (ReadFile(this->hpiperead, outbuff, 4095, &byteread, NULL) == NULL)
132 {
133 this->setPipeOn(false);
134 break;
135 }
136 printf("%s", outbuff);
137 memset(outbuff, '\0', 4096);
138 }
139 this->setPipeOn(false);
140 std::cout << "Pipe Stoped!"<<endl;
141 }
142
143 void Pipe::isloop()
144 {
145 DWORD dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
146 while (dwRet == WAIT_TIMEOUT)
147 {
148 dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
149 }
150
151 if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED)
152 {
153 this->setPipeOn(false);
154 std::cout << "[END] Pipe Stoped!" << endl;
155 }
156 }

Luncher.cpp

 1 // ConsoleApplication2.cpp : 定义控制台应用程序的入口点。
2 //
3 #include <windows.h>
4 #include <thread>
5 #include "Pipe.h"
6 using namespace std;
7
8 void read();
9 void Loop();
10
11 Pipe * pipe; //属于全局变量
12
13
14 int Luncher()  //那个啥,你就是当作这是Main文件的Main方法不
15 {
16 thread t1(read);    //需要C++11标准
17 thread t2(Loop);
18
19 pipe = new Pipe("cmd");
20 t1.join();
21 t2.join();
22 return 0;
23 }
24 void read(){
25
26 while (true){
27 char str[200];
28 cin >> str;
29 pipe->sendCommand(str);  //提交命令
30 }
31 }
32
33 void Loop(){
34 while (true)
35 {
36 Sleep(1000);
37 if (pipe->getStatus() == -11)
38 {
39 cout << " ERROR " << endl;
40 return;
41 }
42 }
43 }

这样即可实现 与任何程序进行交互:当然了也可以不仅仅是 输入输出

我们这里执行cmd;

结果:

Windows下 C++  实现匿名管道的读写操作

并且可以进行交互:

Windows下 C++  实现匿名管道的读写操作

差不多就这样,大神勿喷,我才刚弄C++