/********************************************************************** * * os_process_windows.c -- Windows version of osprocess. See os_process.h * for more details * * Copyright (C) 2010 The New Zealand Digital Library Project * * A component of the Greenstone digital library software * from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *********************************************************************/ #ifdef __WIN32__ #if defined(GSDL_USE_OBJECTSPACE) # include #elif defined(GSDL_USE_IOS_H) # include #else # include using namespace std; #endif #include "text_t.h" #include "os_process_windows.h" osprocesswindows::osprocesswindows(OSProcessPipeMode mode, char* prog_name, char* argv[], char* envp[]) : child_stdout_read_(NULL), child_stdin_write_(NULL), osprocess(mode,prog_name,argv,envp) { HANDLE child_stdin_read = NULL; HANDLE child_stdout_write = NULL; SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // Create a pipe for the child process's STDOUT. if (!CreatePipe(&child_stdout_read_, &child_stdout_write, &saAttr, 0)) { cerr << "osprocesswindows::osprocesswindows(): Failed to create stdout pipe for child process" << endl; } // Ensure the read handle to the pipe for STDOUT is not inherited. if (!SetHandleInformation(child_stdout_read_, HANDLE_FLAG_INHERIT, 0)) { cerr << "osprocesswindows::osprocesswindows(): Failed to set handle information for stdout pipe for child process" << endl; } // Create a pipe for the child process's STDIN. if (!CreatePipe(&child_stdin_read, &child_stdin_write_, &saAttr, 0)) { cerr << "osprocesswindows::osprocesswindows(): Failed to create stdin pipe for child process" << endl; } // Ensure the write handle to the pipe for STDIN is not inherited. if (!SetHandleInformation(child_stdin_write_, HANDLE_FLAG_INHERIT, 0)) { cerr << "osprocesswindows::osprocesswindows(): Failed to set handle information for stdin pipe for child process" << endl; } STARTUPINFOA si; memset(&si, 0, sizeof(si)); memset(&pi_, 0, sizeof(pi_)); si.cb = sizeof(si); // These two lines help prevent a DOS window popping up // when the process is created si.dwFlags |= STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; si.dwFlags |= STARTF_USESTDHANDLES; // any error messages in the child process goes to same place as parent // e.g. in the case of running as a CGI script, the Web server error log si.hStdError = GetStdHandle(STD_ERROR_HANDLE); if ((mode==uniRead) || (mode==biReadWrite)) { // Output from the child process comes to the parent process, down the // OUT pipe si.hStdOutput = child_stdout_write; } else { // uniWrite // Output from the chlid process goes to the same place as parent si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); } if ((mode==uniWrite) || (mode==biReadWrite)) { // Input to the child process can be sent from the parent process, down the // In pipe si.hStdInput = child_stdin_read; } else { // uniRead // Input to the child process comes from same place as parent ?!? si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); } text_t cmd_line = prog_name; if (argv != NULL) { int i=1; while (argv[i] != NULL) { cmd_line += " \""; cmd_line += argv[i]; cmd_line += "\""; i++; } } char* cmd_line_cstr = cmd_line.getcstr(); int rv = CreateProcess(NULL, // no application name cmd_line_cstr, NULL, NULL, // no process or thread security attribues TRUE, // Inherit handles 0, // Creation flag NULL, // No environment block ".", // current working directory &si, &pi_); // process info filled out as a result delete [] cmd_line_cstr; if (!rv) { cerr << "os_process_windows(): Error creating child process" << endl; } // close the handles that aren't used by the parent process if (!CloseHandle(child_stdout_write)) { cerr << "os_process_windows(): Error closing child's StdOut Write Handle" << endl; } if (!CloseHandle(child_stdin_read)) { cerr << "os_process_windows(): Error closing child's StdIn Read Handle" << endl; } } osprocesswindows::~osprocesswindows() { // close any file handles that are still open close(); // Close process and thread handles CloseHandle( pi_.hProcess ); pi_.hProcess = NULL; CloseHandle( pi_.hThread ); pi_.hThread = NULL; } int osprocesswindows::write(char* buffer, const int buffer_len) { DWORD actual_write_len; bool write_ok = WriteFile(child_stdin_write_, buffer, buffer_len, &actual_write_len, NULL); if (!write_ok) { cerr << "osproesswindows::write() Error: failed to write data" << endl; } return actual_write_len; } int osprocesswindows::read(char* buffer, const int buffer_len) { DWORD actual_read_len; bool read_ok = ReadFile(child_stdout_read_, buffer, buffer_len, &actual_read_len, NULL); if (!read_ok) { cerr << "osproesswindows::read() Error: failed to read data" << endl; } return actual_read_len; } void osprocesswindows::wait() { WaitForSingleObject(pi_.hProcess, INFINITE); } bool osprocesswindows::close_write_pipe(OSProcessWarnStatus warn_status) { bool write_close_ok = true; if (child_stdin_write_ != NULL) { write_close_ok = CloseHandle(child_stdin_write_); if (write_close_ok) { child_stdin_write_ = NULL; } else { // not OK cerr << "osprocesswindows::close(): Error - Failed to close stdin write handle on pipe to child process" << endl; } } else if (warn_status == withWarning) { cerr << "osprocesswindows::close_write_pipe(): Warning - Tried to close already closed pipe" << endl; } return write_close_ok; } bool osprocesswindows::close_read_pipe(OSProcessWarnStatus warn_status) { bool read_close_ok = true; if (child_stdout_read_ != NULL) { read_close_ok = CloseHandle(child_stdout_read_); if (read_close_ok) { child_stdout_read_ = NULL; } else { cerr << "osprocesswindows::close(): Error - Failed to close handle stdout read on pipe to chlild process" << endl; } } else if (warn_status == withWarning) { cerr << "osprocesswindows::close_read_pipe(): Warning - Tried to close already closed pipe" << endl; } return read_close_ok; } #endif