1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "stdafx.h" 18 #include "utils.h" 19 20 // Set to true to get some extra debug information 21 bool gIsDebug = false; 22 // Set to true to output errors to stderr (for a Console app) 23 // or to false to output using msg box (for a Windows UI app) 24 bool gIsConsole = false; 25 26 // Application name used in error dialog. Defined using initUtils() 27 static CString gAppName("Find Java 2"); 28 29 // Called by the application to initialize the app name used in error dialog boxes. 30 void initUtils(const TCHAR *appName) { 31 if (appName != NULL) { 32 gAppName = CString(appName); 33 return; 34 } 35 36 // Try to get the VERSIONINFO.FileDescription and use as app name 37 // Errors are ignored, in which case the default app name is used. 38 39 // First get the module (aka app instance) filename. 40 TCHAR moduleName[MAX_PATH + 1]; 41 DWORD sz = ::GetModuleFileName(NULL /*AfxGetInstanceHandle()*/, moduleName, MAX_PATH); 42 if (sz == 0) { 43 // GetModuleFileName failed. Do nothing. 44 return; 45 } 46 moduleName[sz] = '\0'; // make sure string is properly terminated. 47 48 // Get the size of the FileVersionInfo buffer 49 DWORD obsoleteHandle; // see http://blogs.msdn.com/b/oldnewthing/archive/2007/07/31/4138786.aspx 50 DWORD fviSize = ::GetFileVersionInfoSize(moduleName, &obsoleteHandle); 51 if (fviSize == 0) { 52 return; // do nothing on error 53 } 54 55 char *fviBuffer = new char[fviSize]; 56 if (::GetFileVersionInfo(moduleName, 0, fviSize, fviBuffer) != 0) { 57 VOID *vBuffer; 58 UINT vLen; 59 60 struct LANGUAGE_CODEPAGE { 61 WORD mLanguage; 62 WORD mCodePage; 63 } *lgcpBuffer; 64 65 UINT lgcpSize; 66 67 // Read the list of languages and code pages (c.f. MSDN for VerQueryValue) 68 if (::VerQueryValue(fviBuffer, _T("\\VarFileInfo\\Translation"), (LPVOID*)&lgcpBuffer, &lgcpSize) != 0 && 69 lgcpSize >= sizeof(LANGUAGE_CODEPAGE)) { 70 // Use the first available language and code page 71 CString subBlock; 72 subBlock.Format(_T("\\StringFileInfo\\%04x%04x\\FileDescription"), 73 lgcpBuffer[0].mLanguage, 74 lgcpBuffer[0].mCodePage); 75 if (::VerQueryValue(fviBuffer, subBlock, &vBuffer, &vLen) != 0) { 76 gAppName.SetString((LPCTSTR)vBuffer, vLen); 77 } 78 } 79 } 80 delete[] fviBuffer; 81 } 82 83 CString getAppName() { 84 return gAppName; 85 } 86 87 88 // Displays a message in an ok+info dialog box. 89 void msgBox(const TCHAR* text, ...) { 90 CString formatted; 91 va_list ap; 92 va_start(ap, text); 93 formatted.FormatV(text, ap); 94 va_end(ap); 95 96 // TODO global CString to get app name 97 MessageBox(NULL, formatted, gAppName, MB_OK | MB_ICONINFORMATION); 98 } 99 100 // Sets the string to the message matching Win32 GetLastError. 101 // If message is non-null, it is prepended to the last error string. 102 CString getLastWin32Error(const TCHAR* message) { 103 DWORD err = GetLastError(); 104 CString result; 105 LPTSTR errStr; 106 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */ 107 FORMAT_MESSAGE_FROM_SYSTEM, 108 NULL, /* lpSource */ 109 err, /* dwMessageId */ 110 0, /* dwLanguageId */ 111 (LPTSTR) &errStr, /* out lpBuffer */ 112 0, /* nSize */ 113 NULL) != 0) { /* va_list args */ 114 if (message == NULL) { 115 result.Format(_T("[%d] %s"), err, errStr); 116 } else { 117 result.Format(_T("%s[%d] %s"), message, err, errStr); 118 } 119 LocalFree(errStr); 120 } 121 return result; 122 } 123 124 // Displays GetLastError prefixed with a description in an error dialog box 125 void displayLastError(const TCHAR *description, ...) { 126 CString formatted; 127 va_list ap; 128 va_start(ap, description); 129 formatted.FormatV(description, ap); 130 va_end(ap); 131 132 CString error = getLastWin32Error(NULL); 133 formatted.Append(_T("\r\n")); 134 formatted.Append(error); 135 136 if (gIsConsole) { 137 _ftprintf(stderr, _T("%s\n"), (LPCTSTR) formatted); 138 } else { 139 CString name(gAppName); 140 name.Append(_T(" - Error")); 141 MessageBox(NULL, formatted, name, MB_OK | MB_ICONERROR); 142 } 143 } 144 145 // Executes the command line. Does not wait for the program to finish. 146 // The return code is from CreateProcess (0 means failure), not the running app. 147 int execNoWait(const TCHAR *app, const TCHAR *params, const TCHAR *workDir) { 148 STARTUPINFO startup; 149 PROCESS_INFORMATION pinfo; 150 151 ZeroMemory(&pinfo, sizeof(pinfo)); 152 153 ZeroMemory(&startup, sizeof(startup)); 154 startup.cb = sizeof(startup); 155 startup.dwFlags = STARTF_USESHOWWINDOW; 156 startup.wShowWindow = SW_SHOWDEFAULT; 157 158 int ret = CreateProcess( 159 app, /* program path */ 160 (TCHAR *)params, /* command-line */ 161 NULL, /* process handle is not inheritable */ 162 NULL, /* thread handle is not inheritable */ 163 TRUE, /* yes, inherit some handles */ 164 0, /* create flags */ 165 NULL, /* use parent's environment block */ 166 workDir, /* use parent's starting directory */ 167 &startup, /* startup info, i.e. std handles */ 168 &pinfo); 169 170 if (ret) { 171 CloseHandle(pinfo.hProcess); 172 CloseHandle(pinfo.hThread); 173 } 174 175 return ret; 176 } 177 178 // Executes command, waits for completion and returns exit code. 179 // As indicated in MSDN for CreateProcess, callers should double-quote the program name 180 // e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2"; 181 int execWait(const TCHAR *cmd) { 182 STARTUPINFO startup; 183 PROCESS_INFORMATION pinfo; 184 185 ZeroMemory(&pinfo, sizeof(pinfo)); 186 187 ZeroMemory(&startup, sizeof(startup)); 188 startup.cb = sizeof(startup); 189 startup.dwFlags = STARTF_USESHOWWINDOW; 190 startup.wShowWindow = SW_HIDE | SW_MINIMIZE; 191 192 int ret = CreateProcess( 193 NULL, /* program path */ 194 (LPTSTR)cmd, /* command-line */ 195 NULL, /* process handle is not inheritable */ 196 NULL, /* thread handle is not inheritable */ 197 TRUE, /* yes, inherit some handles */ 198 CREATE_NO_WINDOW, /* we don't want a console */ 199 NULL, /* use parent's environment block */ 200 NULL, /* use parent's starting directory */ 201 &startup, /* startup info, i.e. std handles */ 202 &pinfo); 203 204 int result = -1; 205 if (ret) { 206 WaitForSingleObject(pinfo.hProcess, INFINITE); 207 208 DWORD exitCode; 209 if (GetExitCodeProcess(pinfo.hProcess, &exitCode)) { 210 // this should not return STILL_ACTIVE (259) 211 result = exitCode; 212 } 213 CloseHandle(pinfo.hProcess); 214 CloseHandle(pinfo.hThread); 215 } 216 217 return result; 218 } 219 220 bool getModuleDir(CPath *outDir) { 221 TCHAR programDir[MAX_PATH]; 222 int ret = GetModuleFileName(NULL, programDir, sizeof(programDir) * sizeof(TCHAR)); 223 if (ret != 0) { 224 CPath dir(programDir); 225 dir.RemoveFileSpec(); 226 *outDir = dir; 227 return true; 228 } 229 return false; 230 } 231 232 // Disables the FS redirection done by WOW64. 233 // Because this runs as a 32-bit app, Windows automagically remaps some 234 // folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files"). 235 // This prevents the app from correctly searching for java.exe in these folders. 236 // The registry is also remapped. This method disables this redirection. 237 // Caller should restore the redirection later by using revertWow64FsRedirection(). 238 PVOID disableWow64FsRedirection() { 239 240 // The call we want to make is the following: 241 // PVOID oldWow64Value; 242 // Wow64DisableWow64FsRedirection(&oldWow64Value); 243 // However that method may not exist (e.g. on XP non-64 systems) so 244 // we must not call it directly. 245 246 PVOID oldWow64Value = 0; 247 248 HMODULE hmod = LoadLibrary(_T("kernel32.dll")); 249 if (hmod != NULL) { 250 FARPROC proc = GetProcAddress(hmod, "Wow64DisableWow64FsRedirection"); 251 if (proc != NULL) { 252 typedef BOOL(WINAPI *disableWow64FuncType)(PVOID *); 253 disableWow64FuncType funcPtr = (disableWow64FuncType)proc; 254 funcPtr(&oldWow64Value); 255 } 256 257 FreeLibrary(hmod); 258 } 259 260 return oldWow64Value; 261 } 262 263 // Reverts the redirection disabled in disableWow64FsRedirection. 264 void revertWow64FsRedirection(PVOID oldWow64Value) { 265 266 // The call we want to make is the following: 267 // Wow64RevertWow64FsRedirection(oldWow64Value); 268 // However that method may not exist (e.g. on XP non-64 systems) so 269 // we must not call it directly. 270 271 HMODULE hmod = LoadLibrary(_T("kernel32.dll")); 272 if (hmod != NULL) { 273 FARPROC proc = GetProcAddress(hmod, "Wow64RevertWow64FsRedirection"); 274 if (proc != NULL) { 275 typedef BOOL(WINAPI *revertWow64FuncType)(PVOID); 276 revertWow64FuncType funcPtr = (revertWow64FuncType)proc; 277 funcPtr(oldWow64Value); 278 } 279 280 FreeLibrary(hmod); 281 } 282 } 283