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