dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * VBoxStub - VirtualBox's Windows installer stub.
935b743482f6f5b2a731d62322a75f9d111a3cb9vboxsync * Copyright (C) 2010-2014 Oracle Corporation
78f327ee942771169c65c91baf789fd10e72b01avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
78f327ee942771169c65c91baf789fd10e72b01avboxsync * available from http://www.virtualbox.org. This file is free software;
78f327ee942771169c65c91baf789fd10e72b01avboxsync * you can redistribute it and/or modify it under the terms of the GNU
78f327ee942771169c65c91baf789fd10e72b01avboxsync * General Public License (GPL) as published by the Free Software
78f327ee942771169c65c91baf789fd10e72b01avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
78f327ee942771169c65c91baf789fd10e72b01avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
78f327ee942771169c65c91baf789fd10e72b01avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync/*******************************************************************************
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync* Header Files *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync*******************************************************************************/
f9bf78a22f6a21de513febdca5af9ced238d1867vboxsync# define _WIN32_WINNT 0x0501 /* AttachConsole() / FreeConsole(). */
f9bf78a22f6a21de513febdca5af9ced238d1867vboxsync/* Use an own console window if run in verbose mode. */
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync/*******************************************************************************
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync* Defined Constants And Macros *
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync*******************************************************************************/
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync/*******************************************************************************
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync* Structures and Typedefs *
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync*******************************************************************************/
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * Cleanup record.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync /** List entry. */
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync /** True if file, false if directory. */
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync /** The path to the file or directory to clean up. */
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync/** Pointer to a cleanup record. */
0912cf29d2641459d225c40114c567a63273746cvboxsync/*******************************************************************************
0912cf29d2641459d225c40114c567a63273746cvboxsync* Global Variables *
0912cf29d2641459d225c40114c567a63273746cvboxsync*******************************************************************************/
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync/** Whether it's a silent or interactive GUI driven install. */
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync/** List of temporary files. */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync/** Verbosity flag. */
0912cf29d2641459d225c40114c567a63273746cvboxsync * Shows an error message box with a printf() style formatted string.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @returns RTEXITCODE_FAILURE
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszFmt Printf-style format string to show in the message box body.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsyncstatic RTEXITCODE ShowError(const char *pszFmt, ...)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync MessageBoxW(GetDesktopWindow(), pwszMsg, MY_UNICODE(VBOX_STUB_TITLE), MB_ICONERROR);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync MessageBoxA(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR);
0912cf29d2641459d225c40114c567a63273746cvboxsync else /* Should never happen! */
0912cf29d2641459d225c40114c567a63273746cvboxsync AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
0912cf29d2641459d225c40114c567a63273746cvboxsync * Shows a message box with a printf() style formatted string.
0912cf29d2641459d225c40114c567a63273746cvboxsync * @param uType Type of the message box (see MSDN).
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszFmt Printf-style format string to show in the message box body.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync MessageBoxW(GetDesktopWindow(), pwszMsg, MY_UNICODE(VBOX_STUB_TITLE), MB_ICONINFORMATION);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync MessageBoxA(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION);
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync else /* Should never happen! */
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Finds the specified in the resource section of the executable.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @returns IPRT status code.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszDataName Name of resource to read.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param ppvResource Where to return the pointer to the data.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param pdwSize Where to return the size of the data (if found).
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Optional.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsyncstatic int FindData(const char *pszDataName, PVOID *ppvResource, DWORD *pdwSize)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync HINSTANCE hInst = NULL; /* indicates the executable image */
c16bfd344d242a6352ec72b4478099ccadfc5a70vboxsync /* Find our resource. */
c16bfd344d242a6352ec72b4478099ccadfc5a70vboxsync /* Get resource size. */
c16bfd344d242a6352ec72b4478099ccadfc5a70vboxsync /* Get pointer to resource. */
c16bfd344d242a6352ec72b4478099ccadfc5a70vboxsync /* Lock resource. */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Finds the header for the given package.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @returns Pointer to the package header on success. On failure NULL is
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * returned after ShowError has been invoked.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param iPackage The package number.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsyncstatic PVBOXSTUBPKG FindPackageHeader(unsigned iPackage)
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync RTStrPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", iPackage);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync int rc = FindData(szHeaderName, (PVOID *)&pPackage, NULL);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync ShowError("Internal error: Could not find package header #%u: %Rrc", iPackage, rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync /** @todo validate it. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Constructs a full temporary file path from the given parameters.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns iprt status code.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszTempPath The pure path to use for construction.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszTargetFileName The pure file name to use for construction.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param ppszTempFile Pointer to the constructed string. Must be freed
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * using RTStrFree().
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncstatic int GetTempFileAlloc(const char *pszTempPath,
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync if (RTStrAPrintf(ppszTempFile, "%s\\%s", pszTempPath, pszTargetFileName) >= 0)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Extracts a built-in resource to disk.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns iprt status code.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszResourceName The resource name to extract.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszTempFile The full file path + name to extract the resource to.
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(pszResourceName, ("Resource pointer invalid!\n"));
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(pszTempFile, ("Temp file pointer invalid!"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Read the data of the built-in resource. */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync rc = FindData(pszResourceName, &pvData, &dwDataSize);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(rc, ("Could not read resource data!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Create new (and replace an old) file. */
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(rc, ("Could not open file for writing!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Write contents to new file. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rc = RTFileWrite(fh, pvData, dwDataSize, &cbWritten);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(rc, ("Could not open file for writing!\n"));
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(dwDataSize == cbWritten, ("File was not extracted completely! Disk full?\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync } while (0);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Extracts a built-in resource to disk.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns iprt status code.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszTempFile The full file path + name to extract the resource to.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Detects whether we're running on a 32- or 64-bit platform and returns the result.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns TRUE if we're running on a 64-bit OS, FALSE if not.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Error in retrieving process type - assume that we're running on 32bit. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Decides whether we need a specified package to handle or not.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * @returns @c true if we need to handle the specified package, @c false if not.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync return true;
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync VBOXSTUBPKGARCH enmArch = IsWow64() ? VBOXSTUBPKGARCH_AMD64 : VBOXSTUBPKGARCH_X86;
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * Adds a cleanup record.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * @returns Fully complained boolean success indicator.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * @param pszPath The path to the file or directory to clean up.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * @param fFile @c true if file, @c false if directory.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsyncstatic bool AddCleanupRec(const char *pszPath, bool fFile)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync size_t cchPath = strlen(pszPath); Assert(cchPath > 0);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync PSTUBCLEANUPREC pRec = (PSTUBCLEANUPREC)RTMemAlloc(RT_OFFSETOF(STUBCLEANUPREC, szPath[cchPath + 1]));
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync return false;
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync return true;
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * Cleans up all the extracted files and optionally removes the package
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * directory.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * @param cPackages The number of packages.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * @param pszPkgDir The package directory, NULL if it shouldn't be
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsyncstatic void CleanUp(unsigned cPackages, const char *pszPkgDir)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync for (int i = 0; i < 5; i++)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync rc = RTDirRemoveRecursive(pCur->szPath, RTDIRRMREC_F_CONTENT_AND_DIR);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync ShowError("Failed to delete temporary file '%s': %Rrc", pCur->szPath, rc);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync ShowError("Failed to delete temporary directory '%s': %Rrc", pCur->szPath, rc);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync if (RT_SUCCESS(rc) || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND || fFinalTry)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync /* Delay a little and try again. */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Processes an MSI package.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @returns Fully complained exit code.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param pszMsi The path to the MSI to process.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param pszMsiArgs Any additional installer (MSI) argument
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param fLogging Whether to enable installer logging.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsyncstatic RTEXITCODE ProcessMsiPackage(const char *pszMsi, const char *pszMsiArgs, bool fLogging)
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Set UI level.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync INSTALLUILEVEL enmDesiredUiLevel = g_fSilent ? INSTALLUILEVEL_NONE : INSTALLUILEVEL_FULL;
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync INSTALLUILEVEL enmRet = MsiSetInternalUI(enmDesiredUiLevel, NULL);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync if (enmRet == INSTALLUILEVEL_NOCHANGE /* means error */)
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("Internal error: MsiSetInternalUI failed.");
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Enable logging?
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync rc = RTStrCopy(szLogFile, sizeof(szLogFile), pszMsi);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync rc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxInstallLog.txt");
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("Internal error: Filename path too long.");
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("RTStrToUtf16 failed on '%s': %Rrc", szLogFile, rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync UINT uLogLevel = MsiEnableLogW(INSTALLLOGMODE_VERBOSE,
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Initialize the common controls (extended version). This is necessary to
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * run the actual .MSI installers with the new fancy visual control
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * styles (XP+). Also, an integrated manifest is required.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync ccEx.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS |
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES |
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES;
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Convert both strings to UTF-16 and start the installation.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("RTStrToUtf16 failed on '%s': %Rrc", pszMsi, rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("RTStrToUtf16 failed on '%s': %Rrc", pszMsi, rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync UINT uStatus = MsiInstallProductW(pwszMsi, pwszMsiArgs);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return RTEXITCODE_SUCCESS; /* we currently don't indicate this */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Installation failed. Figure out what to say.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync /* Don't say anything? */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync ShowError("This installation package cannot be installed by the Windows Installer service.\n"
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync "You must install a Windows service pack that contains a newer version of the Windows Installer service.");
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync ShowError("This installation package is not supported on this platform.");
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Try get windows to format the message.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync ShowError("Installation failed! Error: %ls", pwszMsg);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync else /* If text lookup failed, show at least the error number. */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync ShowError("Installation failed! Error: %u", uStatus);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Processes a package.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @returns Fully complained exit code.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param iPackage The package number.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param pszPkgDir The package directory (aka extraction dir).
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param pszMsiArgs Any additional installer (MSI) argument
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param fLogging Whether to enable installer logging.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsyncstatic RTEXITCODE ProcessPackage(unsigned iPackage, const char *pszPkgDir, const char *pszMsiArgs, bool fLogging)
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Get the package header and check if it's needed.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync PVBOXSTUBPKG pPackage = FindPackageHeader(iPackage);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Deal with the file based on it's extension.
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync int rc = RTPathJoin(szPkgFile, sizeof(szPkgFile), pszPkgDir, pPackage->szFileName);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync return ShowError("Internal error: RTPathJoin failed: %Rrc", rc);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync RTPathChangeToDosSlashes(szPkgFile, true /* Force conversion. */); /* paranoia */
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync rcExit = ProcessMsiPackage(szPkgFile, pszMsiArgs, fLogging);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync rcExit = RTEXITCODE_SUCCESS; /* Ignore .cab files, they're generally referenced by other files. */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync rcExit = ShowError("Internal error: Do not know how to handle file '%s'.", pPackage->szFileName);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Install the public certificate into TrustedPublishers so the installer won't
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * prompt the user during silent installs.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @returns Fully complained exit code.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync if (addCertToStore(CERT_SYSTEM_STORE_LOCAL_MACHINE,
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync "TrustedPublisher",
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("Failed to construct install certificate.");
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync#endif /* VBOX_WITH_CODE_SIGNING */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Copies the "<exepath>.custom" directory to the extraction path if it exists.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * This is used by the MSI packages from the resource section.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @returns Fully complained exit code.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * @param pszDstDir The destination directory.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsyncstatic RTEXITCODE CopyCustomDir(const char *pszDstDir)
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync int rc = RTPathExecDir(szSrcDir, sizeof(szSrcDir));
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync rc = RTPathAppend(szSrcDir, sizeof(szSrcDir), ".custom");
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("Failed to construct '.custom' dir path: %Rrc", rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Use SHFileOperation w/ FO_COPY to do the job. This API requires an
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * extra zero at the end of both source and destination paths.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync rc = RTStrToUtf16Ex(szSrcDir, RTSTR_MAX, &pwszSrcDir, RTPATH_MAX, &cwc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("RTStrToUtf16Ex failed on '%s': %Rrc", szSrcDir, rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync rc = RTStrToUtf16Ex(pszDstDir, RTSTR_MAX, &pwszDstDir, RTPATH_MAX, &cwc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("RTStrToUtf16Ex failed on '%s': %Rrc", pszDstDir, rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("Copying the '.custom' dir failed: %#x", rc);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * Add a cleanup record for recursively deleting the destination
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * .custom directory. We should actually add this prior to calling
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * SHFileOperationW since it may partially succeed...
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync char *pszDstSubDir = RTPathJoinA(pszDstDir, ".custom");
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync bool fRc = AddCleanupRec(pszDstSubDir, false /*fFile*/);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsyncstatic RTEXITCODE ExtractFiles(unsigned cPackages, const char *pszDstDir, bool fExtractOnly, bool *pfCreatedExtractDir)
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Make sure the directory exists.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("Failed to create extraction path '%s': %Rrc", pszDstDir, rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync * Extract files.
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync for (unsigned k = 0; k < cPackages; k++)
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return RTEXITCODE_FAILURE; /* Done complaining already. */
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync rc = RTPathJoin(szDstFile, sizeof(szDstFile), pszDstDir, pPackage->szFileName);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync return ShowError("Internal error: RTPathJoin failed: %Rrc", rc);
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync return ShowError("Error extracting package #%u: %Rrc", k, rc);
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync if (!fExtractOnly && !AddCleanupRec(szDstFile, true /*fFile*/))
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Check if we're already running and jump out if so. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
0912cf29d2641459d225c40114c567a63273746cvboxsync HANDLE hMutexAppRunning = CreateMutex(NULL, FALSE, "VBoxStubInstaller");
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Close the mutex for this application instance. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Init IPRT. */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync /* Close the mutex for this application instance. */
0912cf29d2641459d225c40114c567a63273746cvboxsync * Parse arguments.
0912cf29d2641459d225c40114c567a63273746cvboxsync /* Parameter variables. */
0912cf29d2641459d225c40114c567a63273746cvboxsync /* Parameter definitions. */
935b743482f6f5b2a731d62322a75f9d111a3cb9vboxsync /** @todo Replace short parameters with enums since they're not
935b743482f6f5b2a731d62322a75f9d111a3cb9vboxsync * used (and not documented to the public). */
0912cf29d2641459d225c40114c567a63273746cvboxsync /* Parse the parameters. */
0912cf29d2641459d225c40114c567a63273746cvboxsync RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
935b743482f6f5b2a731d62322a75f9d111a3cb9vboxsync "REINSTALLMODE=vomus REINSTALL=ALL");
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync rcExit = ShowError("MSI parameters are too long.");
0912cf29d2641459d225c40114c567a63273746cvboxsync vrc = RTStrCopy(szExtractPath, sizeof(szExtractPath), ValueUnion.psz);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync rcExit = ShowError("Extraction path is too long.");
0912cf29d2641459d225c40114c567a63273746cvboxsync vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync rcExit = ShowError("MSI parameters are too long.");
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "Command Line Parameters:\n\n"
0912cf29d2641459d225c40114c567a63273746cvboxsync "--extract - Extract file contents to temporary directory\n"
aa929735951456d7d4f09261e80d9e461724077bvboxsync "--help - Print this help and exit\n"
935b743482f6f5b2a731d62322a75f9d111a3cb9vboxsync "--logging - Enables installer logging\n"
935b743482f6f5b2a731d62322a75f9d111a3cb9vboxsync "--msiparams <parameters> - Specifies extra parameters for the MSI installers\n"
61d7d9128a38eb86895d38f1ad95bdf44fc0b240vboxsync "--no-silent-cert - Do not install VirtualBox Certificate automatically when --silent option is specified\n"
0912cf29d2641459d225c40114c567a63273746cvboxsync "--path - Sets the path of the extraction directory\n"
935b743482f6f5b2a731d62322a75f9d111a3cb9vboxsync "--reinstall - Forces VirtualBox to get re-installed\n"
935b743482f6f5b2a731d62322a75f9d111a3cb9vboxsync "--silent - Enables silent mode installation\n"
0912cf29d2641459d225c40114c567a63273746cvboxsync "--version - Print version number and exit\n\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "Examples:\n"
0912cf29d2641459d225c40114c567a63273746cvboxsync "%s --msiparams INSTALLDIR=C:\\VBox\n"
0912cf29d2641459d225c40114c567a63273746cvboxsync "%s --extract -path C:\\VBox",
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync VBOX_STUB_TITLE, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync /* Are (optional) MSI parameters specified and this is the last
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync * parameter? Append everything to the MSI parameter list then. */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync vrc = RTStrCat(szMSIArgs, sizeof(szMSIArgs), ValueUnion.psz);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync rcExit = ShowError("MSI parameters are too long.");
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync /* Fall through is intentional. */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync "Please refer to the command line help by specifying \"/?\"\n"
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync rcExit = ShowError("Parameter parsing error: %Rrc\n"
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync "Please refer to the command line help by specifying \"/?\"\n"
f9bf78a22f6a21de513febdca5af9ced238d1867vboxsync# ifdef VBOX_STUB_WITH_OWN_CONSOLE /* Use an own console window if run in debug mode. */
f9bf78a22f6a21de513febdca5af9ced238d1867vboxsync ShowError("Unable to allocate console, error = %ld\n",
f9bf78a22f6a21de513febdca5af9ced238d1867vboxsync /* Close the mutex for this application instance. */
f9bf78a22f6a21de513febdca5af9ced238d1867vboxsync# endif /* VBOX_STUB_WITH_OWN_CONSOLE */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync RTPrintf("Silent installation : %RTbool\n", g_fSilent);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync RTPrintf("Logging enabled : %RTbool\n", fEnableLogging);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync RTPrintf("Certificate installation : %RTbool\n", fEnableSilentCert);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync * Determine the extration path if not given by the user, and gather some
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync * other bits we'll be needing later.
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox");
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync ShowError("Failed to determine extraction path (%Rrc)", vrc);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync /** @todo should check if there is a .custom subdirectory there or not. */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync true /* Force conversion. */); /* MSI requirement. */
15fb3f6d968fd393475b33b09311294a23959b0fvboxsync /* Read our manifest. */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync vrc = FindData("MANIFEST", (PVOID *)&pHeader, NULL);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync rcExit = ShowError("Internal package error: Manifest not found (%Rrc)", vrc);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync /** @todo If we could, we should validate the header. Only the magic isn't
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync * commonly defined, nor the version number... */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync * Up to this point, we haven't done anything that requires any cleanup.
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync * From here on, we do everything in function so we can counter clean up.
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync rcExit = ExtractFiles(pHeader->byCntPkgs, szExtractPath,
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync ShowInfo("Files were extracted to: %s", szExtractPath);
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync if (rcExit == RTEXITCODE_SUCCESS && fEnableSilentCert && g_fSilent)
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync /* Don't fail if cleanup fail. At least for now. */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync /* Free any left behind cleanup records (not strictly needed). */
0b13ce7f75e6d378e896f340cb4197a0fbc07cbfvboxsync RTListForEachSafe(&g_TmpFiles, pCur, pNext, STUBCLEANUPREC, ListEntry)
f9bf78a22f6a21de513febdca5af9ced238d1867vboxsync# endif /* VBOX_STUB_WITH_OWN_CONSOLE */
98242607fbc6f6f99815fbec709e38e73e7f9583vboxsync * Release instance mutex.