1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <algorithm> 27 #include "Executor.h" 28 #include "Log.h" 29 #include "WinErrorHandling.h" 30 31 32 namespace { 33 34 void escapeArg(std::wstring& str) { 35 if (str.empty()) { 36 return; 37 } 38 39 if (str.front() == L'\"' && str.back() == L'\"' && str.size() > 1) { 40 return; 41 } 42 43 if (str.find_first_of(L" \t") != std::wstring::npos) { 44 str = L'"' + str + L'"'; 45 } 46 } 47 48 } // namespace 49 50 51 std::wstring Executor::args() const { 52 tstring_array tmpArgs; 53 // argv[0] is the module name. 54 tmpArgs.push_back(appPath); 55 tmpArgs.insert(tmpArgs.end(), argsArray.begin(), argsArray.end()); 56 57 std::for_each(tmpArgs.begin(), tmpArgs.end(), escapeArg); 58 return tstrings::join(tmpArgs.begin(), tmpArgs.end(), _T(" ")); 59 } 60 61 62 int Executor::execAndWaitForExit() const { 63 UniqueHandle h = startProcess(); 64 65 const DWORD res = ::WaitForSingleObject(h.get(), INFINITE); 66 if (WAIT_FAILED == res) { 67 JP_THROW(SysError("WaitForSingleObject() failed", WaitForSingleObject)); 68 } 69 70 DWORD exitCode = 0; 71 if (!GetExitCodeProcess(h.get(), &exitCode)) { 72 // Error reading process's exit code. 73 JP_THROW(SysError("GetExitCodeProcess() failed", GetExitCodeProcess)); 74 } 75 76 const DWORD processId = GetProcessId(h.get()); 77 if (!processId) { 78 JP_THROW(SysError("GetProcessId() failed.", GetProcessId)); 79 } 80 81 LOG_TRACE(tstrings::any() << "Process with PID=" << processId 82 << " terminated. Exit code=" << exitCode); 83 84 return static_cast<int>(exitCode); 85 } 86 87 88 UniqueHandle Executor::startProcess() const { 89 const std::wstring argsStr = args(); 90 91 std::vector<TCHAR> argsBuffer(argsStr.begin(), argsStr.end()); 92 argsBuffer.push_back(0); // terminating '\0' 93 94 STARTUPINFO startupInfo; 95 ZeroMemory(&startupInfo, sizeof(startupInfo)); 96 startupInfo.cb = sizeof(startupInfo); 97 98 PROCESS_INFORMATION processInfo; 99 ZeroMemory(&processInfo, sizeof(processInfo)); 100 101 DWORD creationFlags = 0; 102 103 if (!theVisible) { 104 // For GUI applications. 105 startupInfo.dwFlags |= STARTF_USESHOWWINDOW; 106 startupInfo.wShowWindow = SW_HIDE; 107 108 // For console applications. 109 creationFlags |= CREATE_NO_WINDOW; 110 } 111 112 tstrings::any msg; 113 msg << "CreateProcess(" << appPath << ", " << argsStr << ")"; 114 115 if (!CreateProcess(appPath.c_str(), argsBuffer.data(), NULL, NULL, FALSE, 116 creationFlags, NULL, NULL, &startupInfo, &processInfo)) { 117 msg << " failed"; 118 JP_THROW(SysError(msg, CreateProcess)); 119 } 120 121 msg << " succeeded; PID=" << processInfo.dwProcessId; 122 LOG_TRACE(msg); 123 124 // Close unneeded handles immediately. 125 UniqueHandle(processInfo.hThread); 126 127 // Return process handle. 128 return UniqueHandle(processInfo.hProcess); 129 }