VBoxStub.cpp revision 2c872d5e527386b5202fb36f281a391aecd82c5f
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * VBoxStub - VirtualBox's Windows installer stub.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Copyright (C) 2010 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*******************************************************************************/
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Shows a message box with a printf() style formatted string.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns Message box result (IDOK, IDCANCEL, ...).
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param uType Type of the message box (see MSDN).
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszFmt Printf-style format string to show in the message box body.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rc = MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONINFORMATION);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rc = MessageBox(GetDesktopWindow(), pszFmt, VBOX_STUB_TITLE, MB_ICONINFORMATION);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Shows an error message box with a printf() style formatted string.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns Message box result (IDOK, IDCANCEL, ...).
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszFmt Printf-style format string to show in the message box body.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rc = MessageBox(GetDesktopWindow(), pszMsg, VBOX_STUB_TITLE, MB_ICONERROR);
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync else /* Should never happen! */
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Reads data from a built-in resource.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns iprt status code.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param hInst Instance to read the data from.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszDataName Name of resource to read.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param ppvResource Pointer to buffer which holds the read resource data.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pdwSize Pointer which holds the read data size.
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(pszDataName, ("Resource name is empty!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Find our resource. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync HRSRC hRsrc = FindResourceEx(hInst, RT_RCDATA, pszDataName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(hRsrc, ("Could not find resource!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Get resource size. */
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync AssertMsgBreak(*pdwSize > 0, ("Size of resource is invalid!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Get pointer to resource. */
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(hData, ("Could not load resource!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Lock resource. */
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(*ppvResource, ("Could not lock resource!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync } while (0);
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. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rc = ReadData(NULL, 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.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns TRUE if we need to handle the specified package, FALSE if not.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if ((bIsWow64 && pPackage->byArch == VBOXSTUBPKGARCH_AMD64)) /* 64bit Windows. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else if ((!bIsWow64 && pPackage->byArch == VBOXSTUBPKGARCH_X86)) /* 32bit. */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Recursively copies a directory to another location.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @returns iprt status code.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszDestDir Location to copy the source directory to.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @param pszSourceDir The source directory to copy.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncint CopyDir(const char *pszDestDir, const char *pszSourceDir)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync AssertStmt(pszDestDir, "Destination directory invalid!");
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync AssertStmt(pszSourceDir, "Source directory invalid!");
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if ( RTStrPrintf(szDest, _MAX_PATH, "%s%c", pszDestDir, '\0') > 0
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync && RTStrPrintf(szSource, _MAX_PATH, "%s%c", pszSourceDir, '\0') > 0)
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! */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync HANDLE hMutexAppRunning = CreateMutex (NULL, FALSE, "VBoxStubInstaller");
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Close the mutex for this application instance. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Init IPRT. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Temp variables for arguments. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Process arguments. */
2c872d5e527386b5202fb36f281a391aecd82c5fvboxsync for (int i = 0; i < argc; i++)
2c872d5e527386b5202fb36f281a391aecd82c5fvboxsync vrc = ::StringCbCat(szExtractPath, sizeof(szExtractPath), argv[i+1]);
2c872d5e527386b5202fb36f281a391aecd82c5fvboxsync i++; /* Avoid the specified path from being parsed. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync vrc = ::StringCbCat(szMSIArgs, sizeof(szMSIArgs), " ");
2c872d5e527386b5202fb36f281a391aecd82c5fvboxsync vrc = ::StringCbCat(szMSIArgs, sizeof(szMSIArgs), argv[a]);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "Command Line Parameters:\n\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "-extract | -x - Extract file contents to temporary directory\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "-silent | -s - Enables silent mode installation\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "-path | -p - Sets the path of the extraction directory\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "-help | /? - Print this help and exit\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "-msiparams <parameters> - Specifies extra parameters for the MSI installers\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "-logging | -l - Enables installer logging\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "-version | -v - Print version number and exit\n\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "Examples:\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "%s -msiparams INSTALLDIR=C:\\VBox\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "%s -extract -path C:\\VBox\n",
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync VBOX_STUB_TITLE, VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
2c872d5e527386b5202fb36f281a391aecd82c5fvboxsync "Please refer to the command line help by specifying \"/?\"\n"
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync do /* break loop */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Get/create our temp path (only if not already set). */
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync vrc = RTPathTemp(szExtractPath, sizeof(szExtractPath));
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(vrc, ("Could not retrieve temp directory!\n"));
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync vrc = RTPathAppend(szExtractPath, sizeof(szExtractPath), "VirtualBox");
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(vrc, ("Could not construct temp directory!\n"));
329081e295d2a28a39899b3f919f3c65eef227f0vboxsync /* Convert slahes; this is necessary for MSI routines later! */
329081e295d2a28a39899b3f919f3c65eef227f0vboxsync RTPathChangeToDosSlashes(szExtractPath, true /* Force conversion. */);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(vrc, ("Could not create temp directory!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Get our executable path */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /** @todo error checking */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Read our manifest. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync vrc = ReadData(NULL, "MANIFEST", (LPVOID*)&pHeader, &cbHeader);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Extract files. */
2c872d5e527386b5202fb36f281a391aecd82c5fvboxsync hr = ::StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(vrc, ("Header not found!\n")); /** @todo include header name, how? */
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(vrc, ("Could not create name for temporary extracted file!\n"));
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(vrc, ("Could not extract file!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Copy ".custom" directory into temp directory so that the extracted .MSI
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * file(s) can use it.
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync char *pszPathCustomDir = RTPathJoinA(szPathExe, ".custom");
329081e295d2a28a39899b3f919f3c65eef227f0vboxsync pszPathCustomDir = RTPathChangeToDosSlashes(pszPathCustomDir, true /* Force conversion. */);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync if (pszPathCustomDir && RTDirExists(pszPathCustomDir))
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (RT_FAILURE(vrc)) /* Don't fail if it's missing! */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Do actions on files. */
2c872d5e527386b5202fb36f281a391aecd82c5fvboxsync hr = StringCchPrintf(szHeaderName, RTPATH_MAX, "HDR_%02d", k);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync vrc = ReadData(NULL, szHeaderName, (LPVOID*)&pPackage, &cbPackage);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync vrc = GetTempFileAlloc(szExtractPath, pPackage->szFileName, &pszTempFile);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgRCBreak(vrc, ("Could not create name for temporary action file!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Handle MSI files. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (RTStrICmp(RTPathExt(pszTempFile), ".msi") == 0)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Set UI level. */
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(UILevel != INSTALLUILEVEL_NOCHANGE, ("Could not set installer UI level!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Enable logging? */
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync char *pszLog = RTPathJoinA(szExtractPath, "VBoxInstallLog.txt");
329081e295d2a28a39899b3f919f3c65eef227f0vboxsync /* Convert slahes; this is necessary for MSI routines! */
329081e295d2a28a39899b3f919f3c65eef227f0vboxsync pszLog = RTPathChangeToDosSlashes(pszLog, true /* Force conversion. */);
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync AssertMsgBreak(pszLog, ("Could not construct path for log file!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync UINT uLogLevel = MsiEnableLog(INSTALLLOGMODE_VERBOSE,
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync AssertMsgBreak(uLogLevel == ERROR_SUCCESS, ("Could not set installer logging level!\n"));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync UINT uStatus = ::MsiInstallProductA(pszTempFile, szMSIArgs);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ShowError("This installation package cannot be installed by the Windows Installer service.\n"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "You must install a Windows service pack that contains a newer version of the Windows Installer service.");
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync ShowError("This installation package is not supported on this platform.");
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync ShowError("Installation failed! Error: %s", szMessageBuffer);
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync else /* If text lookup failed, show at least the error number. */
e139144ef4fc5f2bbe26be64faf2737cd8ccf413vboxsync ShowError("Installation failed! Error: %u", uStatus);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync vrc = VERR_NO_CHANGE; /* No change done to the system. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync } /* Package needed? */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync } /* For all packages */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Clean up (only on success - prevent deleting the log). */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync for (int i=0; i<5; i++)
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync vrc = RTDirRemoveRecursive(szExtractPath, 0 /*fFlags*/);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync } while (0);
e5967534664502b10b4b92306ad9d12a1a95a55evboxsync ShowInfo("Files were extracted to: %s", szExtractPath);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /** @todo Add more post installation stuff here if required. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Release instance mutex. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Set final exit (return) code (error level). */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else /* Always set to (VINF_SUCCESS), even if we got something else (like a VWRN etc). */