VBoxStub.cpp revision 0912cf29d2641459d225c40114c567a63273746c
/* $Id$ */
/** @file
* VBoxStub - VirtualBox's Windows installer stub.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <windows.h>
#include <commctrl.h>
#include <lmerr.h>
#include <msiquery.h>
#include <objbase.h>
#include <shlobj.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strsafe.h>
#include <iprt/initterm.h>
#include "VBoxStub.h"
#include "../StubBld/VBoxStubBld.h"
#include "resource.h"
#ifndef _UNICODE
#define _UNICODE
#endif
/*******************************************************************************
* Global Variables *
*******************************************************************************/
static bool g_fSilent = false;
/**
* Shows an error message box with a printf() style formatted string.
*
* @param pszFmt Printf-style format string to show in the message box body.
*
*/
{
char *pszMsg;
{
if (g_fSilent)
else
}
else /* Should never happen! */
}
/**
* Shows a message box with a printf() style formatted string.
*
* @param uType Type of the message box (see MSDN).
* @param pszFmt Printf-style format string to show in the message box body.
*
*/
{
char *pszMsg;
if (rc >= 0)
{
if (g_fSilent)
else
}
else /* Should never happen! */
}
/**
* Reads data from a built-in resource.
*
* @returns iprt status code.
*
* @param hInst Instance to read the data from.
* @param pszDataName Name of resource to read.
* @param ppvResource Pointer to buffer which holds the read resource data.
* @param pdwSize Pointer which holds the read data size.
*
*/
const char *pszDataName,
{
do
{
/* Find our resource. */
HRSRC hRsrc = FindResourceEx(hInst, RT_RCDATA, pszDataName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
/* Get resource size. */
/* Get pointer to resource. */
/* Lock resource. */
return VINF_SUCCESS;
} while (0);
return VERR_IO_GEN_FAILURE;
}
/**
* Constructs a full temporary file path from the given parameters.
*
* @returns iprt status code.
*
* @param pszTempPath The pure path to use for construction.
* @param pszTargetFileName The pure file name to use for construction.
* @param ppszTempFile Pointer to the constructed string. Must be freed
* using RTStrFree().
*/
static int GetTempFileAlloc(const char *pszTempPath,
const char *pszTargetFileName,
char **ppszTempFile)
{
return VINF_SUCCESS;
return VERR_NO_STR_MEMORY;
}
/**
* Extracts a built-in resource to disk.
*
* @returns iprt status code.
*
* @param pszResourceName The resource name to extract.
* @param pszTempFile The full file path + name to extract the resource to.
*
*/
static int ExtractFile(const char *pszResourceName,
const char *pszTempFile)
{
int rc;
do
{
/* Read the data of the built-in resource. */
DWORD dwDataSize = 0;
/* Create new (and replace an old) file. */
bCreatedFile = TRUE;
/* Write contents to new file. */
} while (0);
if (RTFileIsValid(fh))
if (RT_FAILURE(rc))
{
if (bCreatedFile)
}
return rc;
}
/**
* Extracts a built-in resource to disk.
*
* @returns iprt status code.
*
* @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource.
* @param pszTempFile The full file path + name to extract the resource to.
*
*/
const char *pszTempFile)
{
}
/**
* Detects whether we're running on a 32- or 64-bit platform and returns the result.
*
* @returns TRUE if we're running on a 64-bit OS, FALSE if not.
*
*/
{
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
if (NULL != fnIsWow64Process)
{
{
/* Error in retrieving process type - assume that we're running on 32bit. */
return FALSE;
}
}
return bIsWow64;
}
/**
* Decides whether we need a specified package to handle or not.
*
* @returns TRUE if we need to handle the specified package, FALSE if not.
*
* @param pPackage Pointer to a VBOXSTUBPKG struct that contains the resource.
*
*/
{
{
return TRUE;
}
{
return TRUE;
}
{
return TRUE;
}
return FALSE;
}
/**
* Recursively copies a directory to another location.
*
* @returns iprt status code.
*
* @param pszDestDir Location to copy the source directory to.
* @param pszSourceDir The source directory to copy.
*
*/
{
SHFILEOPSTRUCT s = {0};
{
s.fFlags = FOF_SILENT
}
return RTErrConvertFromWin32(SHFileOperation(&s));
}
char *lpCmdLine,
int nCmdShow)
{
/* Check if we're already running and jump out if so. */
/* Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
if ( (hMutexAppRunning != NULL)
&& (GetLastError() == ERROR_ALREADY_EXISTS))
{
/* Close the mutex for this application instance. */
return 1;
}
/* Init IPRT. */
if (RT_FAILURE(vrc))
return vrc;
/*
* Parse arguments.
*/
/* Parameter variables. */
bool fExtractOnly = false;
bool fEnableLogging = false;
char szExtractPath[RTPATH_MAX] = {0};
char szMSIArgs[4096] = {0};
/* Parameter definitions. */
static const RTGETOPTDEF s_aOptions[] =
{
};
/* Parse the parameters. */
int ch;
{
switch (ch)
{
case 'x':
fExtractOnly = true;
break;
case 's':
g_fSilent = true;
break;
case 'l':
fEnableLogging = true;
break;
case 'p':
if (RT_FAILURE(vrc))
{
ShowError("Extraction path is too long.");
return RTEXITCODE_FAILURE;
}
break;
case 'm':
if (szMSIArgs[0])
if (RT_SUCCESS(vrc))
if (RT_FAILURE(vrc))
{
ShowError("MSI parameters are too long.");
return RTEXITCODE_FAILURE;
}
break;
case 'V':
ShowInfo("Version: %d.%d.%d.%d",
return VINF_SUCCESS;
case 'h':
ShowInfo("-- %s v%d.%d.%d.%d --\n"
"Command Line Parameters:\n\n"
"--extract - Extract file contents to temporary directory\n"
"--silent - Enables silent mode installation\n"
"--path - Sets the path of the extraction directory\n"
"--msiparams <parameters> - Specifies extra parameters for the MSI installers\n"
"--logging - Enables installer logging\n"
"--help - Print this help and exit\n"
"--version - Print version number and exit\n\n"
"Examples:\n"
"%s --msiparams INSTALLDIR=C:\\VBox\n"
"%s --extract -path C:\\VBox",
return VINF_SUCCESS;
default:
if (g_fSilent)
ShowError("Unknown option \"%s\"!\n"
"Please refer to the command line help by specifying \"/?\"\n"
else
ShowError("Parameter parsing error: %Rrc\n"
"Please refer to the command line help by specifying \"/?\"\n"
"to get more information.", ch);
return RTEXITCODE_SYNTAX;
}
}
do /* break loop */
{
if (szExtractPath[0] == '\0')
{
/* Convert slahes; this is necessary for MSI routines later! */
}
if (!RTDirExists(szExtractPath))
{
}
/* Get our executable path */
/** @todo error checking */
/* Read our manifest. */
/* Extract files. */
{
{
char *pszTempFile = NULL;
}
}
{
/*
* Copy ".custom" directory into temp directory so that the extracted .MSI
* file(s) can use it.
*/
{
vrc = VINF_SUCCESS;
}
/* Do actions on files. */
{
char szHeaderName[RTPATH_MAX] = {0};
if (PackageIsNeeded(pPackage))
{
char *pszTempFile = NULL;
/* Handle MSI files. */
{
/* Set UI level. */
NULL);
/* Enable logging? */
if (fEnableLogging)
{
/* Convert slahes; this is necessary for MSI routines! */
}
/* Initialize the common controls (extended version). This is necessary to
* run the actual .MSI installers with the new fancy visual control
* styles (XP+). Also, an integrated manifest is required. */
if ( (uStatus != ERROR_SUCCESS)
&& (uStatus != ERROR_SUCCESS_REBOOT_REQUIRED)
&& (uStatus != ERROR_INSTALL_USEREXIT))
{
switch (uStatus)
{
ShowError("This installation package cannot be installed by the Windows Installer service.\n"
"You must install a Windows service pack that contains a newer version of the Windows Installer service.");
break;
ShowError("This installation package is not supported on this platform.");
break;
default:
{
{
NULL,
}
hModule, /* If NULL, load system stuff. */
0,
NULL))
{
}
else /* If text lookup failed, show at least the error number. */
if (hModule)
break;
}
}
}
}
} /* Package needed? */
} /* For all packages */
}
/* Clean up (only on success - prevent deleting the log). */
if ( !fExtractOnly
&& RT_SUCCESS(vrc))
{
for (int i=0; i<5; i++)
{
if (RT_SUCCESS(vrc))
break;
}
}
} while (0);
if (RT_SUCCESS(vrc))
{
if ( fExtractOnly
&& !g_fSilent)
{
}
/** @todo Add more post installation stuff here if required. */
}
/* Release instance mutex. */
if (hMutexAppRunning != NULL)
{
}
/* Set final exit (return) code (error level). */
if (RT_FAILURE(vrc))
{
switch(vrc)
{
case VERR_NO_CHANGE:
default:
vrc = 1;
}
}
else /* Always set to (VINF_SUCCESS), even if we got something else (like a VWRN etc). */
vrc = VINF_SUCCESS;
return vrc;
}