/*========================================================================= Program: Visualization Toolkit Module: vtkWin32ProcessOutputWindow.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkWin32ProcessOutputWindow.h" #include "vtkObjectFactory.h" #include "vtkWindows.h" #include #ifndef _MAX_FNAME #define _MAX_FNAME 4096 #endif #ifndef _MAX_PATH #define _MAX_PATH 4096 #endif #ifndef PRIdword #if _LP64 #define PRIdword "u" #else #define PRIdword "lu" #endif #endif vtkStandardNewMacro(vtkWin32ProcessOutputWindow); extern "C" int vtkEncodedArrayWin32OutputWindowProcessWrite(const char* fname); //------------------------------------------------------------------------------ vtkWin32ProcessOutputWindow::vtkWin32ProcessOutputWindow() { this->OutputPipe = 0; this->Broken = 0; this->Count = 0; } //------------------------------------------------------------------------------ vtkWin32ProcessOutputWindow::~vtkWin32ProcessOutputWindow() { if (this->OutputPipe) { CloseHandle(this->OutputPipe); } } //------------------------------------------------------------------------------ void vtkWin32ProcessOutputWindow::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ void vtkWin32ProcessOutputWindow::DisplayText(const char* text) { // Display the text if the pipe has not been broken. if (!this->Broken && text) { const char* begin = text; while (const char* end = strchr(begin, '\n')) { this->Write(begin, end - begin); this->Write("\r\n", 2); begin = end + 1; } this->Write(begin, strlen(begin)); } } //------------------------------------------------------------------------------ int vtkWin32ProcessOutputWindow::Initialize() { // Write the executable as a temporary file. It will delete itself. char exeName[_MAX_FNAME + 1] = ""; char tempDir[_MAX_PATH + 1] = ""; // We will try putting the executable in the system temp directory. // Note that the returned path already has a trailing slash. DWORD length = GetTempPath(_MAX_PATH + 1, tempDir); if (length <= 0 || length > _MAX_PATH) { return 0; } // Construct the executable name from the process id, pointer to // this output window instance, and a count. This should be unique. snprintf(exeName, sizeof(exeName), "vtkWin32OWP_%" PRIdword "_%p_%u.exe", GetCurrentProcessId(), this, this->Count++); // Allocate a buffer to hold the executable path. size_t tdlen = strlen(tempDir); char* exeFullPath = (char*)malloc(tdlen + strlen(exeName) + 2); if (!exeFullPath) { return 0; } // Construct the full path to the executable. snprintf(exeFullPath, sizeof(exeFullPath), "%s%s", tempDir, exeName); // Try to write the executable to disk. if (!vtkEncodedArrayWin32OutputWindowProcessWrite(exeFullPath)) { free(exeFullPath); return 0; } // Create a process and a pipe connected to its stdin. STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags |= STARTF_USESHOWWINDOW; si.dwFlags |= STARTF_USESTDHANDLES; si.wShowWindow = SW_SHOWDEFAULT; // Create a pipe with an inherited read end. if (!CreatePipe(&si.hStdInput, &this->OutputPipe, 0, 0) || !DuplicateHandle(GetCurrentProcess(), si.hStdInput, GetCurrentProcess(), &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) { DeleteFile(exeFullPath); free(exeFullPath); return 0; } // Create the child process. if (!CreateProcess(0, exeFullPath, 0, 0, TRUE, NORMAL_PRIORITY_CLASS, 0, 0, &si, &pi)) { DeleteFile(exeFullPath); free(exeFullPath); CloseHandle(si.hStdInput); return 0; } // We only need to keep the pipe write end. Close all other handles. CloseHandle(si.hStdInput); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); free(exeFullPath); return 1; } //------------------------------------------------------------------------------ void vtkWin32ProcessOutputWindow::Write(const char* data, size_t length) { if (data && length) { // Initialize the output pipe the first time. if (this->Broken || (!this->OutputPipe && !this->Initialize())) { this->Broken = 1; return; } // Write the data to the pipe. If it breaks, close the pipe. DWORD nWritten; if (!WriteFile(this->OutputPipe, data, (DWORD)length, &nWritten, 0)) { this->Broken = 1; CloseHandle(this->OutputPipe); this->OutputPipe = 0; } } }