1 /* 2 * Copyright (c) 2020, 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 <io.h> 27 #include <fcntl.h> 28 #include <windows.h> 29 30 #include "AppLauncher.h" 31 #include "JvmLauncher.h" 32 #include "Log.h" 33 #include "Dll.h" 34 #include "Toolbox.h" 35 #include "FileUtils.h" 36 #include "UniqueHandle.h" 37 #include "ErrorHandling.h" 38 #include "WinSysInfo.h" 39 #include "WinErrorHandling.h" 40 41 42 // AllowSetForegroundWindow 43 #pragma comment(lib, "user32") 44 45 46 namespace { 47 48 std::unique_ptr<Dll> loadDllWithAlteredPATH(const tstring& dllFullPath) { 49 LOG_TRACE_FUNCTION(); 50 51 const tstring vanillaPathEnvVariable = SysInfo::getEnvVariable(_T("PATH")); 52 53 tstring pathEnvVariable = vanillaPathEnvVariable 54 + _T(";") 55 + FileUtils::dirname(dllFullPath); 56 57 SysInfo::setEnvVariable(_T("PATH"), pathEnvVariable); 58 59 LOG_TRACE(tstrings::any() << "New value of PATH: " << pathEnvVariable); 60 61 // Schedule restore of PATH after attempt to load the given dll 62 const auto resetPATH = runAtEndOfScope([&vanillaPathEnvVariable]() -> void { 63 SysInfo::setEnvVariable(_T("PATH"), vanillaPathEnvVariable); 64 }); 65 66 return std::unique_ptr<Dll>(new Dll(dllFullPath)); 67 } 68 69 std::unique_ptr<Dll> loadDllWithAddDllDirectory(const tstring& dllFullPath) { 70 LOG_TRACE_FUNCTION(); 71 72 const tstring dirPath = FileUtils::dirname(dllFullPath); 73 74 typedef DLL_DIRECTORY_COOKIE(WINAPI *AddDllDirectoryFunc)(PCWSTR); 75 76 DllFunction<AddDllDirectoryFunc> _AddDllDirectory( 77 Dll("kernel32.dll", Dll::System()), "AddDllDirectory"); 78 79 AddDllDirectoryFunc func = _AddDllDirectory; 80 DLL_DIRECTORY_COOKIE res = func(dirPath.c_str()); 81 if (!res) { 82 JP_THROW(SysError(tstrings::any() 83 << "AddDllDirectory(" << dirPath << ") failed", func)); 84 } 85 86 LOG_TRACE(tstrings::any() << "AddDllDirectory(" << dirPath << "): OK"); 87 88 // Important: use LOAD_LIBRARY_SEARCH_DEFAULT_DIRS flag, 89 // but not LOAD_LIBRARY_SEARCH_USER_DIRS! 90 HMODULE dllHandle = LoadLibraryEx(dllFullPath.c_str(), NULL, 91 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); 92 93 LOG_TRACE(tstrings::any() << "LoadLibraryEx(" << dllFullPath 94 << ", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS): " << dllHandle); 95 96 const auto freeDll = runAtEndOfScope([&dllHandle]() -> void { 97 Dll::freeLibrary(dllHandle); 98 }); 99 100 return std::unique_ptr<Dll>(new Dll(dllFullPath)); 101 } 102 103 104 class DllWrapper { 105 public: 106 DllWrapper(const tstring& dllName) { 107 try { 108 // Try load DLL. 109 dll = std::unique_ptr<Dll>(new Dll(dllName)); 110 LOG_TRACE(tstrings::any() << "Load [" << dllName << "]: OK"); 111 } 112 catch (const std::exception&) { 113 // JVM DLL load failed, though it exists in file system. 114 try { 115 // Try adjust the DLL search paths with AddDllDirectory() WINAPI CALL 116 dll = loadDllWithAddDllDirectory(dllName); 117 } 118 catch (const std::exception&) { 119 // AddDllDirectory() didn't work. Try altering PATH environment 120 // variable as the last resort. 121 dll = loadDllWithAlteredPATH(dllName); 122 } 123 } 124 } 125 126 private: 127 DllWrapper(const DllWrapper&); 128 DllWrapper& operator=(const DllWrapper&); 129 130 private: 131 std::unique_ptr<Dll> dll; 132 }; 133 134 135 tstring getJvmLibPath(const Jvm& jvm, bool isClientJvm) { 136 FileUtils::mkpath path; 137 path << FileUtils::dirname(jvm.getPath()); 138 if (isClientJvm) { 139 path << _T("client"); 140 } else { 141 path << _T("server"); 142 } 143 path << _T("jvm.dll"); 144 145 if (isClientJvm && !FileUtils::isFileExists(path)) { 146 return getJvmLibPath(jvm, false); 147 } 148 149 return path; 150 } 151 152 153 void launchApp() { 154 // [RT-31061] otherwise UI can be left in back of other windows. 155 ::AllowSetForegroundWindow(ASFW_ANY); 156 157 const tstring launcherPath = SysInfo::getProcessModulePath(); 158 const tstring appImageRoot = FileUtils::dirname(launcherPath); 159 160 std::unique_ptr<Jvm> jvm(AppLauncher() 161 .setImageRoot(appImageRoot) 162 .addJvmLibName(_T("bin\\jli.dll")) 163 .setAppDir(FileUtils::mkpath() << appImageRoot << _T("app")) 164 .setDefaultRuntimePath(FileUtils::mkpath() << appImageRoot 165 << _T("runtime")) 166 .createJvmLauncher()); 167 168 const DllWrapper jliDll(jvm->getPath()); 169 std::unique_ptr<DllWrapper> splashDll; 170 if (jvm->isWithSplash()) { 171 const DllWrapper jvmDll(getJvmLibPath(*jvm, jvm->isClientJvm())); 172 splashDll = std::unique_ptr<DllWrapper>(new DllWrapper( 173 FileUtils::mkpath() 174 << FileUtils::dirname(jvm->getPath()) 175 << _T("splashscreen.dll"))); 176 } 177 178 jvm->launch(); 179 } 180 181 } // namespace 182 183 #ifndef JP_LAUNCHERW 184 185 int __cdecl wmain() { 186 return AppLauncher::launch(std::nothrow, launchApp); 187 } 188 189 #else 190 191 namespace { 192 193 class LastErrorGuiLogAppender : public LogAppender { 194 public: 195 virtual void append(const LogEvent& v) { 196 JP_TRY; 197 198 const std::wstring msg = (tstrings::any() 199 << AppLauncher::lastErrorMsg()).wstr(); 200 MessageBox(0, msg.c_str(), 201 FileUtils::basename(SysInfo::getProcessModulePath()).c_str(), 202 MB_ICONERROR | MB_OK); 203 204 JP_CATCH_ALL; 205 } 206 }; 207 208 209 class Console { 210 public: 211 Console() { 212 if (!AttachConsole(ATTACH_PARENT_PROCESS)) { 213 // Failed to connect to parent's console. Create our own. 214 if (!AllocConsole()) { 215 // We already have a console, no need to redirect std I/O. 216 return; 217 } 218 } 219 220 stdoutChannel = std::unique_ptr<Channel>(new Channel(stdout)); 221 stderrChannel = std::unique_ptr<Channel>(new Channel(stderr)); 222 } 223 224 struct FileCloser { 225 typedef FILE* pointer; 226 227 void operator()(pointer h) { 228 ::fclose(h); 229 } 230 }; 231 232 typedef std::unique_ptr< 233 FileCloser::pointer, 234 FileCloser 235 > UniqueFILEHandle; 236 237 private: 238 class Channel { 239 public: 240 Channel(FILE* stdFILEHandle): stdFILEHandle(stdFILEHandle) { 241 const char* stdFileName = "CONOUT$"; 242 const char* openMode = "w"; 243 if (stdFILEHandle == stdin) { 244 stdFileName = "CONIN$"; 245 openMode = "r"; 246 } 247 248 FILE* fp = 0; 249 freopen_s(&fp, stdFileName, openMode, stdFILEHandle); 250 251 fileHandle = UniqueFILEHandle(fp); 252 253 std::ios_base::sync_with_stdio(); 254 } 255 256 virtual ~Channel() { 257 JP_TRY; 258 259 FILE* fp = 0; 260 fileHandle = UniqueFILEHandle(fp); 261 std::ios_base::sync_with_stdio(); 262 263 JP_CATCH_ALL; 264 } 265 266 private: 267 UniqueFILEHandle fileHandle; 268 FILE *stdFILEHandle; 269 }; 270 271 std::unique_ptr<Channel> stdoutChannel; 272 std::unique_ptr<Channel> stderrChannel; 273 }; 274 275 276 void launchAppW() { 277 std::unique_ptr<Console> console; 278 if (AppLauncher::isWithLogging()) { 279 console = std::unique_ptr<Console>(new Console()); 280 } 281 282 launchApp(); 283 } 284 285 } // namespace 286 287 288 int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) { 289 LastErrorGuiLogAppender lastErrorLogAppender; 290 TeeLogAppender logAppender(&AppLauncher::defaultLastErrorLogAppender(), 291 &lastErrorLogAppender); 292 return AppLauncher::launch(std::nothrow, launchAppW, &logAppender); 293 } 294 295 #endif