win32processioredirector.cpp

来自「这是VCF框架的代码」· C++ 代码 · 共 600 行 · 第 1/2 页

CPP
600
字号
//Win32ProcessIORedirector.cpp/*Copyright 2000-2004 The VCF Project.Please see License.txt in the top level directorywhere you installed the VCF.*/#include "vcf/FoundationKit/FoundationKit.h"#include "vcf/FoundationKit/ProcessWithRedirectedIO.h"#include "vcf/FoundationKit/Win32ProcessIORedirector.h"using namespace VCF;Win32ProcessIORedirector::Win32ProcessIORedirector():	childProcess_(NULL),	processID_(0),	process_(NULL),	processThreadID_(0),	readThreadID_(0),	readThread_(NULL),	childStdinRdHandle_(NULL),	childStdinWrHandle_(NULL),	childStdoutRdHandle_(NULL),	childStdoutWrHandle_(NULL),	savedStdinHandle_(NULL),	savedStdoutHandle_(NULL),	canContinueReading_(false),	startInfoPtr_(NULL){	memset( &processInfo_, 0, sizeof(processInfo_) );	if ( System::isUnicodeEnabled() ) {		startInfoPtr_ = new STARTUPINFOW;		memset( startInfoPtr_, 0, sizeof(STARTUPINFOW) );		((STARTUPINFOW*)startInfoPtr_)->cb = sizeof(STARTUPINFOW);	}	else {		startInfoPtr_ = new STARTUPINFOA;		memset( startInfoPtr_, 0, sizeof(STARTUPINFOA) );		((STARTUPINFOA*)startInfoPtr_)->cb = sizeof(STARTUPINFOA);	}}Win32ProcessIORedirector::~Win32ProcessIORedirector(){	canContinueReading_ = false;	WaitForSingleObject( readThread_, INFINITE );	CloseHandle( readThread_ );	readThread_ = NULL;	if (processID_ != DWORD(-1))	{		DWORD dwExitCode;		HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID_);		// if the process handle is INVALID_HANDLEVALUE or		// the process handle is valid but ExitCode is set		if (!hProcess || (hProcess && GetExitCodeProcess(hProcess, &dwExitCode))) {			processID_ = DWORD(-1);		}		else			if ( !CloseHandle(hProcess)) {				throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(hProcess)"));			}	}	if ( System::isUnicodeEnabled() ) {		delete ((STARTUPINFOW*)startInfoPtr_);	}	else {		delete ((STARTUPINFOA*)startInfoPtr_);	}}bool Win32ProcessIORedirector::testProcess(){	if (processID_ != DWORD(-1))	{		HANDLE hProcess = this->childProcess_;//::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID_);		if (hProcess) {			DWORD exitCode;			BOOL bRet =  GetExitCodeProcess(hProcess, &exitCode);//WaitForSingleObject(hProcess,0);// 	// fails when the process is active			//if  (!CloseHandle(hProcess)) {			//	throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(hProcess)"));		//	}			return (exitCode == STILL_ACTIVE) ? true : false;		}	}	return false;}void Win32ProcessIORedirector::readPipe(){	DWORD bytesRead = 0;	const int BUFSIZE = 256;	char readBuffer[BUFSIZE+1];	DWORD bytesLeftToRead = 1;	while ( bytesLeftToRead > 0 ) {		if (!ReadFile(childStdoutRdHandle_, readBuffer, BUFSIZE, &bytesRead, NULL) || bytesRead == 0)  {			if (::GetLastError() == ERROR_BROKEN_PIPE)				break;			else				VCF_ASSERT2(false, "ReadFile failed");		}		readBuffer[bytesRead/sizeof(char)] = 0;		//notify folks of an OutputReady event		String outputData = readBuffer;		OutputReadyEvent event( process_, outputData );		process_->OutputReady.fireEvent( &event );		Sleep(100);		int err = PeekNamedPipe( childStdoutRdHandle_, NULL, 0, NULL, &bytesLeftToRead, NULL);		if ( !err || bytesLeftToRead == 0 ) {			if( !testProcess() ) {				//break;				bytesLeftToRead = 0;			}			else {				bytesLeftToRead = 1;			}		}	}	if ( bytesLeftToRead > 0 ) {		//do one last read		if (!ReadFile(childStdoutRdHandle_, readBuffer, BUFSIZE, &bytesRead, NULL) || bytesRead == 0)  {			if (::GetLastError() != ERROR_BROKEN_PIPE) {				//??????			}		}		readBuffer[bytesRead/sizeof(char)] = 0;		//notify folks of an OutputReady event		String outputData = readBuffer;		OutputReadyEvent event( process_, outputData );		process_->OutputReady.fireEvent( &event );	}	if ( !CloseHandle(childStdinRdHandle_) ) {		throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(pThis->hChildStdinRd_)"));	}	if ( !CloseHandle(childStdoutWrHandle_)) {		throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(pThis->childStdoutWrHandle_)"));	}	if ( !CloseHandle(childStdinWrHandle_)){		throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(pThis->hChildStdinWr_)"));	}	if ( !CloseHandle(childStdoutRdHandle_)){		throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(pThis->childStdoutRdHandle_)"));	}}UINT __stdcall Win32ProcessIORedirector::ReadPipeThreadProc(LPVOID pParam){	UINT result = 0;	Win32ProcessIORedirector* thisPtr = (Win32ProcessIORedirector*)pParam;	thisPtr->readPipe();	return result;}bool Win32ProcessIORedirector::createProcess( const String& processName, const String& arguments ){	bool result = false;	canContinueReading_ = true;	commandLine_ = processName + " " + arguments;	if ( NULL != readThread_ ) {		::WaitForSingleObject( readThread_, INFINITE );		::CloseHandle( readThread_ );		if ( !::CloseHandle(childStdinRdHandle_) ){			throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(childStdinRdHandle_) failed"));		}		if ( !::CloseHandle(childStdoutWrHandle_) ) {			throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(childStdoutWrHandle_) failed"));		}		if ( !::CloseHandle(childStdinWrHandle_) ){			throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(childStdinWrHandle_) failed"));		}		if ( !::CloseHandle(childStdoutRdHandle_) ) {			throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(childStdoutRdHandle_) failed"));		}		readThread_ = NULL;	}	HANDLE hChildStdoutRdTmp, hChildStdinWrTmp;	SECURITY_ATTRIBUTES saAttr;	memset( &saAttr, 0, sizeof(saAttr) );	BOOL bSuccess;	// Set the bInheritHandle flag so pipe handles are inherited.	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);	saAttr.bInheritHandle = TRUE;	saAttr.lpSecurityDescriptor = NULL;	//from Andreas notes	// The steps for redirecting child process's STDOUT:	//	 1. Save current STDOUT, to be restored later.	//	 2. Create anonymous pipe to be STDOUT for child process.	//	 3. Set STDOUT of the parent process to be write handle to	//		the pipe, so it is inherited by the child process.	//	 4. Create a noninheritable duplicate of the read handle and	//		close the inheritable read handle.	// Save the handle to the current STDOUT.	savedStdoutHandle_ = ::GetStdHandle(STD_OUTPUT_HANDLE);	// Create a pipe for the child process's STDOUT.	if (!::CreatePipe(&hChildStdoutRdTmp, &childStdoutWrHandle_, &saAttr, 0))	{		throw RuntimeException( MAKE_ERROR_MSG_2("Stdout pipe creation failed") );	}	// Set a write handle to the pipe to be STDOUT.	if (!::SetStdHandle(STD_OUTPUT_HANDLE, childStdoutWrHandle_)) {		throw RuntimeException( MAKE_ERROR_MSG_2("Redirecting STDOUT failed"));	}	// Create noninheritable read handle and close the inheritable read handle.	bSuccess = ::DuplicateHandle(::GetCurrentProcess(), hChildStdoutRdTmp,									::GetCurrentProcess(), &childStdoutRdHandle_,									0, FALSE, DUPLICATE_SAME_ACCESS);	if (!bSuccess) {		throw RuntimeException( MAKE_ERROR_MSG_2("DuplicateHandle failed") ) ;	}	if (! ::CloseHandle(hChildStdoutRdTmp)) {		throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(hChildStdoutRdTmp)") );	}	// The steps for redirecting child process's STDIN:	//	 1.  Save current STDIN, to be restored later.	//	 2.  Create anonymous pipe to be STDIN for child process.	//	 3.  Set STDIN of the parent to be the read handle to the	//		 pipe, so it is inherited by the child process.	//	 4.  Create a noninheritable duplicate of the write handle,	//		 and close the inheritable write handle.	// Save the handle to the current STDIN.	savedStdinHandle_ = GetStdHandle(STD_INPUT_HANDLE);	// Create a pipe for the child process's STDIN.	if (!::CreatePipe(&childStdinRdHandle_, &hChildStdinWrTmp, &saAttr, 0)) {		throw RuntimeException( MAKE_ERROR_MSG_2("Stdin pipe creation failed") );	}	// Set a read handle to the pipe to be STDIN.	if (!::SetStdHandle(STD_INPUT_HANDLE, childStdinRdHandle_)) {		throw RuntimeException( MAKE_ERROR_MSG_2("Redirecting Stdin failed") );	}	// Duplicate the write handle to the pipe so it is not inherited.	bSuccess = ::DuplicateHandle(::GetCurrentProcess(), hChildStdinWrTmp,									::GetCurrentProcess(), &childStdinWrHandle_,									0, FALSE,// not inherited									DUPLICATE_SAME_ACCESS);	if (!bSuccess)  {		throw RuntimeException( MAKE_ERROR_MSG_2("DuplicateHandle failed") );	}	if (!::CloseHandle(hChildStdinWrTmp)) {		throw RuntimeException( MAKE_ERROR_MSG_2("CloseHandle(hChildStdinWrTmp)") );	}	//now start the child process - this will start a new cmd with the	//the cmd line sent to it	childProcess_ = NULL;	String tmp = System::getEnvironmentVariable( L"ComSpec" );	if (tmp.empty()) {		result = false;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?