VirtualBox

Changeset 39742 in vbox for trunk/src/VBox/Additions


Ignore:
Timestamp:
Jan 10, 2012 5:47:55 PM (13 years ago)
Author:
vboxsync
Message:

Loader/VBoxWindowsAdditions.cpp: Made it more robust and scripting friendly.

  • Don't forget to quote the executable or it will misbehave when started from a directory with spaces in the path.
  • Don't unquote arguments.
  • Don't truncate arguments to _MAX_LEN.
  • Check for overflows/truncated returns from GetModuleName and GetCurrentDirectory so as to not misbehave when this happens.
  • Wait for the real install process to finish executing before returning.
  • Just use WCHAR all the way, forget TCHAR and UNICODE.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp

    r31661 r39742  
    11/* $Id$ */
    22/** @file
    3  * VBoxWindowsAdditions - The Windows Guest Additions Loader
     3 * VBoxWindowsAdditions - The Windows Guest Additions Loader.
     4 *
     5 * This is STUB which select whether to install 32-bit or 64-bit additions.
    46 */
    57
    68/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     9 * Copyright (C) 2006-2012 Oracle Corporation
    810 *
    911 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1618 */
    1719
    18 #ifndef UNICODE
    19 #define UNICODE
     20/*******************************************************************************
     21*   Header Files                                                               *
     22*******************************************************************************/
     23#include <Windows.h>
     24#ifndef ERROR_ELEVATION_REQUIRED    /* Windows Vista and later. */
     25# define ERROR_ELEVATION_REQUIRED  740
    2026#endif
    2127
    22 #include <windows.h>
    2328#include <stdio.h>
    24 #include <tchar.h>
    25 
    26 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    27 
    28 LPFN_ISWOW64PROCESS fnIsWow64Process;
    29 
    30 BOOL IsWow64 ()
     29#include <string.h>
     30
     31
     32static BOOL IsWow64(void)
    3133{
    3234    BOOL bIsWow64 = FALSE;
    33     fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
    34 
    35     if (NULL != fnIsWow64Process)
     35    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
     36    LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(L"kernel32"), "IsWow64Process");
     37    if (fnIsWow64Process != NULL)
    3638    {
    3739        if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
    3840        {
    39             _tprintf(_T("ERROR: Could not determine process type!\n"));
     41            fwprintf(stderr, L"ERROR: Could not determine process type!\n");
    4042
    4143            /* Error in retrieving process type - assume that we're running on 32bit. */
    42             return FALSE;
     44            bIsWow64 = FALSE;
    4345        }
    4446    }
     
    4648}
    4749
    48 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    49 {
     50static void WaitForProcess2(HANDLE hProcess, int *piExitCode)
     51{
     52    /*
     53     * Wait for the process, make sure the deal with messages.
     54     */
     55    for (;;)
     56    {
     57        DWORD dwRc = MsgWaitForMultipleObjects(1, &hProcess, FALSE, 5000/*ms*/, QS_ALLEVENTS);
     58
     59        MSG Msg;
     60        while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
     61        {
     62            TranslateMessage(&Msg);
     63            DispatchMessageW(&Msg);
     64        }
     65
     66        if (dwRc == WAIT_OBJECT_0)
     67            break;
     68        if (   dwRc != WAIT_TIMEOUT
     69            && dwRc != WAIT_OBJECT_0 + 1)
     70        {
     71            fwprintf(stderr, L"ERROR: MsgWaitForMultipleObjects failed: %u (%u)\n", dwRc, GetLastError());
     72            break;
     73        }
     74    }
     75
     76    /*
     77     * Collect the process info.
     78     */
     79    DWORD dwExitCode;
     80    if (GetExitCodeProcess(hProcess, &dwExitCode))
     81        *piExitCode = (int)dwExitCode;
     82    else
     83    {
     84        fwprintf(stderr, L"ERROR: GetExitCodeProcess failed: %u\n", GetLastError());
     85        *piExitCode = 16;
     86    }
     87}
     88
     89static void WaitForProcess(HANDLE hProcess, int *piExitCode)
     90{
     91    DWORD WaitRc = WaitForSingleObjectEx(hProcess, INFINITE, TRUE);
     92    while (   WaitRc == WAIT_IO_COMPLETION
     93           || WaitRc == WAIT_TIMEOUT)
     94        WaitRc = WaitForSingleObjectEx(hProcess, INFINITE, TRUE);
     95    if (WaitRc == WAIT_OBJECT_0)
     96    {
     97        DWORD dwExitCode;
     98        if (GetExitCodeProcess(hProcess, &dwExitCode))
     99            *piExitCode = (int)dwExitCode;
     100        else
     101        {
     102            fwprintf(stderr, L"ERROR: GetExitCodeProcess failed: %u\n", GetLastError());
     103            *piExitCode = 16;
     104        }
     105    }
     106    else
     107    {
     108        fwprintf(stderr, L"ERROR: WaitForSingleObjectEx failed: %u (%u)\n", WaitRc, GetLastError());
     109        *piExitCode = 16;
     110    }
     111}
     112
     113int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
     114{
     115    /*
     116     * Gather the parameters of the real installer program.
     117     */
     118
     119    SetLastError(NO_ERROR);
     120    WCHAR wszCurDir[_MAX_PATH] = { 0 };
     121    DWORD cchCurDir = GetCurrentDirectoryW(sizeof(wszCurDir), wszCurDir);
     122    if (cchCurDir == 0 || cchCurDir >= sizeof(wszCurDir))
     123    {
     124        fwprintf(stderr, L"ERROR: GetCurrentDirectoryW failed: %u (ret %u)\n", GetLastError(), cchCurDir);
     125        return 12;
     126    }
     127
     128    SetLastError(NO_ERROR);
     129    WCHAR wszModule[_MAX_PATH] = { 0 };
     130    DWORD cchModule = GetModuleFileNameW(NULL, wszModule, sizeof(wszModule));
     131    if (cchModule == 0 || cchModule >= sizeof(wszModule))
     132    {
     133        fwprintf(stderr, L"ERROR: GetModuleFileNameW failed: %u (ret %u)\n", GetLastError(), cchModule);
     134        return 13;
     135    }
     136
     137    /* Strip the extension off the module name and construct the arch specific
     138       one of the real installer program. */
     139    DWORD off = cchModule - 1;
     140    while (   off > 0
     141           && (   wszModule[off] != '/'
     142               && wszModule[off] != '\\'
     143               && wszModule[off] != ':'))
     144    {
     145        if (wszModule[off] == '.')
     146        {
     147            wszModule[off] = '\0';
     148            cchModule = off;
     149            break;
     150        }
     151        off--;
     152    }
     153
     154    WCHAR const  *pwszSuff = IsWow64() ? L"-amd64.exe" : L"-x86.exe";
     155    size_t        cchSuff  = wcslen(pwszSuff);
     156    if (cchSuff + cchModule >= sizeof(wszModule))
     157    {
     158        fwprintf(stderr, L"ERROR: Real installer name is too long (%u chars)\n", cchSuff + cchModule);
     159        return 14;
     160    }
     161    wcscpy(&wszModule[cchModule], pwszSuff);
     162    cchModule += cchSuff;
     163
     164    /* Replace the first argument of the argument list. */
     165    PWCHAR  pwszNewCmdLine = NULL;
     166    LPCWSTR pwszOrgCmdLine = GetCommandLineW();
     167    if (pwszOrgCmdLine) /* Dunno if this can be NULL, but whatever. */
     168    {
     169        /* Skip the first argument in the original. */
     170        /** @todo Is there some ISBLANK or ISSPACE macro/function in Win32 that we could
     171         *        use here, if it's correct wrt. command line conventions? */
     172        WCHAR wch;
     173        while ((wch = *pwszOrgCmdLine) == L' ' || wch == L'\t')
     174            pwszOrgCmdLine++;
     175        if (wch == L'"')
     176        {
     177            pwszOrgCmdLine++;
     178            while ((wch = *pwszOrgCmdLine) != L'\0')
     179            {
     180                pwszOrgCmdLine++;
     181                if (wch == L'"')
     182                    break;
     183            }
     184        }
     185        else
     186        {
     187            while ((wch = *pwszOrgCmdLine) != L'\0')
     188            {
     189                pwszOrgCmdLine++;
     190                if (wch == L' ' || wch == L'\t')
     191                    break;
     192            }
     193        }
     194        while ((wch = *pwszOrgCmdLine) == L' ' || wch == L'\t')
     195            pwszOrgCmdLine++;
     196
     197        /* Join up "szModule" with the remainder of the original command line. */
     198        size_t cchOrgCmdLine = wcslen(pwszOrgCmdLine);
     199        size_t cchNewCmdLine = 1 + cchModule + 1 + 1 + cchOrgCmdLine + 1;
     200        PWCHAR pwsz = pwszNewCmdLine = (PWCHAR)LocalAlloc(LPTR, cchNewCmdLine * sizeof(WCHAR));
     201        if (!pwsz)
     202        {
     203            fwprintf(stderr, L"ERROR: Out of memory (%u bytes)\n", cchNewCmdLine);
     204            return 15;
     205        }
     206        *pwsz++ = L'"';
     207        wcscpy(pwsz, wszModule);
     208        pwsz += cchModule;
     209        *pwsz++ = L'"';
     210        if (cchOrgCmdLine)
     211        {
     212            *pwsz++ = L' ';
     213            wcscpy(pwsz, pwszOrgCmdLine);
     214        }
     215        else
     216            *pwsz = L'\0';
     217    }
     218
     219    /*
     220     * Start the process.
     221     */
    50222    int iRet = 0;
    51 
    52     LPWSTR *pszArgList = NULL;
    53     int nArgs = 0;
    54 
    55     TCHAR szCurDir[_MAX_PATH + 1] = { 0 };
    56     GetCurrentDirectory(_MAX_PATH, szCurDir);
    57 
    58     SHELLEXECUTEINFOW TempInfo = { 0 };
    59     TempInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
    60 
    61     TCHAR szModule[_MAX_PATH + 1] = { 0 };
    62     TCHAR szApp[_MAX_PATH + 1] = { 0 };
    63     TCHAR szProg[_MAX_PATH + 1] = { 0 };
    64 
    65     pszArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);
    66     if (0 == GetModuleFileName(NULL, szModule, _MAX_PATH))
    67     {
    68         /* Module not found, use a default name. */
    69         _stprintf(szModule, _T("%ws"), (pszArgList != NULL) ? pszArgList[0] : _T("VBoxWindowsAdditions.exe"));
    70     }
    71 
    72     TCHAR* pcExt = wcsrchr(szModule, _T('.'));
    73     if (NULL != pcExt)
    74         wcsncpy(szApp, szModule, (pcExt - szModule));
    75 
    76     if (IsWow64()) /* 64bit Windows. */
    77     {
    78         _stprintf(szProg, _T("%ws-amd64.exe"), szApp);
    79     }
    80     else /* 32bit Windows. */
    81     {
    82         _stprintf(szProg, _T("%ws-x86.exe"), szApp);
    83     }
    84 
    85     /* Construct parameter list. */
    86     TCHAR *pszParams = (TCHAR*)LocalAlloc(LPTR, _MAX_PATH*sizeof(TCHAR));
    87     TCHAR szDelim = _T(' ');
    88 
    89     if (pszParams)
    90     {
    91         wcsncat(pszParams, szProg,
    92                         __min(wcslen(szProg),_MAX_PATH-wcslen(pszParams)));
    93         wcsncat(pszParams, &szDelim,
    94                         __min(1,_MAX_PATH-wcslen(pszParams)));
    95 
    96         if (nArgs > 1)
    97         {
    98             for (int i=0; i<nArgs-1; i++)
    99             {
    100                 if (i > 0)
    101                 {
    102                     wcsncat(pszParams, &szDelim,
    103                         __min(1,_MAX_PATH-wcslen(pszParams)));
    104                 }
    105                 wcsncat(pszParams, pszArgList[i+1],
    106                         __min(wcslen(pszArgList[i+1]),_MAX_PATH-wcslen(pszParams)));
    107             }
    108         }
    109     }
    110 
    111     /* Struct for ShellExecute. */
    112     TempInfo.fMask = 0;
    113     TempInfo.hwnd = NULL;
    114     TempInfo.lpVerb =L"runas" ;
    115     TempInfo.lpFile = szProg;
    116     TempInfo.lpParameters = pszParams;
    117     TempInfo.lpDirectory = szCurDir;
    118     TempInfo.nShow = SW_NORMAL;
    119 
    120     STARTUPINFOW si;
    121     PROCESS_INFORMATION pi;
    122     DWORD dwRes = 0;
    123 
    124     ZeroMemory(&si, sizeof(si));
    125     si.cb = sizeof(si);
    126     ZeroMemory(&pi, sizeof(pi));
    127 
    128     dwRes = CreateProcessW(szProg, pszParams, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
    129     if (!dwRes && GetLastError() == 740) /* 740 = ERROR_ELEVATION_REQUIRED -> Only for Windows Vista. */
    130     {
    131         if (FALSE == ::ShellExecuteExW(&TempInfo))
    132         {
    133             _tprintf (_T("ERROR: Could not launch program! Code: %ld\n"), GetLastError());
    134             iRet = 1;
    135         }
    136     }
    137 
    138     if (pszParams)
    139         LocalFree(pszParams);
    140 
    141     if (pszArgList)
    142         LocalFree(pszArgList);
    143 
     223    STARTUPINFOW        StartupInfo = { sizeof(StartupInfo), 0 };
     224    PROCESS_INFORMATION ProcInfo = { 0 };
     225    SetLastError(740);
     226    BOOL fOk = CreateProcessW(wszModule,
     227                              pwszNewCmdLine,
     228                              NULL /*pProcessAttributes*/,
     229                              NULL /*pThreadAttributes*/,
     230                              TRUE /*fInheritHandles*/,
     231                              0 /*dwCreationFlags*/,
     232                              NULL /*pEnvironment*/,
     233                              NULL /*pCurrentDirectory*/,
     234                              &StartupInfo,
     235                              &ProcInfo);
     236    if (fOk)
     237    {
     238        /* Wait for the process to finish. */
     239        CloseHandle(ProcInfo.hThread);
     240        WaitForProcess(ProcInfo.hProcess, &iRet);
     241        CloseHandle(ProcInfo.hProcess);
     242    }
     243    else if (GetLastError() == ERROR_ELEVATION_REQUIRED)
     244    {
     245        /*
     246         * Elevation is required. That can be accomplished via ShellExecuteEx
     247         * and the runas atom.
     248         */
     249        MSG Msg;
     250        PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE);
     251        CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
     252
     253        SHELLEXECUTEINFOW ShExecInfo = { 0 };
     254        ShExecInfo.cbSize       = sizeof(SHELLEXECUTEINFOW);
     255        ShExecInfo.fMask        = SEE_MASK_NOCLOSEPROCESS;
     256        ShExecInfo.hwnd         = NULL;
     257        ShExecInfo.lpVerb       = L"runas" ;
     258        ShExecInfo.lpFile       = wszModule;
     259        ShExecInfo.lpParameters = pwszNewCmdLine;
     260        ShExecInfo.lpDirectory  = wszCurDir;
     261        ShExecInfo.nShow        = SW_NORMAL;
     262        ShExecInfo.hProcess     = INVALID_HANDLE_VALUE;
     263        if (ShellExecuteExW(&ShExecInfo))
     264        {
     265            if (ShExecInfo.hProcess != INVALID_HANDLE_VALUE)
     266            {
     267                WaitForProcess2(ShExecInfo.hProcess, &iRet);
     268                CloseHandle(ShExecInfo.hProcess);
     269            }
     270            else
     271            {
     272                fwprintf(stderr, L"ERROR: ShellExecuteExW did not return a valid process handle!\n");
     273                iRet = 1;
     274            }
     275        }
     276        else
     277        {
     278            fwprintf(stderr, L"ERROR: Failed to execute '%ws' via ShellExecuteExW: %u\n", wszModule, GetLastError());
     279            iRet = 9;
     280        }
     281    }
     282    else
     283    {
     284        fwprintf(stderr, L"ERROR: Failed to execute '%ws' via CreateProcessW: %u\n", wszModule, GetLastError());
     285        iRet = 8;
     286    }
     287
     288    if (pwszNewCmdLine)
     289        LocalFree(pwszNewCmdLine);
     290
     291#if 0
     292    fwprintf(stderr, L"DEBUG: iRet=%d\n", iRet);
     293    fflush(stderr);
     294#endif
    144295    return iRet;
    145296}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette