CreateProcess主进程与子进程管道通信的封装

本类简单的封装了进程的创建,以及管道的读取,主要的用途是用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();













猜你喜欢

转载自blog.csdn.net/wyansai/article/details/78809918