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