VirtualBox

Changeset 43850 in vbox


Ignore:
Timestamp:
Nov 9, 2012 1:28:58 PM (12 years ago)
Author:
vboxsync
Message:

Installer/win/Stub/VBoxStub.cpp: Fixed broken parameter handling by rewriting it to use RTGetOpt. -msiparam didn't work and had to be at the end of the parameter list. More than one -path would concatenate with instead of overwrite the previous values. Returning 0 (success) on syntax error. Poping up message boxes on errors in silent mode.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Installer/win/Stub/VBoxStub.cpp

    r39613 r43850  
    3636#include <iprt/file.h>
    3737#include <iprt/initterm.h>
     38#include <iprt/getopt.h>
    3839#include <iprt/mem.h>
     40#include <iprt/message.h>
    3941#include <iprt/path.h>
    4042#include <iprt/param.h>
     43#include <iprt/stream.h>
    4144#include <iprt/string.h>
    4245#include <iprt/thread.h>
     
    5154
    5255
    53 /**
    54  * Shows a message box with a printf() style formatted string.
    55  *
    56  * @returns Message box result (IDOK, IDCANCEL, ...).
    57  *
    58  * @param   uType               Type of the message box (see MSDN).
     56/*******************************************************************************
     57*   Global Variables                                                           *
     58*******************************************************************************/
     59static bool g_fSilent = false;
     60
     61
     62/**
     63 * Shows an error message box with a printf() style formatted string.
     64 *
    5965 * @param   pszFmt              Printf-style format string to show in the message box body.
    6066 *
    6167 */
    62 static int ShowInfo(const char *pszFmt, ...)
     68static void ShowError(const char *pszFmt, ...)
    6369{
    6470    char       *pszMsg;
     
    6672
    6773    va_start(va, pszFmt);
    68     RTStrAPrintfV(&pszMsg, pszFmt, va);
    69     va_end(va);
    70 
    71     int rc;
    72     if (pszMsg)
    73         rc = MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION);
    74     else
    75         rc = MessageBox(GetDesktopWindow(), pszFmt, VBOX_STUB_TITLE, MB_ICONINFORMATION);
    76     RTStrFree(pszMsg);
    77     return rc;
    78 }
    79 
    80 
    81 /**
    82  * Shows an error message box with a printf() style formatted string.
    83  *
    84  * @returns Message box result (IDOK, IDCANCEL, ...).
    85  *
    86  * @param   pszFmt              Printf-style format string to show in the message box body.
    87  *
    88  */
    89 static int ShowError(const char *pszFmt, ...)
    90 {
    91     char       *pszMsg;
    92     va_list     va;
    93     int         rc;
    94 
    95     va_start(va, pszFmt);
    9674    if (RTStrAPrintfV(&pszMsg, pszFmt, va))
    9775    {
    98         rc = MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR);
     76        if (g_fSilent)
     77            RTMsgError("%s", pszMsg);
     78        else
     79            MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR);
    9980        RTStrFree(pszMsg);
    10081    }
     
    10283        AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
    10384    va_end(va);
    104     return rc;
     85}
     86
     87
     88/**
     89 * Shows a message box with a printf() style formatted string.
     90 *
     91 * @param   uType               Type of the message box (see MSDN).
     92 * @param   pszFmt              Printf-style format string to show in the message box body.
     93 *
     94 */
     95static void ShowInfo(const char *pszFmt, ...)
     96{
     97    char       *pszMsg;
     98    va_list     va;
     99    va_start(va, pszFmt);
     100    int rc = RTStrAPrintfV(&pszMsg, pszFmt, va);
     101    va_end(va);
     102    if (rc >= 0)
     103    {
     104        if (g_fSilent)
     105            RTPrintf("%s\n", pszMsg);
     106        else
     107            MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION);
     108    }
     109    else /* Should never happen! */
     110        AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
     111    RTStrFree(pszMsg);
    105112}
    106113
     
    316323        s.pTo = szDest;
    317324        s.pFrom = szSource;
    318         s.fFlags = FOF_SILENT |
    319                    FOF_NOCONFIRMATION |
    320                    FOF_NOCONFIRMMKDIR |
    321                    FOF_NOERRORUI;
     325        s.fFlags = FOF_SILENT
     326                 | FOF_NOCONFIRMATION
     327                 | FOF_NOCONFIRMMKDIR
     328                 | FOF_NOERRORUI;
    322329    }
    323330    return RTErrConvertFromWin32(SHFileOperation(&s));
     
    335342    /* Check if we're already running and jump out if so. */
    336343    /* Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
    337     HANDLE hMutexAppRunning = CreateMutex (NULL, FALSE, "VBoxStubInstaller");
     344    HANDLE hMutexAppRunning = CreateMutex(NULL, FALSE, "VBoxStubInstaller");
    338345    if (   (hMutexAppRunning != NULL)
    339346        && (GetLastError() == ERROR_ALREADY_EXISTS))
     
    350357        return vrc;
    351358
    352     BOOL fExtractOnly = FALSE;
    353     BOOL fSilent = FALSE;
    354     BOOL fEnableLogging = FALSE;
    355     BOOL fExit = FALSE;
    356 
    357     /* Temp variables for arguments. */
     359    /*
     360     * Parse arguments.
     361     */
     362
     363    /* Parameter variables. */
     364    bool fExtractOnly              = false;
     365    bool fEnableLogging            = false;
    358366    char szExtractPath[RTPATH_MAX] = {0};
    359     char szMSIArgs[RTPATH_MAX] = {0};
    360 
    361     /* Process arguments. */
    362     for (int i = 0; i < argc; i++)
    363     {
    364         if (   (0 == RTStrICmp(argv[i], "-x"))
    365             || (0 == RTStrICmp(argv[i], "-extract"))
    366             || (0 == RTStrICmp(argv[i], "/extract")))
    367         {
    368             fExtractOnly = TRUE;
    369         }
    370 
    371         else if (   (0 == RTStrICmp(argv[i], "-s"))
    372                  || (0 == RTStrICmp(argv[i], "-silent"))
    373                  || (0 == RTStrICmp(argv[i], "/silent")))
    374         {
    375             fSilent = TRUE;
    376         }
    377 
    378         else if (   (0 == RTStrICmp(argv[i], "-l"))
    379                  || (0 == RTStrICmp(argv[i], "-logging"))
    380                  || (0 == RTStrICmp(argv[i], "/logging")))
    381         {
    382             fEnableLogging = TRUE;
    383         }
    384 
    385         else if ((  (0 == RTStrICmp(argv[i], "-p"))
    386                  || (0 == RTStrICmp(argv[i], "-path"))
    387                  || (0 == RTStrICmp(argv[i], "/path")))
    388                  )
    389         {
    390             if (argc > i)
    391             {
    392                 vrc = ::StringCbCat(szExtractPath, sizeof(szExtractPath), argv[i+1]);
    393                 i++; /* Avoid the specified path from being parsed. */
    394             }
    395             else
    396             {
    397                 ShowError("No path for extraction specified!");
    398                 fExit = TRUE;
    399             }
    400         }
    401 
    402         else if ((  (0 == RTStrICmp(argv[i], "-msiparams"))
    403                  || (0 == RTStrICmp(argv[i], "/msiparams")))
    404                  && (argc > i))
    405         {
    406             for (int a = i + 1; a < argc; a++)
    407             {
    408                 if (a > i+1) /* Insert a space. */
    409                     vrc = ::StringCbCat(szMSIArgs, sizeof(szMSIArgs), " ");
    410 
    411                 vrc = ::StringCbCat(szMSIArgs, sizeof(szMSIArgs), argv[a]);
    412             }
    413         }
    414 
    415         else if (   (0 == RTStrICmp(argv[i], "-v"))
    416                  || (0 == RTStrICmp(argv[i], "-version"))
    417                  || (0 == RTStrICmp(argv[i], "/version")))
    418         {
    419             ShowInfo("Version: %d.%d.%d.%d",
    420                      VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
    421             fExit = TRUE;
    422         }
    423 
    424         else if (   (0 == RTStrICmp(argv[i], "-help"))
    425                  || (0 == RTStrICmp(argv[i], "/help"))
    426                  || (0 == RTStrICmp(argv[i], "/?")))
    427         {
    428             ShowInfo("-- %s v%d.%d.%d.%d --\n"
     367    char szMSIArgs[4096]           = {0};
     368
     369    /* Parameter definitions. */
     370    static const RTGETOPTDEF s_aOptions[] =
     371    {
     372        { "--extract",          'x', RTGETOPT_REQ_NOTHING },
     373        { "-extract",           'x', RTGETOPT_REQ_NOTHING },
     374        { "/extract",           'x', RTGETOPT_REQ_NOTHING },
     375        { "--silent",           's', RTGETOPT_REQ_NOTHING },
     376        { "-silent",            's', RTGETOPT_REQ_NOTHING },
     377        { "/silent",            's', RTGETOPT_REQ_NOTHING },
     378        { "--logging",          'l', RTGETOPT_REQ_NOTHING },
     379        { "-logging",           'l', RTGETOPT_REQ_NOTHING },
     380        { "/logging",           'l', RTGETOPT_REQ_NOTHING },
     381        { "--path",             'p', RTGETOPT_REQ_STRING  },
     382        { "-path",              'p', RTGETOPT_REQ_STRING  },
     383        { "/path",              'p', RTGETOPT_REQ_STRING  },
     384        { "--msiparams",        'm', RTGETOPT_REQ_STRING  },
     385        { "-msiparams",         'm', RTGETOPT_REQ_STRING  },
     386        { "--version",          'V', RTGETOPT_REQ_NOTHING },
     387        { "-version",           'V', RTGETOPT_REQ_NOTHING },
     388        { "/version",           'V', RTGETOPT_REQ_NOTHING },
     389        { "-v",                 'V', RTGETOPT_REQ_NOTHING },
     390        { "--help",             'h', RTGETOPT_REQ_NOTHING },
     391        { "-help",              'h', RTGETOPT_REQ_NOTHING },
     392        { "/help",              'h', RTGETOPT_REQ_NOTHING },
     393        { "/?",                 'h', RTGETOPT_REQ_NOTHING },
     394    };
     395
     396    /* Parse the parameters. */
     397    int ch;
     398    RTGETOPTUNION ValueUnion;
     399    RTGETOPTSTATE GetState;
     400    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
     401    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
     402    {
     403        switch (ch)
     404        {
     405            case 'x':
     406                fExtractOnly = true;
     407                break;
     408
     409            case 's':
     410                g_fSilent = true;
     411                break;
     412
     413            case 'l':
     414                fEnableLogging = true;
     415                break;
     416
     417            case 'p':
     418                vrc = RTStrCopy(szExtractPath, sizeof(szExtractPath), ValueUnion.psz);
     419                if (RT_FAILURE(vrc))
     420                {
     421                    ShowError("Extraction path is too long.");
     422                    return RTEXITCODE_FAILURE;
     423                }
     424                break;
     425
     426            case 'm':
     427                if (szMSIArgs[0])
     428                    vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), " ");
     429                if (RT_SUCCESS(vrc))
     430                    vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz);
     431                if (RT_FAILURE(vrc))
     432                {
     433                    ShowError("MSI parameters are too long.");
     434                    return RTEXITCODE_FAILURE;
     435                }
     436                break;
     437
     438            case 'V':
     439                ShowInfo("Version: %d.%d.%d.%d",
     440                         VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
     441                return VINF_SUCCESS;
     442
     443            case 'h':
     444                ShowInfo("-- %s v%d.%d.%d.%d --\n"
    429445                         "Command Line Parameters:\n\n"
    430                          "-extract | -x           - Extract file contents to temporary directory\n"
    431                          "-silent | -s            - Enables silent mode installation\n"
    432                          "-path | -p              - Sets the path of the extraction directory\n"
    433                          "-help | /?              - Print this help and exit\n"
    434                          "-msiparams <parameters> - Specifies extra parameters for the MSI installers\n"
    435                          "-logging | -l           - Enables installer logging\n"
    436                          "-version | -v           - Print version number and exit\n\n"
     446                         "--extract                - Extract file contents to temporary directory\n"
     447                         "--silent                 - Enables silent mode installation\n"
     448                         "--path                   - Sets the path of the extraction directory\n"
     449                         "--msiparams <parameters> - Specifies extra parameters for the MSI installers\n"
     450                         "--logging                - Enables installer logging\n"
     451                         "--help                   - Print this help and exit\n"
     452                         "--version                - Print version number and exit\n\n"
    437453                         "Examples:\n"
    438                          "%s -msiparams INSTALLDIR=C:\\VBox\n"
    439                          "%s -extract -path C:\\VBox\n",
     454                         "%s --msiparams INSTALLDIR=C:\\VBox\n"
     455                         "%s --extract -path C:\\VBox",
    440456                         VBOX_STUB_TITLE, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
    441457                         argv[0], argv[0]);
    442             fExit = TRUE;
    443         }
    444         else
    445         {
    446             if (i > 0)
    447             {
    448                 ShowError("Unknown option \"%s\"!\n"
    449                           "Please refer to the command line help by specifying \"/?\"\n"
    450                           "to get more information.", argv[i]);
    451                 fExit = TRUE;
    452             }
    453         }
    454     }
    455 
    456     if (fExit)
    457         return 0;
     458                return VINF_SUCCESS;
     459
     460            default:
     461                if (g_fSilent)
     462                    return RTGetOptPrintError(ch, &ValueUnion);
     463                if (ch == VINF_GETOPT_NOT_OPTION || ch == VERR_GETOPT_UNKNOWN_OPTION)
     464                    ShowError("Unknown option \"%s\"!\n"
     465                              "Please refer to the command line help by specifying \"/?\"\n"
     466                              "to get more information.", ValueUnion.psz);
     467                else
     468                    ShowError("Parameter parsing error: %Rrc\n"
     469                              "Please refer to the command line help by specifying \"/?\"\n"
     470                              "to get more information.", ch);
     471                return RTEXITCODE_SYNTAX;
     472
     473        }
     474    }
    458475
    459476    HRESULT hr = S_OK;
     
    551568                    {
    552569                        /* Set UI level. */
    553                         INSTALLUILEVEL UILevel = MsiSetInternalUI(  fSilent
     570                        INSTALLUILEVEL UILevel = MsiSetInternalUI(  g_fSilent
    554571                                                                  ? INSTALLUILEVEL_NONE
    555572                                                                  : INSTALLUILEVEL_FULL,
     
    585602                            && (uStatus != ERROR_INSTALL_USEREXIT))
    586603                        {
    587                             if (!fSilent)
     604                            switch (uStatus)
    588605                            {
    589                                 switch (uStatus)
     606                                case ERROR_INSTALL_PACKAGE_VERSION:
     607                                    ShowError("This installation package cannot be installed by the Windows Installer service.\n"
     608                                              "You must install a Windows service pack that contains a newer version of the Windows Installer service.");
     609                                    break;
     610
     611                                case ERROR_INSTALL_PLATFORM_UNSUPPORTED:
     612                                    ShowError("This installation package is not supported on this platform.");
     613                                    break;
     614
     615                                default:
    590616                                {
    591                                     case ERROR_INSTALL_PACKAGE_VERSION:
    592 
    593                                         ShowError("This installation package cannot be installed by the Windows Installer service.\n"
    594                                                   "You must install a Windows service pack that contains a newer version of the Windows Installer service.");
    595                                         break;
    596 
    597                                     case ERROR_INSTALL_PLATFORM_UNSUPPORTED:
    598 
    599                                         ShowError("This installation package is not supported on this platform.");
    600                                         break;
    601 
    602                                     default:
     617                                    DWORD dwFormatFlags =   FORMAT_MESSAGE_ALLOCATE_BUFFER
     618                                                          | FORMAT_MESSAGE_IGNORE_INSERTS
     619                                                          | FORMAT_MESSAGE_FROM_SYSTEM;
     620                                    HMODULE hModule = NULL;
     621                                    if (uStatus >= NERR_BASE && uStatus <= MAX_NERR)
    603622                                    {
    604                                         DWORD dwFormatFlags =   FORMAT_MESSAGE_ALLOCATE_BUFFER
    605                                                               | FORMAT_MESSAGE_IGNORE_INSERTS
    606                                                               | FORMAT_MESSAGE_FROM_SYSTEM;
    607                                         HMODULE hModule = NULL;
    608                                         if (uStatus >= NERR_BASE && uStatus <= MAX_NERR)
    609                                         {
    610                                             hModule = LoadLibraryEx(TEXT("netmsg.dll"),
    611                                                                     NULL,
    612                                                                     LOAD_LIBRARY_AS_DATAFILE);
    613                                             if (hModule != NULL)
    614                                                 dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
    615                                         }
    616 
    617                                         DWORD dwBufferLength;
    618                                         LPSTR szMessageBuffer;
    619                                         if (dwBufferLength = FormatMessageA(dwFormatFlags,
    620                                                                             hModule, /* If NULL, load system stuff. */
    621                                                                             uStatus,
    622                                                                             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    623                                                                             (LPSTR)&szMessageBuffer,
    624                                                                             0,
    625                                                                             NULL))
    626                                         {
    627                                             ShowError("Installation failed! Error: %s", szMessageBuffer);
    628                                             LocalFree(szMessageBuffer);
    629                                         }
    630                                         else /* If text lookup failed, show at least the error number. */
    631                                             ShowError("Installation failed! Error: %u", uStatus);
    632                                         if (hModule)
    633                                             FreeLibrary(hModule);
    634                                         break;
     623                                        hModule = LoadLibraryEx(TEXT("netmsg.dll"),
     624                                                                NULL,
     625                                                                LOAD_LIBRARY_AS_DATAFILE);
     626                                        if (hModule != NULL)
     627                                            dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
    635628                                    }
     629
     630                                    DWORD dwBufferLength;
     631                                    LPSTR szMessageBuffer;
     632                                    if (dwBufferLength = FormatMessageA(dwFormatFlags,
     633                                                                        hModule, /* If NULL, load system stuff. */
     634                                                                        uStatus,
     635                                                                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     636                                                                        (LPSTR)&szMessageBuffer,
     637                                                                        0,
     638                                                                        NULL))
     639                                    {
     640                                        ShowError("Installation failed! Error: %s", szMessageBuffer);
     641                                        LocalFree(szMessageBuffer);
     642                                    }
     643                                    else /* If text lookup failed, show at least the error number. */
     644                                        ShowError("Installation failed! Error: %u", uStatus);
     645                                    if (hModule)
     646                                        FreeLibrary(hModule);
     647                                    break;
    636648                                }
    637649                            }
     
    663675    {
    664676        if (   fExtractOnly
    665             && !fSilent)
     677            && !g_fSilent)
    666678        {
    667679            ShowInfo("Files were extracted to: %s", szExtractPath);
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