1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
#pragma once
#ifdef _MSC_VER
#include <Windows.h>
#include <vector>
#include <string>
#include <iostream>
#pragma warning (push)
#pragma warning (disable : 4996) // For getenv.
namespace pipe {
using std::string;
using std::istream;
using std::ostream;
using std::cout;
using std::endl;
/**
* Run a piped process on Windows.
*/
static const size_t bufferSize = 1024;
struct WriteData {
istream &stream;
HANDLE handle;
};
DWORD WINAPI writeThread(void *data) {
WriteData *d = (WriteData *)data;
char buffer[bufferSize];
DWORD filled;
DWORD written;
d->stream.read(buffer, bufferSize);
filled = (DWORD)d->stream.gcount();
while (filled > 0) {
if (!WriteFile(d->handle, buffer, filled, &written, NULL)) {
cout << "Error: " << GetLastError() << endl;
CloseHandle(d->handle);
return 0;
}
if (written < filled) {
memmove(buffer, buffer + written, filled - written);
filled -= written;
} else {
d->stream.read(buffer, bufferSize);
filled = (DWORD)d->stream.gcount();
}
}
CloseHandle(d->handle);
return 0;
}
struct ReadData {
ostream &stream;
HANDLE handle;
};
DWORD WINAPI readThread(void *data) {
ReadData *d = (ReadData *)data;
char buffer[bufferSize];
DWORD written;
while (ReadFile(d->handle, buffer, bufferSize, &written, NULL)) {
d->stream.write(buffer, written);
if (written == 0)
break;
}
CloseHandle(d->handle);
return 0;
}
void runProcess(const string &exe, const string &cmd, istream &inStream, ostream &outStream) {
STARTUPINFO startup;
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESTDHANDLES;
SECURITY_ATTRIBUTES writeSa;
writeSa.nLength = sizeof(SECURITY_ATTRIBUTES);
writeSa.bInheritHandle = TRUE;
writeSa.lpSecurityDescriptor = NULL;
HANDLE input, output;
CreatePipe(&startup.hStdInput, &input, &writeSa, 0);
CreatePipe(&output, &startup.hStdOutput, &writeSa, 0);
startup.hStdError = startup.hStdOutput;
SetHandleInformation(input, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(output, HANDLE_FLAG_INHERIT, 0);
PROCESS_INFORMATION info;
char *cmdline = new char[cmd.size() + 1];
memcpy(cmdline, cmd.c_str(), cmd.size() + 1);
if (CreateProcess(exe.c_str(), cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info) == 0) {
cout << "Failed to start " << exe << endl;
exit(1);
}
delete []cmdline;
CloseHandle(startup.hStdInput);
CloseHandle(startup.hStdOutput);
CloseHandle(info.hThread);
WriteData wd = { inStream, input };
ReadData rd = { outStream, output };
HANDLE wThread = CreateThread(NULL, 0, &writeThread, &wd, 0, NULL);
HANDLE rThread = CreateThread(NULL, 0, &readThread, &rd, 0, NULL);
WaitForSingleObject(info.hProcess, INFINITE);
WaitForSingleObject(wThread, INFINITE);
WaitForSingleObject(rThread, INFINITE);
CloseHandle(info.hProcess);
}
// Run using cmd.exe. If "remain" is true, then /K is used instead of /C
void runCmd(bool remain, const string &cmd, istream &inStream, ostream &outStream) {
string exe = getenv("comspec");
string c = (remain ? "/K " : "/C ") + cmd;
runProcess(exe, c, inStream, outStream);
}
}
#pragma warning (pop)
#endif
|