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, "[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;

结果:

并且可以进行交互:

 

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

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM