本类简单的封装了进程的创建,以及管道的读取,主要的用途是用c++调用php与python脚本时进行通信。
从管道读取内容的时候,必须预定规则,比如读取一行,行尾的标识符是'\n'还是'\t'之类的,不约定的话,会造成管道阻塞。
向管道写入内容的时候,如果python脚本没有收到回车符'\n',它也会阻塞,所以写入内容的结束符,最好也约定好。
封装类CProcess如下:
头文件Process.h
#pragma once #include "tchar.h" #include "windows.h" class CProcess { public: // 管道类型 enum PipeType { pIn, pOut, pErr }; // 读写方式 enum Direction { Read, Write }; // 程序执行的方式 enum ExecType { ASYNC, SYNC }; CProcess(); CProcess(ExecType execType); ~CProcess(); // 创建一个指定执行方式的进程类 BOOL Create(ExecType execType); // 执行脚本 BOOL Execute(LPCTSTR Command); // 进程类是否正常 BOOL IsOk() { return m_hPipes[pIn][Write] != INVALID_HANDLE_VALUE;} // 获取进程id DWORD GetPid() { return m_dwProcessId; } // 从管道读取一行 size_t ReadLine(LPVOID lpBuffer,size_t len,char seq = '\n'); // 向管道写入 size_t WriteSome(LPVOID lpBuffer, size_t len); protected: BOOL CreatePipes(); void ClosePipes(); private: DWORD m_dwProcessId; HANDLE m_hPipes[3][2]; ExecType m_execType; };
源文件Process.cpp
#include "Process.h" CProcess::CProcess() { m_dwProcessId = 0; m_execType = SYNC; // 初始化管道句柄为空句柄 for (int i = 0; i < _countof(m_hPipes);++i) for (int j = 0; j < _countof(m_hPipes[i]);++j) m_hPipes[i][j] = INVALID_HANDLE_VALUE; } CProcess::CProcess(ExecType execType) :CProcess() { if (!Create(execType)) ClosePipes(); } CProcess::~CProcess() { ClosePipes(); } BOOL CProcess::Create(ExecType execType) { BOOL bRet = TRUE; bRet |= CreatePipes(); m_execType = execType; return bRet; } BOOL CProcess::Execute(LPCTSTR Command) { BOOL bRet = TRUE; STARTUPINFO si; ZeroMemory(&si,sizeof(si)); si.cb = sizeof(si); si.hStdInput = m_hPipes[pIn][Read]; si.hStdOutput = m_hPipes[pOut][Write]; si.hStdError = m_hPipes[pErr][Write]; si.wShowWindow = SW_HIDE; si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; PROCESS_INFORMATION pi; TCHAR cmd[MAX_PATH]; _tcscpy_s(cmd,_countof(cmd), Command); bRet |= ::CreateProcess(NULL, cmd, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi); if (!bRet) { ClosePipes(); return FALSE; } m_dwProcessId = pi.dwProcessId; // 关闭不要的读写句柄 ::CloseHandle(m_hPipes[pIn][Read]); m_hPipes[pIn][Read] = INVALID_HANDLE_VALUE; ::CloseHandle(m_hPipes[pOut][Write]); m_hPipes[pOut][Write] = INVALID_HANDLE_VALUE; ::CloseHandle(m_hPipes[pErr][Write]); m_hPipes[pErr][Write] = INVALID_HANDLE_VALUE; if(m_execType == SYNC) WaitForSingleObject(pi.hProcess, INFINITE); ::CloseHandle(pi.hProcess); ::CloseHandle(pi.hThread); return bRet; } size_t CProcess::ReadLine(LPVOID lpBuffer, size_t len, char seq) { if (!IsOk()) return 0; DWORD totalRead = 0; DWORD bytesRead; char * buffer = new char[len + 1]; ZeroMemory(buffer,len + 1); char ch; do { if (!::ReadFile(m_hPipes[pOut][Read], &ch, 1, &bytesRead, NULL)) break; buffer[totalRead] = ch; ++totalRead; } while (bytesRead == 1 && ch != seq && totalRead < len + 1); if (totalRead > 0) strcpy_s((char*)lpBuffer, len, buffer); delete[] buffer; return totalRead; } size_t CProcess::WriteSome(LPVOID lpBuffer, size_t len) { if (!IsOk()) return 0; DWORD totalWritten = 0; while (len > 0) { DWORD chunkWritten; if (!::WriteFile(m_hPipes[pIn][Write], lpBuffer, len, &chunkWritten, NULL)) break; if (!chunkWritten) break; lpBuffer = (char *)lpBuffer + chunkWritten; totalWritten += chunkWritten; len -= chunkWritten; } return totalWritten; } BOOL CProcess::CreatePipes() { BOOL bRet = TRUE; for (int i = 0; i < pOut + 1; ++i) { SECURITY_ATTRIBUTES security; security.nLength = sizeof(security); security.lpSecurityDescriptor = NULL; security.bInheritHandle = TRUE; bRet |= ::CreatePipe(&m_hPipes[i][Read], &m_hPipes[i][Write], &security, 0); } bRet |= ::SetHandleInformation(m_hPipes[pIn][Write], HANDLE_FLAG_INHERIT, 0); bRet |= ::SetHandleInformation(m_hPipes[pOut][Read], HANDLE_FLAG_INHERIT, 0); bRet |= ::SetHandleInformation(m_hPipes[pErr][Read], HANDLE_FLAG_INHERIT, 0); return bRet; } void CProcess::ClosePipes() { for (int i = 0; i < _countof(m_hPipes); ++i) { for (int j = 0; j < _countof(m_hPipes[i]); ++j) { if (m_hPipes[i][j] != INVALID_HANDLE_VALUE) { ::CloseHandle(m_hPipes[i][j]); m_hPipes[i][j] = INVALID_HANDLE_VALUE; } } } }
以php脚本为例的使用说明:
脚本内容如下:
<?php fwrite(STDOUT, "Enter your name: \n"); $name = trim(fgets(STDIN)); echo $name,"\n";
c++中,使用的代码如下:
CProcess * process = new CProcess(CProcess::ASYNC); if (!process->Execute(_T("php D:/test.php"))) { cout << "程序启动失败" << endl; return; }然后,开启一个线程,进行读写,因为是异步创建的进程
thread([process]() { char ch[MAX_PATH]; memset(ch, 0, MAX_PATH); do { size_t bytesRead = process->ReadLine(ch, sizeof(ch)); if (bytesRead == 0) break; cout << ch << endl; if (ch[bytesRead - 1] == '\n') break; } while (true); memset(ch, 0, MAX_PATH); sprintf_s(ch, "wangy\n"); process->WriteSome(ch, sizeof(ch)); delete process; }).detach();