Example #1
0
void ChildProcess::WaitForCompletion(bool printOutput)
{
	if (hProcess_)
	{
		// This looks like a busy loop, but it isn't. IsStillRunning()
		// waits until the process exits or sends more output, so this
		// is actually an idle loop.
		while (IsStillRunning())
		{
			if (printOutput)
			{
				std::wstring output = RemoveOutputText();
				outputPrintf(L"%s", output.c_str());
			}
		}
		// This isn't technically needed, but removing it would make
		// me nervous.
		WaitForSingleObject(hProcess_, INFINITE);
	}

	// Once the process is finished we have to close the stderr/stdout
	// handles so that the listener thread will exit. We also have to
	// close these if the process never started.
	if (hStdError_ != INVALID_HANDLE_VALUE)
	{
		CloseHandle(hStdError_);
		hStdError_ = INVALID_HANDLE_VALUE;
	}
	if (hStdOutput_ != INVALID_HANDLE_VALUE)
	{
		CloseHandle(hStdOutput_);
		hStdOutput_ = INVALID_HANDLE_VALUE;
	}

	// Wait for the listener thread to exit.
	if (hChildThread_)
	{
		WaitForSingleObject(hChildThread_, INFINITE);
		CloseHandle(hChildThread_);
		hChildThread_ = 0;
	}

	// Clean up.
	if (hPipe_ != INVALID_HANDLE_VALUE)
	{
		CloseHandle(hPipe_);
		hPipe_ = INVALID_HANDLE_VALUE;
	}

	if (printOutput)
	{
		// Now that the child thread has exited we can finally read
		// the last of the child-process output.
		std::wstring output = RemoveOutputText();
		if (!output.empty())
			outputPrintf(L"%s", output.c_str());
	}
}
Example #2
0
// Load a file and convert to a string. If the file contains
// an embedded NUL then the resulting string will be truncated.
std::wstring LoadFileAsText(const std::wstring& fileName)
{
	if (!::PathFileExistsW(fileName.c_str()))
		return L"";

	std::ifstream f;
	f.open(fileName, std::ios_base::binary);
	if (!f)
	{
		outputPrintf(L"Failed to load file `%s` as text - f.open failed!\n", fileName.c_str());
		return L"";
	}
	// Find the file length.
	f.seekg(0, std::ios_base::end);
	const std::streamoff len_int = f.tellg();
	if (len_int == -1)
	{
		outputPrintf(L"Failed to load file `%s` as text - f.tellg failed!\n", fileName.c_str());
		return L"";
	}
	const size_t length = static_cast<size_t>(len_int);
	f.seekg(0, std::ios_base::beg);

	// Allocate a buffer and read the file.
	std::vector<char> data(length + 2);
	f.read(&data[0], length);
	if (!f)
	{
		outputPrintf(L"Failed to load file `%s` as text - f.read failed!\n", fileName.c_str());
		return L"";
	}

	// Add a multi-byte null terminator.
	data[length] = 0;
	data[length+1] = 0;

	const wchar_t bom = 0xFEFF;
	UIETWASSERT(data.size() > sizeof(bom));
	if (memcmp(&bom, &data[0], sizeof(bom)) == 0)
	{
		// Assume UTF-16, strip bom, and return.
		return reinterpret_cast<const wchar_t*>(&data[sizeof(bom)]);
	}

	// If not-UTF-16 then convert from ANSI to wstring and return
	return AnsiToUnicode(&data[0]);
}
Example #3
0
bool ChildProcess::Run(bool showCommand, std::wstring args)
{
	UIETWASSERT(!hProcess_);

	if (showCommand)
		outputPrintf(L"%s\n", args.c_str());

	SECURITY_ATTRIBUTES security = { sizeof(security), 0, TRUE };

	hStdOutput_ = CreateFile(kPipeName, GENERIC_WRITE, 0, &security,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
	if (hStdOutput_ == INVALID_HANDLE_VALUE)
		return false;
	if (!DuplicateHandle(GetCurrentProcess(), hStdOutput_, GetCurrentProcess(),
		&hStdError_, 0, TRUE, DUPLICATE_SAME_ACCESS))
		return false;

	STARTUPINFO startupInfo = {};
	startupInfo.hStdOutput = hStdOutput_;
	startupInfo.hStdError = hStdError_;
	startupInfo.hStdInput = INVALID_HANDLE_VALUE;
	startupInfo.dwFlags = STARTF_USESTDHANDLES;

	PROCESS_INFORMATION processInfo = {};
	DWORD flags = CREATE_NO_WINDOW;
	// Wacky CreateProcess rules say args has to be writable!
	std::vector<wchar_t> argsCopy(args.size() + 1);
	wcscpy_s(&argsCopy[0], argsCopy.size(), args.c_str());
	BOOL success = CreateProcess(exePath_.c_str(), &argsCopy[0], NULL, NULL,
		TRUE, flags, NULL, NULL, &startupInfo, &processInfo);
	if (success)
	{
		CloseHandle(processInfo.hThread);
		hProcess_ = processInfo.hProcess;
		return true;
	}
	else
	{
		outputPrintf(L"Error %d starting %s, %s\n", (int)GetLastError(), exePath_.c_str(), args.c_str());
	}

	return false;
}
Example #4
0
void outputLastError(const DWORD lastErr)
{
	const DWORD errMsgSize = 1024u;
	wchar_t errBuff[errMsgSize] = {};
	const DWORD ret = ::FormatMessageW(
		(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS),
		NULL, lastErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		errBuff, errMsgSize, NULL);

	if (ret == 0)
		return; // FormatMessageW failed.
	outputPrintf(errBuff);
}
Example #5
0
ChildProcess::~ChildProcess()
{
	if (hProcess_)
	{
		DWORD exitCode = GetExitCode();
		if (exitCode)
			outputPrintf(L"Process exit code was %08x (%lu)\n", exitCode, exitCode);
		CloseHandle(hProcess_);
	}
	if (hOutputAvailable_)
	{
		CloseHandle(hOutputAvailable_);
	}
}