11lxm 发表于 2017-6-28 12:00:21

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

  由于刚弄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, "Read 流创建失效");
28         return;
29   }
30   
31   if (!CreatePipe(&hpiperead2, &hpipewrite2, &ai, 0))//创建读入管道
32   {
33         
34         this->setStatus(-1, "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, " 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, " 线程创建失败 CreateThread LOOP 失败");
56         return;
57   }
58   hThrLoop = CreateThread(NULL, 0, WaitPipe, this, 0, &dwThread);//chuangjian
59   if (hThrLoop == false){
60         this->setStatus(-1, " 线程创建失败 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;
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;      //输出缓冲
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 << " 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;
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;
  结果:

  并且可以进行交互:

  差不多就这样,大神勿喷,我才刚弄C++
页: [1]
查看完整版本: Windows下 C++ 实现匿名管道的读写操作