Ver código fonte

Implemented CodeDweller::Child for Windows except for streams.

git-svn-id: https://svn.microneil.com/svn/CodeDweller/branches/adeniz_1@30 d34b734f-a00e-4b39-a726-e4eeb87269ab
adeniz_1
adeniz 10 anos atrás
pai
commit
ce9852081a
2 arquivos alterados com 208 adições e 10 exclusões
  1. 168
    6
      child.cpp
  2. 40
    4
      child.hpp

+ 168
- 6
child.cpp Ver arquivo

@@ -19,7 +19,7 @@
// Place, Suite 330, Boston, MA 02111-1307 USA
//==============================================================================
// See child.hpp for notes.
#include <iostream> // Temporary.
#include <stdexcept>
@@ -28,28 +28,190 @@
namespace CodeDweller {
Child::Child(std::vector<std::string> args) {
init();
if (args.size() == 0) {
//
} else if (args.size() == 1) {
cmdline = args[0];
return;
}
// Append all but last command-line arguments.
for (size_t i = 0; i < args.size() - 1; i++) {
cmdline += args[i] + " ";
}
cmdline += args.back(); // Append last command-line argument.
}
Child::Child(std::string childpath) {
Child::Child(std::string childpath) :
cmdline(childpath) {
init();
}
Child::~Child() {
}
void
Child::init() {
exitCodeObtainedFlag = false;
exitCode = 0;
}
std::istream *
Child::reader() {
return new std::istream(std::cin.rdbuf());
}
std::ostream *
Child::writer() {
return new std::ostream(std::cout.rdbuf());
}
void
Child::run() {
throw std::runtime_error("Not implemented");
// Set the bInheritHandle flag so pipe handles are inherited.
SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttributes.bInheritHandle = true;
securityAttributes.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
HANDLE childStdOutAtChild;
HANDLE childStdInAtChild;
int bufferSize = 0;
if (!CreatePipe(&childStdOutAtParent,
&childStdOutAtChild,
&securityAttributes,
bufferSize)) {
throw std::runtime_error("Error from CreatePipe for stdout: " +
getErrorText());
}
// Ensure the read handle to the pipe for STDOUT is not inherited.
int inheritFlag = 0;
if (!SetHandleInformation(childStdOutAtParent,
HANDLE_FLAG_INHERIT,
inheritFlag) ) {
throw std::runtime_error("Error from GetHandleInformation for stdout: " +
getErrorText());
}
// Create a pipe for the child process's STDIN.
if (! CreatePipe(&childStdInAtChild,
&childStdInAtParent,
&securityAttributes,
bufferSize)) {
throw std::runtime_error("Error from CreatePipe for stdin: " +
getErrorText());
}
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(childStdInAtParent,
HANDLE_FLAG_INHERIT,
inheritFlag)) {
throw std::runtime_error("Error from GetHandleInformation for stdin: " +
getErrorText());
}
// Set up members of the PROCESS_INFORMATION structure.
PROCESS_INFORMATION processInfo;
std::fill((char *) &processInfo,
((char *) &processInfo) + sizeof(PROCESS_INFORMATION),
0);
// Set up members of the STARTUPINFO structure. This structure
// specifies the STDIN and STDOUT handles for redirection.
STARTUPINFO startInfo;
std::fill((char *) &startInfo,
((char *) &startInfo) + sizeof(STARTUPINFO),
0);
startInfo.cb = sizeof(STARTUPINFO);
startInfo.hStdError = childStdOutAtChild;
startInfo.hStdOutput = childStdOutAtChild;
startInfo.hStdInput = childStdInAtChild;
startInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bool createSuccess;
createSuccess = CreateProcess(NULL,
(char *) cmdline.c_str(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
true, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&startInfo, // STARTUPINFO pointer
&processInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if (!createSuccess ) {
throw std::runtime_error("Error from CreateProcess with "
"command line \"" + cmdline + "\": " +
getErrorText());
}
// Save the handles to the child process and its primary thread.
childProcess = processInfo.hProcess;
childThread = processInfo.hThread;
// Close the child's end of the pipes.
CloseHandle(childStdOutAtChild);
CloseHandle(childStdInAtChild);
}
void
Child::terminate() {
throw std::runtime_error("Not implemented");
if (!TerminateProcess(childProcess, terminateExitCode)) {
throw std::runtime_error("Error terminating the child process: " +
getErrorText());
}
}
int32_t
Child::result() {
throw std::runtime_error("Not implemented");
return 0;
int result;
if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) {
throw std::runtime_error("Error getting child process exit code: " +
getErrorText());
}
return result;
}
std::string
Child::getErrorText() {
LPVOID winMsgBuf;
DWORD lastError = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
lastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char *) &winMsgBuf,
0, NULL );
std::string errMsg((char *) winMsgBuf);
LocalFree(winMsgBuf);
return errMsg;
}
}

+ 40
- 4
child.hpp Ver arquivo

@@ -28,6 +28,8 @@
#ifndef CHILD_HPP
#define CHILD_HPP

#include <windows.h>

#include <cstdint>
#include <istream>
#include <ostream>
@@ -82,11 +84,11 @@ namespace CodeDweller {
/** Destructor terminates the child process. */
~Child();

/// Stream that is seen by the child as standard output.
std::istream reader;
/// Return a stream that is seen by the child as standard output.
std::istream *reader();

/// Stream that is seen by the child as standard input.
std::ostream writer;
/// Return a stream that is seen by the child as standard input.
std::ostream *writer();

/** Spawn the child process.

@@ -111,6 +113,40 @@ namespace CodeDweller {
*/
int32_t result();

private:

/// Exit code to use when terminating the child process.
static const uint32_t terminateExitCode = 0;

/// Initialize data members.
void init();

/// Child executable path and command-line parameters.
std::string cmdline;

/// Parent's read handle for child process standard output.
HANDLE childStdOutAtParent;

/// Parent's write handle for child process standard input.
HANDLE childStdInAtParent;

/// Child's process handle.
HANDLE childProcess;

/// Child's thread handle.
HANDLE childThread;

/// Exit value of the process.
int32_t exitCode;

/// True if the exit code has been obtained.
bool exitCodeObtainedFlag;

/// Return text for the most recent error.
//
// \returns Human-readable description of the most recent error.
//
std::string getErrorText();
};

}

Carregando…
Cancelar
Salvar