VirtualBox

Ignore:
Timestamp:
Apr 3, 2013 8:16:56 PM (12 years ago)
Author:
vboxsync
Message:

VBoxStub: Split up main and changed the code to talk more unicode with windows. Mostly untested!

Location:
trunk/src/VBox/Installer/win/Stub
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Installer/win/Stub/Makefile.kmk

    r43894 r45320  
    2222if "$(KBUILD_TARGET_ARCH)" == "x86"
    2323
    24 TEMPLATE_VBOXSTUB = Drop the signing, we will sign it later.
    25 TEMPLATE_VBOXSTUB_EXTENDS = VBOXR3STATIC
    26 TEMPLATE_VBOXSTUB_POST_CMDS = $(NO_SUCH_VARIABLE)
     24 TEMPLATE_VBOXSTUB = Drop the signing, we will sign it later.
     25 TEMPLATE_VBOXSTUB_EXTENDS = VBOXR3STATIC
     26 TEMPLATE_VBOXSTUB_POST_CMDS = $(NO_SUCH_VARIABLE)
    2727
    28 PROGRAMS.x86 += VBoxStub
    29 VBoxStub_TEMPLATE= VBOXSTUB
    30 VBoxStub_DEFS    = _WIN32_WINNT=0x0501 IN_RT_R3
     28 PROGRAMS += VBoxStub
     29 VBoxStub_TEMPLATE= VBOXSTUB
     30 VBoxStub_DEFS    = _WIN32_WINNT=0x0501 IN_RT_R3
    3131
    32 VBoxStub_SOURCES = \
    33         VBoxStub.cpp \
    34         VBoxStub.rc
     32 VBoxStub_SOURCES = \
     33        VBoxStub.cpp \
     34        VBoxStub.rc
    3535
    36 VBoxStub_SDKS += \
    37         VBOX_NTDLL
    38 VBoxStub_LIBS = \
    39         $(VBOX_LIB_RUNTIME_STATIC) \
    40         $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Msi.lib
     36 VBoxStub_SDKS += \
     37        VBOX_NTDLL
     38 VBoxStub_LIBS = \
     39        $(VBOX_LIB_RUNTIME_STATIC) \
     40        $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Msi.lib
    4141
    42 VBoxStub.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)
    43 VBoxStub.cpp_DEPS  = $(VBOX_SVN_REV_KMK)
     42 VBoxStub.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)
     43 VBoxStub.cpp_DEPS  = $(VBOX_SVN_REV_KMK)
    4444
    45 # If signing mode is enabled, then add the possibility to
    46 # install public certificate automatically in /silent mode
    47 ifdef VBOX_SIGNING_MODE
     45 # If signing mode is enabled, then add the possibility to
     46 # install public certificate automatically in /silent mode
     47 ifdef VBOX_SIGNING_MODE
    4848
    49 VBoxStub_SOURCES  += VBoxStubCertUtil.cpp
    50 VBoxStub_LIBS     += crypt32.lib
    51 VBoxStub.cpp_DEPS += $(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h
    52 VBoxStub.cpp_INCS += $(VBoxStub_0_OUTDIR)
    53 VBoxStub.cpp_DEFS += VBOX_SIGNING_MODE
     49  VBoxStub_SOURCES  += VBoxStubCertUtil.cpp
     50  VBoxStub_LIBS     += crypt32.lib
     51  VBoxStub.cpp_DEPS += $(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h
     52  VBoxStub.cpp_INCS += $(VBoxStub_0_OUTDIR)
     53  VBoxStub.cpp_DEFS += VBOX_WITH_CODE_SIGNING
    5454
    55 $$(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h: $(VBOX_BIN2C) $(PATH_ROOT)/src/VBox/Additions/WINNT/tools/oracle-vbox.cer
     55  $$(VBoxStub_0_OUTDIR)/VBoxStubPublicCert.h: $(VBOX_BIN2C) $(PATH_ROOT)/src/VBox/Additions/WINNT/tools/oracle-vbox.cer
    5656        $(VBOX_BIN2C) _VBoxStubPublicCert $(PATH_ROOT)/src/VBox/Additions/WINNT/tools/oracle-vbox.cer $@
    5757
    58 endif
     58 endif
    5959
    60 # The icon location is configurable.
    61 VBoxStub.rc_INCS += $(VBoxStub_0_OUTDIR)
    62 VBoxStub.rc_DEPS += \
    63         $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \
    64         $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc
    65 VBoxStub.rc_CLEAN = \
    66         $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \
    67         $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc
     60 # The icon location is configurable.
     61 VBoxStub.rc_INCS += $(VBoxStub_0_OUTDIR)
     62 VBoxStub.rc_DEPS += \
     63        $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \
     64        $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc
     65 VBoxStub.rc_CLEAN = \
     66        $(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc \
     67        $(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc
    6868
    69 # Icon include file.
    70 $$(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc: $(VBOX_WINDOWS_ICON_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@)
     69 # Icon include file.
     70 $$(VBoxStub_0_OUTDIR)/VBoxStub-icon.rc: $(VBOX_WINDOWS_ICON_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@)
    7171        $(APPEND) -t $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ICON_FILE))"'
    7272
    73 # Manifest.
    74 VBOX_STUB_MANIFEST_FILE := $(PATH_SUB_CURRENT)/VBoxStub.manifest
    75 $$(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc: $(VBOX_STUB_MANIFEST_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@)
     73 # Manifest.
     74 VBOX_STUB_MANIFEST_FILE := $(PATH_SUB_CURRENT)/VBoxStub.manifest
     75 $$(VBoxStub_0_OUTDIR)/VBoxStub-manifest.rc: $(VBOX_STUB_MANIFEST_FILE) $(MAKEFILE_CURRENT) | $$(dir $$@)
    7676        $(APPEND) -t $@ 'APP_MANIFEST RT_MANIFEST "$(subst /,\\,$(VBOX_STUB_MANIFEST_FILE))"'
     77
    7778
    7879endif # x86 only
  • trunk/src/VBox/Installer/win/Stub/VBoxStub.cpp

    r45318 r45320  
    4949#include "resource.h"
    5050
    51 #ifdef VBOX_SIGNING_MODE
    52 #include "VBoxStubCertUtil.h"
    53 #include "VBoxStubPublicCert.h"
     51#ifdef VBOX_WITH_CODE_SIGNING
     52# include "VBoxStubCertUtil.h"
     53# include "VBoxStubPublicCert.h"
    5454#endif
    5555
    56 #ifndef  _UNICODE
     56#ifndef  _UNICODE /* Isn't this a little late? */
    5757#define  _UNICODE
    5858#endif
     
    6868 * Shows an error message box with a printf() style formatted string.
    6969 *
     70 * @returns RTEXITCODE_FAILURE
    7071 * @param   pszFmt              Printf-style format string to show in the message box body.
    7172 *
    7273 */
    73 static void ShowError(const char *pszFmt, ...)
     74static RTEXITCODE ShowError(const char *pszFmt, ...)
    7475{
    7576    char       *pszMsg;
     
    8889        AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
    8990    va_end(va);
     91    return RTEXITCODE_FAILURE;
    9092}
    9193
     
    119121
    120122/**
    121  * Reads data from a built-in resource.
    122  *
    123  * @returns iprt status code.
    124  *
    125  * @param   hInst               Instance to read the data from.
     123 * Finds the specified in the resource section of the executable.
     124 *
     125 * @returns IPRT status code.
     126 *
    126127 * @param   pszDataName         Name of resource to read.
    127  * @param   ppvResource         Pointer to buffer which holds the read resource data.
    128  * @param   pdwSize             Pointer which holds the read data size.
    129  *
    130  */
    131 static int ReadData(HINSTANCE   hInst,
    132                     const char *pszDataName,
     128 * @param   ppvResource         Where to return the pointer to the data.
     129 * @param   pdwSize             Where to return the size of the data (if found).
     130 *                              Optional.
     131 *
     132 */
     133static int FindData(const char *pszDataName,
    133134                    PVOID      *ppvResource,
    134135                    DWORD      *pdwSize)
    135136{
    136137    AssertReturn(pszDataName, VERR_INVALID_PARAMETER);
     138    HINSTANCE hInst = NULL;
    137139
    138140    /* Find our resource. */
     
    141143
    142144    /* Get resource size. */
    143     *pdwSize = SizeofResource(hInst, hRsrc);
    144     AssertReturn(*pdwSize > 0, VERR_NO_DATA);
     145    DWORD cb = SizeofResource(hInst, hRsrc);
     146    AssertReturn(cb > 0, VERR_NO_DATA);
     147    if (pdwSize)
     148        *pdwSize = cb;
    145149
    146150    /* Get pointer to resource. */
     
    156160
    157161/**
     162 * Finds the header for the given package.
     163 *
     164 * @returns Pointer to the package header on success.  On failure NULL is
     165 *          returned after ShowError has been invoked.
     166 * @param   iPackage            The package number.
     167 */
     168static PVBOXSTUBPKG FindPackageHeader(unsigned iPackage)
     169{
     170    char szHeaderName[32];
     171    RTStrPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", iPackage);
     172
     173    PVBOXSTUBPKG pPackage;
     174    int rc = FindData(szHeaderName, (PVOID *)&pPackage, NULL);
     175    if (RT_FAILURE(rc))
     176    {
     177        ShowError("Internal error: Could not find package header #%u: %Rrc", iPackage, rc);
     178        return NULL;
     179    }
     180
     181    /** @todo validate it. */
     182    return pPackage;
     183}
     184
     185
     186
     187/**
    158188 * Constructs a full temporary file path from the given parameters.
    159189 *
     
    199229        PVOID pvData = NULL;
    200230        DWORD dwDataSize = 0;
    201         rc = ReadData(NULL, pszResourceName, &pvData, &dwDataSize);
     231        rc = FindData(pszResourceName, &pvData, &dwDataSize);
    202232        AssertMsgRCBreak(rc, ("Could not read resource data!\n"));
    203233
     
    298328
    299329/**
    300  * Recursively copies a directory to another location.
    301  *
    302  * @returns iprt status code.
    303  *
    304  * @param   pszDestDir          Location to copy the source directory to.
    305  * @param   pszSourceDir        The source directory to copy.
    306  *
    307  */
    308 int CopyDir(const char *pszDestDir, const char *pszSourceDir)
    309 {
    310     char szDest[RTPATH_MAX + 1];
    311     char szSource[RTPATH_MAX + 1];
    312 
    313     AssertStmt(pszDestDir, "Destination directory invalid!");
    314     AssertStmt(pszSourceDir, "Source directory invalid!");
    315 
    316     SHFILEOPSTRUCT s = {0};
    317     if (   RTStrPrintf(szDest, _MAX_PATH, "%s%c", pszDestDir, '\0') > 0
    318         && RTStrPrintf(szSource, _MAX_PATH, "%s%c", pszSourceDir, '\0') > 0)
    319     {
    320         s.hwnd = NULL;
    321         s.wFunc = FO_COPY;
    322         s.pTo = szDest;
    323         s.pFrom = szSource;
    324         s.fFlags = FOF_SILENT
    325                  | FOF_NOCONFIRMATION
    326                  | FOF_NOCONFIRMMKDIR
    327                  | FOF_NOERRORUI;
    328     }
    329     return RTErrConvertFromWin32(SHFileOperation(&s));
     330 * Processes an MSI package.
     331 *
     332 * @returns Fully complained exit code.
     333 * @param   iPackage            The package number.
     334 * @param   pszMsi              The path to the MSI to process.
     335 * @param   pszMsiArgs          Any additional installer (MSI) argument
     336 * @param   fLogging            Whether to enable installer logging.
     337 */
     338static RTEXITCODE ProcessMsiPackage(unsigned iPackage, const char *pszMsi, const char *pszMsiArgs, bool fLogging)
     339{
     340    int rc;
     341
     342    /*
     343     * Set UI level.
     344     */
     345    INSTALLUILEVEL enmDesiredUiLevel = g_fSilent ? INSTALLUILEVEL_NONE : INSTALLUILEVEL_FULL;
     346    INSTALLUILEVEL enmRet = MsiSetInternalUI(enmDesiredUiLevel, NULL);
     347    if (enmRet == INSTALLUILEVEL_NOCHANGE /* means error */)
     348        return ShowError("Internal error: MsiSetInternalUI failed.");
     349
     350    /*
     351     * Enable logging?
     352     */
     353    if (fLogging)
     354    {
     355        char szLogFile[RTPATH_MAX];
     356        rc = RTStrCopy(szLogFile, sizeof(szLogFile), pszMsi);
     357        if (RT_SUCCESS(rc))
     358        {
     359            RTPathStripFilename(szLogFile);
     360            rc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxInstallLog.txt");
     361        }
     362        if (RT_FAILURE(rc))
     363            return ShowError("Internal error: Filename path too long.");
     364
     365        PRTUTF16 pwszLogFile;
     366        rc = RTStrToUtf16(szLogFile, &pwszLogFile);
     367        if (RT_FAILURE(rc))
     368            return ShowError("RTStrToUtf16 failed on '%s': %Rrc", szLogFile, rc);
     369
     370        UINT uLogLevel = MsiEnableLogW(INSTALLLOGMODE_VERBOSE,
     371                                       pwszLogFile,
     372                                       INSTALLLOGATTRIBUTES_FLUSHEACHLINE | (iPackage > 0 ? INSTALLLOGATTRIBUTES_APPEND : 0));
     373        RTUtf16Free(pwszLogFile);
     374        if (uLogLevel != ERROR_SUCCESS)
     375            return ShowError("MsiEnableLogW failed");
     376    }
     377
     378    /*
     379     * Initialize the common controls (extended version). This is necessary to
     380     * run the actual .MSI installers with the new fancy visual control
     381     * styles (XP+). Also, an integrated manifest is required.
     382     */
     383    INITCOMMONCONTROLSEX ccEx;
     384    ccEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
     385    ccEx.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS |
     386                 ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES |
     387                 ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES;
     388    InitCommonControlsEx(&ccEx); /* Ignore failure. */
     389
     390    /*
     391     * Convert both strings to UTF-16 and start the installation.
     392     */
     393    PRTUTF16 pwszMsi;
     394    rc = RTStrToUtf16(pszMsi, &pwszMsi);
     395    if (RT_FAILURE(rc))
     396        return ShowError("RTStrToUtf16 failed on '%s': %Rrc", pszMsi, rc);
     397    PRTUTF16 pwszMsiArgs;
     398    rc = RTStrToUtf16(pszMsiArgs, &pwszMsiArgs);
     399    if (RT_FAILURE(rc))
     400    {
     401        RTUtf16Free(pwszMsi);
     402        return ShowError("RTStrToUtf16 failed on '%s': %Rrc", pszMsi, rc);
     403    }
     404
     405    UINT uStatus = MsiInstallProductW(pwszMsi, pwszMsiArgs);
     406    RTUtf16Free(pwszMsi);
     407    RTUtf16Free(pwszMsiArgs);
     408
     409    if (uStatus == ERROR_SUCCESS)
     410        return RTEXITCODE_SUCCESS;
     411    if (uStatus == ERROR_SUCCESS_REBOOT_REQUIRED)
     412        return RTEXITCODE_SUCCESS; /* we currently don't indicate this */
     413
     414    /*
     415     * Installation failed. Figure out what to say.
     416     */
     417    switch (uStatus)
     418    {
     419        case ERROR_INSTALL_USEREXIT:
     420            /* Don't say anything? */
     421            break;
     422
     423        case ERROR_INSTALL_PACKAGE_VERSION:
     424            ShowError("This installation package cannot be installed by the Windows Installer service.\n"
     425                      "You must install a Windows service pack that contains a newer version of the Windows Installer service.");
     426            break;
     427
     428        case ERROR_INSTALL_PLATFORM_UNSUPPORTED:
     429            ShowError("This installation package is not supported on this platform.");
     430            break;
     431
     432        default:
     433        {
     434            /*
     435             * Try get windows to format the message.
     436             */
     437            DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER
     438                                | FORMAT_MESSAGE_IGNORE_INSERTS
     439                                | FORMAT_MESSAGE_FROM_SYSTEM;
     440            HMODULE hModule = NULL;
     441            if (uStatus >= NERR_BASE && uStatus <= MAX_NERR)
     442            {
     443                hModule = LoadLibraryEx(TEXT("netmsg.dll"),
     444                                        NULL,
     445                                        LOAD_LIBRARY_AS_DATAFILE);
     446                if (hModule != NULL)
     447                    dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
     448            }
     449
     450            /** @todo this is totally WRONG wrt to string code pages. We expect UTF-8
     451             *        while the ANSI code page might be one of the special Chinese ones,
     452             *        IPRT is going to be so angry with us (and so will the users). */
     453            DWORD dwBufferLength;
     454            LPSTR szMessageBuffer;
     455            if (dwBufferLength = FormatMessageA(dwFormatFlags,
     456                                                hModule, /* If NULL, load system stuff. */
     457                                                uStatus,
     458                                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     459                                                (LPSTR)&szMessageBuffer,
     460                                                0,
     461                                                NULL))
     462            {
     463                ShowError("Installation failed! Error: %s", szMessageBuffer);
     464                LocalFree(szMessageBuffer);
     465            }
     466            else /* If text lookup failed, show at least the error number. */
     467                ShowError("Installation failed! Error: %u", uStatus);
     468
     469            if (hModule)
     470                FreeLibrary(hModule);
     471            break;
     472        }
     473    }
     474
     475    return RTEXITCODE_FAILURE;
     476}
     477
     478
     479/**
     480 * Processes a package.
     481 *
     482 * @returns Fully complained exit code.
     483 * @param   iPackage            The package number.
     484 * @param   pszPkgDir           The package directory (aka extraction dir).
     485 * @param   pszMsiArgs          Any additional installer (MSI) argument
     486 * @param   fLogging            Whether to enable installer logging.
     487 */
     488static RTEXITCODE ProcessPackage(unsigned iPackage, const char *pszPkgDir, const char *pszMsiArgs, bool fLogging)
     489{
     490    /*
     491     * Get the package header and check if it's needed.
     492     */
     493    PVBOXSTUBPKG pPackage = FindPackageHeader(iPackage);
     494    if (pPackage == NULL)
     495        return RTEXITCODE_FAILURE;
     496
     497    if (!PackageIsNeeded(pPackage))
     498        return RTEXITCODE_SUCCESS;
     499
     500    /*
     501     * Deal with the file based on it's extension.
     502     */
     503    char *pszPkgFile = RTPathJoinA(pszPkgDir, pPackage->szFileName);
     504    if (!pszPkgFile)
     505        return ShowError("Out of memory on line #%u!", __LINE__);
     506    RTPathChangeToDosSlashes(pszPkgFile, true /* Force conversion. */); /* paranoia */
     507
     508    RTEXITCODE rcExit;
     509    const char *pszExt = RTPathExt(pszPkgFile);
     510    if (RTStrICmp(pszExt, ".msi") == 0)
     511        rcExit = ProcessMsiPackage(iPackage, pszPkgFile, pszMsiArgs, fLogging);
     512    else
     513        rcExit = ShowError("Internal error: Do not know how to handle file '%s'.", pPackage->szFileName);
     514
     515    RTStrFree(pszPkgFile);
     516    return rcExit;
     517}
     518
     519
     520#ifdef VBOX_WITH_CODE_SIGNING
     521/**
     522 * Install the public certificate into TrustedPublishers so the installer won't
     523 * prompt the user during silent installs.
     524 *
     525 * @returns Fully complained exit code.
     526 */
     527static RTEXITCODE InstallCertificate(void)
     528{
     529    if (addCertToStore(CERT_SYSTEM_STORE_LOCAL_MACHINE,
     530                       "TrustedPublisher",
     531                       g_ab_VBoxStubPublicCert,
     532                       sizeof(g_ab_VBoxStubPublicCert)))
     533        return RTEXITCODE_SUCCESS;
     534    return ShowError("Failed to construct install certificate.");
     535}
     536#endif /* VBOX_WITH_CODE_SIGNING */
     537
     538
     539/**
     540 * Copies the "<exepath>.custom" directory to the extraction path if it exists.
     541 *
     542 * This is used by the MSI packages from the resource section.
     543 *
     544 * @returns Fully complained exit code.
     545 * @param   pszDstDir       The destination directory.
     546 */
     547static RTEXITCODE CopyCustomDir(const char *pszDstDir)
     548{
     549    char szSrcDir[RTPATH_MAX];
     550    int rc = RTPathExecDir(szSrcDir, sizeof(szSrcDir) - 1);
     551    if (RT_SUCCESS(rc))
     552        rc = RTPathAppend(szSrcDir, sizeof(szSrcDir) - 1, ".custom");
     553    if (RT_FAILURE(rc))
     554        return ShowError("Failed to construct '.custom' dir path: %Rrc", rc);
     555
     556    if (RTDirExists(szSrcDir))
     557    {
     558        /*
     559         * Use SHFileOperation w/ FO_COPY to do the job.  This API requires an
     560         * extra zero at the end of both source and destination paths.  Thus
     561         * the -1 above and below.
     562         */
     563        size_t   cwc;
     564        RTUTF16  wszSrcDir[RTPATH_MAX + 2];
     565        PRTUTF16 pwszSrcDir = wszSrcDir;
     566        rc = RTStrToUtf16Ex(szSrcDir, RTSTR_MAX, &pwszSrcDir, RTPATH_MAX, &cwc);
     567        if (RT_FAILURE(rc))
     568            return ShowError("RTStrToUtf16Ex failed on '%s': %Rrc", szSrcDir, rc);
     569        wszSrcDir[cwc] = '\0';
     570
     571        RTUTF16  wszDstDir[RTPATH_MAX + 2];
     572        PRTUTF16 pwszDstDir = wszSrcDir;
     573        rc = RTStrToUtf16Ex(pszDstDir, RTSTR_MAX, &pwszDstDir, RTPATH_MAX, &cwc);
     574        if (RT_FAILURE(rc))
     575            return ShowError("RTStrToUtf16Ex failed on '%s': %Rrc", pszDstDir, rc);
     576        wszDstDir[cwc] = '\0';
     577
     578        SHFILEOPSTRUCTW FileOp;
     579        RT_ZERO(FileOp); /* paranoia */
     580        FileOp.hwnd     = NULL;
     581        FileOp.wFunc    = FO_COPY;
     582        FileOp.pFrom    = wszSrcDir;
     583        FileOp.pTo      = wszDstDir;
     584        FileOp.fFlags   = FOF_SILENT
     585                        | FOF_NOCONFIRMATION
     586                        | FOF_NOCONFIRMMKDIR
     587                        | FOF_NOERRORUI;
     588        FileOp.fAnyOperationsAborted = FALSE;
     589        FileOp.hNameMappings = NULL;
     590        FileOp.lpszProgressTitle = NULL;
     591
     592        rc = SHFileOperationW(&FileOp);
     593        if (rc != 0)    /* Not a Win32 status code! */
     594            return ShowError("Copying the '.custom' dir failed: %#x", rc);
     595    }
     596
     597    return RTEXITCODE_SUCCESS;
     598}
     599
     600
     601static RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly)
     602{
     603    int rc;
     604
     605    /*
     606     * Make sure the directory exists.
     607     */
     608    if (!RTDirExists(pszDstDir))
     609    {
     610        rc = RTDirCreate(pszDstDir, 0700, 0);
     611        if (RT_FAILURE(rc))
     612            return ShowError("Failed to create extraction path '%s': %Rrc", pszDstDir, rc);
     613    }
     614
     615    /*
     616     * Extract files.
     617     */
     618    for (unsigned k = 0; k < cPackages; k++)
     619    {
     620        PVBOXSTUBPKG pPackage = FindPackageHeader(k);
     621        if (!pPackage)
     622            return RTEXITCODE_FAILURE; /* Done complaining already. */
     623
     624        if (fExtractOnly || PackageIsNeeded(pPackage))
     625        {
     626            char *pszDstFile = RTPathJoinA(pszDstDir, pPackage->szFileName);
     627            if (!pszDstFile)
     628                return ShowError("Out of memory on line %u!", __LINE__);
     629
     630            rc = Extract(pPackage, pszDstFile);
     631            RTStrFree(pszDstFile);
     632            if (RT_FAILURE(rc))
     633                return ShowError("Error extracting package #%u: %Rrc", k, rc);
     634        }
     635    }
     636
     637    return RTEXITCODE_SUCCESS;
    330638}
    331639
     
    363671    bool fExtractOnly              = false;
    364672    bool fEnableLogging            = false;
    365 #ifdef VBOX_SIGNING_MODE
     673#ifdef VBOX_WITH_CODE_SIGNING
    366674    bool fEnableSilentCert         = true;
    367675#endif
     
    378686        { "-silent",            's', RTGETOPT_REQ_NOTHING },
    379687        { "/silent",            's', RTGETOPT_REQ_NOTHING },
    380 #ifdef VBOX_SIGNING_MODE
     688#ifdef VBOX_WITH_CODE_SIGNING
    381689        { "--no-silent-cert",   'c', RTGETOPT_REQ_NOTHING },
    382690        { "-no-silent-cert",    'c', RTGETOPT_REQ_NOTHING },
     
    418726                break;
    419727
    420 #ifdef VBOX_SIGNING_MODE
     728#ifdef VBOX_WITH_CODE_SIGNING
    421729            case 'c':
    422730                fEnableSilentCert = false;
     
    431739                vrc = RTStrCopy(szExtractPath, sizeof(szExtractPath), ValueUnion.psz);
    432740                if (RT_FAILURE(vrc))
    433                 {
    434                     ShowError("Extraction path is too long.");
    435                     return RTEXITCODE_FAILURE;
    436                 }
     741                    return ShowError("Extraction path is too long.");
    437742                break;
    438743
     
    443748                    vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz);
    444749                if (RT_FAILURE(vrc))
    445                 {
    446                     ShowError("MSI parameters are too long.");
    447                     return RTEXITCODE_FAILURE;
    448                 }
     750                    return ShowError("MSI parameters are too long.");
    449751                break;
    450752
     
    488790    }
    489791
    490     /** @todo The rest of this function should be done in smaller functions,
    491      *        we've lost the overview here! Too much state going around! */
    492 
    493     HRESULT hr = S_OK;
    494 
    495     do /* break loop */
    496     {
    497         /*
    498          * Determine and create our temp path (only if not already set).
    499          */
    500         if (szExtractPath[0] == '\0')
     792    /*
     793     * Determine the extration path if not given by the user, and gather some
     794     * other bits we'll be needing later.
     795     */
     796    if (szExtractPath[0] == '\0')
     797    {
     798        vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
     799        if (RT_SUCCESS(vrc))
     800            vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox");
     801        if (RT_FAILURE(vrc))
     802            return ShowError("Failed to determin extraction path (%Rrc)", vrc);
     803
     804    }
     805    RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */); /* MSI requirement. */
     806
     807    /* Read our manifest. */
     808    PVBOXSTUBPKGHEADER pHeader;
     809    vrc = FindData("MANIFEST", (PVOID *)&pHeader, NULL);
     810    if (RT_FAILURE(vrc))
     811        return ShowError("Internal package error: Manifest not found (%Rrc)", vrc);
     812    /** @todo If we could, we should validate the header. Only the magic isn't
     813     *        commonly defined, nor the version number... */
     814
     815    /*
     816     * Up to this point, we haven't done anything that requires any cleanup.
     817     * From here on, we do everything in function so we can counter clean up.
     818     */
     819    RTEXITCODE rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath, fExtractOnly);
     820    if (rcExit == RTEXITCODE_SUCCESS)
     821    {
     822        if (fExtractOnly)
    501823        {
    502             vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
    503             AssertMsgRCBreak(vrc, ("Could not retrieve temp directory!\n"));
    504 
    505             vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox");
    506             AssertMsgRCBreak(vrc, ("Could not construct temp directory!\n"));
    507 
    508             /* Convert slahes; this is necessary for MSI routines later! */
    509             RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */);
     824            if (!g_fSilent)
     825                ShowInfo("Files were extracted to: %s", szExtractPath);
    510826        }
    511         if (!RTDirExists(szExtractPath))
     827        else
    512828        {
    513             vrc = RTDirCreate(szExtractPath, 0700, 0);
    514             AssertMsgRCBreak(vrc, ("Could not create temp directory!\n"));
    515         }
    516 
    517         /* Get our executable path */
    518         char szPathExe[_MAX_PATH];
    519         vrc = RTPathExecDir(szPathExe, sizeof(szPathExe));
    520         /** @todo error checking */
    521 
    522         /* Read our manifest. */
    523         PVBOXSTUBPKGHEADER pHeader = NULL;
    524         DWORD cbHeader = 0;
    525         vrc = ReadData(NULL, "MANIFEST", (LPVOID*)&pHeader, &cbHeader);
    526         AssertMsgRCBreak(vrc, ("Manifest not found!\n"));
    527 
    528         /* Extract files. */
    529         for (BYTE k = 0; k < pHeader->byCntPkgs; k++)
    530         {
    531             PVBOXSTUBPKG pPackage = NULL;
    532             DWORD cbPackage = 0;
    533             char szHeaderName[RTPATH_MAX + 1] = {0};
    534 
    535             hr = ::StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k);
    536             vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage);
    537             AssertMsgRCBreak(vrc, ("Header not found!\n")); /** @todo include header name, how? */
    538 
    539             if (PackageIsNeeded(pPackage) || fExtractOnly)
     829            rcExit = CopyCustomDir(szExtractPath);
     830#ifdef VBOX_WITH_CODE_SIGNING
     831            if (rcExit == RTEXITCODE_SUCCESS && fEnableSilentCert && g_fSilent)
     832                InstallCertificate();
     833#endif
     834            unsigned iPackage = 0;
     835            while (iPackage < pHeader->byCntPkgs && rcExit == RTEXITCODE_SUCCESS)
    540836            {
    541                 char *pszTempFile = NULL;
    542                 vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile);
    543                 AssertMsgRCBreak(vrc, ("Could not create name for temporary extracted file!\n"));
    544                 vrc = Extract(pPackage, pszTempFile);
    545                 AssertMsgRCBreak(vrc, ("Could not extract file!\n"));
    546                 RTStrFree(pszTempFile);
     837                rcExit = ProcessPackage(iPackage, szExtractPath, szMSIArgs, fEnableLogging);
     838                iPackage++;
    547839            }
    548840        }
    549 
    550         if (FALSE == fExtractOnly && !RT_FAILURE(vrc))
    551         {
    552             /*
    553              * Copy ".custom" directory into temp directory so that the extracted .MSI
    554              * file(s) can use it.
    555              */
    556             char *pszPathCustomDir = RTPathJoinA(szPathExe, ".custom");
    557             pszPathCustomDir = RTPathChangeToDosSlashes(pszPathCustomDir, true /* Force conversion. */);
    558             if (pszPathCustomDir && RTDirExists(pszPathCustomDir))
    559             {
    560                 vrc = CopyDir(szExtractPath, pszPathCustomDir);
    561                 if (RT_FAILURE(vrc)) /* Don't fail if it's missing! */
    562                     vrc = VINF_SUCCESS;
    563 
    564                 RTStrFree(pszPathCustomDir);
    565             }
    566 
    567 #ifdef VBOX_SIGNING_MODE
    568             /*
    569              * If --silent command line option is specified, do force public
    570              * certificate install in background (i.e. completely prevent
    571              * user interaction)
    572              */
    573             if (TRUE == g_fSilent && TRUE == fEnableSilentCert)
    574             {
    575                 if (!addCertToStore(CERT_SYSTEM_STORE_LOCAL_MACHINE,
    576                                     "TrustedPublisher",
    577                                     g_ab_VBoxStubPublicCert,
    578                                     sizeof(g_ab_VBoxStubPublicCert)))
    579                 {
    580                     /* Interrupt installation */
    581                     vrc = VERR_NO_CHANGE;
    582                     break;
    583                 }
    584             }
    585 #endif
    586             /* Do actions on files. */
    587             for (BYTE k = 0; k < pHeader->byCntPkgs; k++)
    588             {
    589                 PVBOXSTUBPKG pPackage = NULL;
    590                 DWORD cbPackage = 0;
    591                 char szHeaderName[RTPATH_MAX] = {0};
    592 
    593                 hr = StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k);
    594                 vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage);
    595                 AssertMsgRCBreak(vrc, ("Package not found!\n"));
    596 
    597                 if (PackageIsNeeded(pPackage))
    598                 {
    599                     char *pszTempFile = NULL;
    600 
    601                     vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile);
    602                     AssertMsgRCBreak(vrc, ("Could not create name for temporary action file!\n"));
    603 
    604                     /* Handle MSI files. */
    605                     if (RTStrICmp(RTPathExt(pszTempFile), ".msi") == 0)
    606                     {
    607                         /* Set UI level. */
    608                         INSTALLUILEVEL UILevel = MsiSetInternalUI(  g_fSilent
    609                                                                   ? INSTALLUILEVEL_NONE
    610                                                                   : INSTALLUILEVEL_FULL,
    611                                                                     NULL);
    612                         AssertMsgBreak(UILevel != INSTALLUILEVEL_NOCHANGE, ("Could not set installer UI level!\n"));
    613 
    614                         /* Enable logging? */
    615                         if (fEnableLogging)
    616                         {
    617                             char *pszLog = RTPathJoinA(szExtractPath, "VBoxInstallLog.txt");
    618                             /* Convert slahes; this is necessary for MSI routines! */
    619                             pszLog = RTPathChangeToDosSlashes(pszLog, true /* Force conversion. */);
    620                             AssertMsgBreak(pszLog, ("Could not construct path for log file!\n"));
    621                             UINT uLogLevel = MsiEnableLog(INSTALLLOGMODE_VERBOSE,
    622                                                           pszLog, INSTALLLOGATTRIBUTES_FLUSHEACHLINE);
    623                             RTStrFree(pszLog);
    624                             AssertMsgBreak(uLogLevel == ERROR_SUCCESS, ("Could not set installer logging level!\n"));
    625                         }
    626 
    627                         /* Initialize the common controls (extended version). This is necessary to
    628                          * run the actual .MSI installers with the new fancy visual control
    629                          * styles (XP+). Also, an integrated manifest is required. */
    630                         INITCOMMONCONTROLSEX ccEx;
    631                         ccEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
    632                         ccEx.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS |
    633                                      ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES |
    634                                      ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES;
    635                         InitCommonControlsEx(&ccEx); /* Ignore failure. */
    636 
    637                         UINT uStatus = ::MsiInstallProductA(pszTempFile, szMSIArgs);
    638                         if (   (uStatus != ERROR_SUCCESS)
    639                             && (uStatus != ERROR_SUCCESS_REBOOT_REQUIRED)
    640                             && (uStatus != ERROR_INSTALL_USEREXIT))
    641                         {
    642                             switch (uStatus)
    643                             {
    644                                 case ERROR_INSTALL_PACKAGE_VERSION:
    645                                     ShowError("This installation package cannot be installed by the Windows Installer service.\n"
    646                                               "You must install a Windows service pack that contains a newer version of the Windows Installer service.");
    647                                     break;
    648 
    649                                 case ERROR_INSTALL_PLATFORM_UNSUPPORTED:
    650                                     ShowError("This installation package is not supported on this platform.");
    651                                     break;
    652 
    653                                 default:
    654                                 {
    655                                     DWORD dwFormatFlags =   FORMAT_MESSAGE_ALLOCATE_BUFFER
    656                                                           | FORMAT_MESSAGE_IGNORE_INSERTS
    657                                                           | FORMAT_MESSAGE_FROM_SYSTEM;
    658                                     HMODULE hModule = NULL;
    659                                     if (uStatus >= NERR_BASE && uStatus <= MAX_NERR)
    660                                     {
    661                                         hModule = LoadLibraryEx(TEXT("netmsg.dll"),
    662                                                                 NULL,
    663                                                                 LOAD_LIBRARY_AS_DATAFILE);
    664                                         if (hModule != NULL)
    665                                             dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
    666                                     }
    667 
    668                                     DWORD dwBufferLength;
    669                                     LPSTR szMessageBuffer;
    670                                     if (dwBufferLength = FormatMessageA(dwFormatFlags,
    671                                                                         hModule, /* If NULL, load system stuff. */
    672                                                                         uStatus,
    673                                                                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    674                                                                         (LPSTR)&szMessageBuffer,
    675                                                                         0,
    676                                                                         NULL))
    677                                     {
    678                                         ShowError("Installation failed! Error: %s", szMessageBuffer);
    679                                         LocalFree(szMessageBuffer);
    680                                     }
    681                                     else /* If text lookup failed, show at least the error number. */
    682                                         ShowError("Installation failed! Error: %u", uStatus);
    683                                     if (hModule)
    684                                         FreeLibrary(hModule);
    685                                     /** @todo program exit code needs to be set */
    686                                     break;
    687                                 }
    688                             }
    689 
    690                             vrc = VERR_NO_CHANGE; /* No change done to the system. */
    691                         }
    692                             /** @todo program exit code needs to be for ERROR_INSTALL_USEREXIT. */
    693                     }
    694                     RTStrFree(pszTempFile);
    695                 } /* Package needed? */
    696             } /* For all packages */
    697         }
     841    }
     842
     843
     844
     845    do /* break loop */
     846    {
    698847
    699848        /* Clean up (only on success - prevent deleting the log). */
     
    712861    } while (0);
    713862
    714     if (RT_SUCCESS(vrc))
    715     {
    716         if (   fExtractOnly
    717             && !g_fSilent)
    718         {
    719             ShowInfo("Files were extracted to: %s", szExtractPath);
    720         }
    721 
    722         /** @todo Add more post installation stuff here if required. */
    723     }
    724 
    725863    /* Release instance mutex. */
    726864    if (hMutexAppRunning != NULL)
     
    730868    }
    731869
    732     /*
    733      * Figure the exit code (not very difficult at the moment).
    734      */
    735     RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    736     if (RT_FAILURE(vrc))
    737         rcExit = RTEXITCODE_FAILURE;
    738870    return rcExit;
    739871}
  • trunk/src/VBox/Installer/win/Stub/resource.h

    r44529 r45320  
    1515 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    1616 */
     17
     18
    1719#define IDI_VIRTUALBOX 101
    1820
    19 #define RT_MANIFEST 24
     21#ifndef RT_MANIFEST
     22# define RT_MANIFEST 24
     23#endif
    2024#define APP_MANIFEST 1
    2125
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