Home | History | Annotate | Download | only in src
      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