#include "stdafx.h"
#include "CProcess.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;
			}
		}
	}
}