VirtualBox

Ignore:
Timestamp:
Aug 23, 2022 2:36:00 AM (2 years ago)
Author:
vboxsync
Message:

Add/NT/Inst: Refactored VBoxDrvInst.cpp so it can be compiled in no-CRT mode without having to implement a bunch of _txxxx and _wxxxx CRT functions. Haven't quite tested all of the code yet, need GA build. bugref:10261

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp

    r96407 r96422  
    3434#endif
    3535
    36 #include <iprt/cdefs.h>
     36#include <iprt/alloca.h>
    3737#include <VBox/version.h>
    3838
    3939#include <iprt/win/windows.h>
    4040#include <iprt/win/setupapi.h>
    41 #include <stdio.h>
    42 #include <tchar.h>
     41
     42#include <iprt/asm.h>
     43#include <iprt/mem.h>
     44#include <iprt/path.h>      /* RTPATH_IS_SEP */
     45#include <iprt/string.h>
     46#include <iprt/utf16.h>
    4347
    4448
     
    4650*   Defines                                                                                                                      *
    4751*********************************************************************************************************************************/
    48 
    4952/* Exit codes */
    5053#define EXIT_OK      (0)
     
    5356#define EXIT_USAGE   (3)
    5457
    55 /* Prototypes */
    56 typedef struct {
    57   PWSTR pApplicationId;
    58   PWSTR pDisplayName;
    59   PWSTR pProductName;
    60   PWSTR pMfgName;
    61 } INSTALLERINFO, *PINSTALLERINFO;
    62 typedef const PINSTALLERINFO PCINSTALLERINFO;
    63 
    64 typedef enum {
    65   DIFXAPI_SUCCESS,
    66   DIFXAPI_INFO,
    67   DIFXAPI_WARNING,
    68   DIFXAPI_ERROR
    69 } DIFXAPI_LOG;
    70 
    71 typedef void (WINAPI * DIFXLOGCALLBACK_W)( DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);
    72 typedef void ( __cdecl* DIFXAPILOGCALLBACK_W)( DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);
    73 
    74 typedef DWORD (WINAPI *fnDriverPackageInstall) (PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);
    75 fnDriverPackageInstall g_pfnDriverPackageInstall = NULL;
    76 
    77 typedef DWORD (WINAPI *fnDriverPackageUninstall) (PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);
    78 fnDriverPackageUninstall g_pfnDriverPackageUninstall = NULL;
    79 
    80 typedef VOID (WINAPI *fnDIFXAPISetLogCallback) (DIFXAPILOGCALLBACK_W LogCallback, PVOID CallbackContext);
    81 fnDIFXAPISetLogCallback g_pfnDIFXAPISetLogCallback = NULL;
    82 
    8358/* Defines */
    84 #define DRIVER_PACKAGE_REPAIR                 0x00000001
    85 #define DRIVER_PACKAGE_SILENT                 0x00000002
    86 #define DRIVER_PACKAGE_FORCE                  0x00000004
    87 #define DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT 0x00000008
    88 #define DRIVER_PACKAGE_LEGACY_MODE            0x00000010
    89 #define DRIVER_PACKAGE_DELETE_FILES           0x00000020
     59#define DRIVER_PACKAGE_REPAIR                   0x00000001
     60#define DRIVER_PACKAGE_SILENT                   0x00000002
     61#define DRIVER_PACKAGE_FORCE                    0x00000004
     62#define DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT   0x00000008
     63#define DRIVER_PACKAGE_LEGACY_MODE              0x00000010
     64#define DRIVER_PACKAGE_DELETE_FILES             0x00000020
    9065
    9166/* DIFx error codes */
    9267/** @todo any reason why we're not using difxapi.h instead of these redefinitions? */
    9368#ifndef ERROR_DRIVER_STORE_ADD_FAILED
    94 # define ERROR_DRIVER_STORE_ADD_FAILED \
    95     (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x0247L)
     69# define ERROR_DRIVER_STORE_ADD_FAILED          (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x0247L)
    9670#endif
    97 #define ERROR_DEPENDENT_APPLICATIONS_EXIST \
    98     (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x300)
    99 #define ERROR_DRIVER_PACKAGE_NOT_IN_STORE \
    100     (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x302)
     71#define ERROR_DEPENDENT_APPLICATIONS_EXIST      (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR|0x300)
     72#define ERROR_DRIVER_PACKAGE_NOT_IN_STORE       (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x302)
    10173
    10274/* Registry string list flags */
    103 #define VBOX_REG_STRINGLIST_NONE              0x00000000        /* No flags set. */
    104 #define VBOX_REG_STRINGLIST_ALLOW_DUPLICATES  0x00000001        /* Allows duplicates in list when adding a value. */
     75#define VBOX_REG_STRINGLIST_NONE                0x00000000        /**< No flags set. */
     76#define VBOX_REG_STRINGLIST_ALLOW_DUPLICATES    0x00000001        /**< Allows duplicates in list when adding a value. */
    10577
    10678#ifdef DEBUG
     
    10880#endif
    10981
    110 /** @todo Get rid of all that TCHAR crap! Use WCHAR wherever possible. */
    111 
    112 bool GetErrorMsg(DWORD dwLastError, _TCHAR *pszMsg, DWORD dwBufSize)
    113 {
    114     if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, pszMsg, dwBufSize / sizeof(TCHAR), NULL) == 0)
    115     {
    116         _sntprintf(pszMsg, dwBufSize / sizeof(TCHAR), _T("Unknown error!\n"));
     82
     83/*********************************************************************************************************************************
     84*   Structures and Typedefs                                                                                                      *
     85*********************************************************************************************************************************/
     86typedef struct
     87{
     88    PWSTR pApplicationId;
     89    PWSTR pDisplayName;
     90    PWSTR pProductName;
     91    PWSTR pMfgName;
     92} INSTALLERINFO, *PINSTALLERINFO;
     93typedef const PINSTALLERINFO PCINSTALLERINFO;
     94
     95typedef enum
     96{
     97    DIFXAPI_SUCCESS,
     98    DIFXAPI_INFO,
     99    DIFXAPI_WARNING,
     100    DIFXAPI_ERROR
     101} DIFXAPI_LOG;
     102
     103typedef void (__cdecl * DIFXAPILOGCALLBACK_W)(DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);
     104
     105typedef DWORD (WINAPI *fnDriverPackageInstall)(PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);
     106fnDriverPackageInstall g_pfnDriverPackageInstall = NULL;
     107
     108typedef DWORD (WINAPI *fnDriverPackageUninstall)(PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);
     109fnDriverPackageUninstall g_pfnDriverPackageUninstall = NULL;
     110
     111typedef VOID (WINAPI *fnDIFXAPISetLogCallback)(DIFXAPILOGCALLBACK_W LogCallback, PVOID CallbackContext);
     112fnDIFXAPISetLogCallback g_pfnDIFXAPISetLogCallback = NULL;
     113
     114
     115/** @name Output helpers
     116 *
     117 * The general ASSUMPTION here is that all strings are restricted to 7-bit
     118 * ASCII, with the exception of wchar_t ones.
     119 *
     120 * @note We don't use printf, RTPrintf or similar not for masochistic reasons
     121 *       but to keep the binary small and make it easier to switch between CRT
     122 *       and IPRT w/ no-CRT.
     123 *
     124 * @{
     125 */
     126
     127static void OutputWStr(HANDLE hDst, const wchar_t *pwszStr)
     128{
     129    DWORD cbIgn;
     130    if (GetConsoleMode(hDst, &cbIgn))
     131        WriteConsoleW(hDst, pwszStr, (DWORD)RTUtf16Len(pwszStr), &cbIgn, NULL);
     132    else
     133    {
     134        char *pszTmp;
     135        int rc = RTUtf16ToUtf8(pwszStr, &pszTmp);
     136        if (RT_SUCCESS(rc))
     137        {
     138            char *pszInCodepage;
     139            rc = RTStrUtf8ToCurrentCP(&pszInCodepage, pszTmp);
     140            if (RT_SUCCESS(rc))
     141            {
     142                WriteFile(hDst, pszInCodepage, (DWORD)strlen(pszInCodepage), &cbIgn, NULL);
     143                RTStrFree(pszInCodepage);
     144            }
     145            else
     146                WriteFile(hDst, RT_STR_TUPLE("<RTStrUtf8ToCurrentCP error>"), &cbIgn, NULL);
     147            RTStrFree(pszTmp);
     148        }
     149        else
     150            WriteFile(hDst, RT_STR_TUPLE("<RTUtf16ToUtf8 error>"), &cbIgn, NULL);
     151    }
     152}
     153
     154
     155static void ErrorMsgBegin(const char *pszMsg)
     156{
     157    HANDLE const hStdErr = GetStdHandle(STD_ERROR_HANDLE);
     158    DWORD        cbIgn;
     159    WriteFile(hStdErr, RT_STR_TUPLE("error: "), &cbIgn, NULL);
     160    WriteFile(hStdErr, pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL);
     161}
     162
     163
     164static void ErrorMsgStr(const char *pszMsg)
     165{
     166    HANDLE const hStdErr = GetStdHandle(STD_ERROR_HANDLE);
     167    DWORD cbIgn;
     168    WriteFile(hStdErr, pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL);
     169}
     170
     171
     172static void ErrorMsgWStr(const wchar_t *pwszStr)
     173{
     174    OutputWStr(GetStdHandle(STD_ERROR_HANDLE), pwszStr);
     175}
     176
     177
     178static int ErrorMsgEnd(const char *pszMsg)
     179{
     180    HANDLE const hStdErr = GetStdHandle(STD_ERROR_HANDLE);
     181    DWORD        cbIgn;
     182    if (pszMsg)
     183        WriteFile(hStdErr, pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL);
     184    WriteFile(hStdErr, RT_STR_TUPLE("\r\n"), &cbIgn, NULL);
     185    return EXIT_FAIL;
     186}
     187
     188
     189static void ErrorMsgU64(uint64_t uValue, bool fSigned = false)
     190{
     191    char szVal[128];
     192    RTStrFormatU64(szVal, sizeof(szVal), uValue, 10, 0, 0, fSigned ? RTSTR_F_VALSIGNED : 0);
     193    ErrorMsgStr(szVal);
     194}
     195
     196
     197static int ErrorMsg(const char *pszMsg)
     198{
     199    ErrorMsgBegin(pszMsg);
     200    return ErrorMsgEnd(NULL);
     201}
     202
     203
     204static int ErrorMsgSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3)
     205{
     206    ErrorMsgBegin(pszMsg1);
     207    ErrorMsgWStr(pwszMsg2);
     208    return ErrorMsgEnd(pszMsg3);
     209}
     210
     211
     212static int ErrorMsgSWSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3,
     213                         const wchar_t *pwszMsg4, const char *pszMsg5)
     214{
     215    ErrorMsgBegin(pszMsg1);
     216    ErrorMsgWStr(pwszMsg2);
     217    ErrorMsgStr(pszMsg3);
     218    ErrorMsgWStr(pwszMsg4);
     219    return ErrorMsgEnd(pszMsg5);
     220}
     221
     222
     223static void ErrorMsgErrVal(uint32_t uErrVal, bool fSigned)
     224{
     225    char    szVal[128];
     226    ssize_t cchVal = RTStrFormatU32(szVal, sizeof(szVal) - 1, uErrVal, 10, 0, 0, fSigned ? RTSTR_F_VALSIGNED : 0);
     227    szVal[cchVal++] = '/';
     228    szVal[cchVal]   = '\0';
     229    ErrorMsgStr(szVal);
     230
     231    RTStrFormatU32(szVal, sizeof(szVal) - 1, uErrVal, 16, 0, 0, RTSTR_F_SPECIAL);
     232    ErrorMsgStr(szVal);
     233}
     234
     235
     236static int ErrorMsgErr(const char *pszMsg, uint32_t uErrVal, const char *pszErrIntro, bool fSigned)
     237{
     238    ErrorMsgBegin(pszMsg);
     239    ErrorMsgStr(pszErrIntro);
     240    ErrorMsgErrVal(uErrVal, fSigned);
     241    return ErrorMsgEnd(")");
     242}
     243
     244
     245static int ErrorMsgVBoxErr(const char *pszMsg, int rc)
     246{
     247    return ErrorMsgErr(pszMsg, rc, " (", true);
     248}
     249
     250
     251static int ErrorMsgLastErr(const char *pszMsg)
     252{
     253    return ErrorMsgErr(pszMsg, GetLastError(), " (last error ", false);
     254}
     255
     256
     257static int ErrorMsgLastErrSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3)
     258{
     259    DWORD dwErr = GetLastError();
     260    ErrorMsgBegin(pszMsg1);
     261    ErrorMsgWStr(pwszMsg2);
     262    ErrorMsgStr(pszMsg3);
     263    ErrorMsgStr(" (last error ");
     264    ErrorMsgErrVal(dwErr, false);
     265    return ErrorMsgEnd(")");
     266}
     267
     268static int ErrorMsgLastErrSWSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3,
     269                                const wchar_t *pwszMsg4, const char *pszMsg5)
     270{
     271    DWORD dwErr = GetLastError();
     272    ErrorMsgBegin(pszMsg1);
     273    ErrorMsgWStr(pwszMsg2);
     274    ErrorMsgStr(pszMsg3);
     275    ErrorMsgWStr(pwszMsg4);
     276    ErrorMsgStr(pszMsg5);
     277    ErrorMsgStr(" (last error ");
     278    ErrorMsgErrVal(dwErr, false);
     279    return ErrorMsgEnd(")");
     280}
     281
     282
     283static int ErrorMsgLastErrSWSRSUS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const char *pszMsg4,
     284                                  uint64_t uValue, const char *pszMsg5)
     285{
     286    DWORD dwErr = GetLastError();
     287    ErrorMsgBegin(pszMsg1);
     288    ErrorMsgWStr(pwszMsg2);
     289    ErrorMsgStr(pszMsg3);
     290    ErrorMsgStr(" (last error ");
     291    ErrorMsgErrVal(dwErr, false);
     292    ErrorMsgStr(")");
     293    ErrorMsgStr(pszMsg4);
     294    ErrorMsgU64(uValue);
     295    return ErrorMsgEnd(pszMsg5);
     296}
     297
     298
     299static int ErrorMsgLastErrSSS(const char *pszMsg1, const char *pszMsg2, const char *pszMsg3)
     300{
     301    DWORD dwErr = GetLastError();
     302    ErrorMsgBegin(pszMsg1);
     303    ErrorMsgStr(pszMsg2);
     304    ErrorMsgStr(pszMsg3);
     305    ErrorMsgStr(" (last error ");
     306    ErrorMsgErrVal(dwErr, false);
     307    return ErrorMsgEnd(")");
     308}
     309
     310
     311static int ErrorMsgLStatus(const char *pszMsg, LSTATUS lrc)
     312{
     313    return ErrorMsgErr(pszMsg, (DWORD)lrc, " (", true);
     314}
     315
     316
     317static int ErrorMsgLStatusSWSRS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3,
     318                                LSTATUS lrc, const char *pszMsg4)
     319{
     320    ErrorMsgBegin(pszMsg1);
     321    ErrorMsgWStr(pwszMsg2);
     322    ErrorMsgStr(pszMsg3);
     323    ErrorMsgErrVal((DWORD)lrc, true);
     324    return ErrorMsgEnd(pszMsg4);
     325}
     326
     327
     328static int ErrorMsgLStatusSWSWSRS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const wchar_t *pwszMsg4,
     329                                  const char *pszMsg5, LSTATUS lrc, const char *pszMsg6)
     330{
     331    ErrorMsgBegin(pszMsg1);
     332    ErrorMsgWStr(pwszMsg2);
     333    ErrorMsgStr(pszMsg3);
     334    ErrorMsgWStr(pwszMsg4);
     335    ErrorMsgStr(pszMsg5);
     336    ErrorMsgErrVal((DWORD)lrc, true);
     337    return ErrorMsgEnd(pszMsg6);
     338}
     339
     340
     341static int ErrorMsgLStatusSWSWSWSRS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const wchar_t *pwszMsg4,
     342                                    const char *pszMsg5, const wchar_t *pwszMsg6, const char *pszMsg7,
     343                                    LSTATUS lrc, const char *pszMsg8)
     344{
     345    ErrorMsgBegin(pszMsg1);
     346    ErrorMsgWStr(pwszMsg2);
     347    ErrorMsgStr(pszMsg3);
     348    ErrorMsgWStr(pwszMsg4);
     349    ErrorMsgStr(pszMsg5);
     350    ErrorMsgWStr(pwszMsg6);
     351    ErrorMsgStr(pszMsg7);
     352    ErrorMsgErrVal((DWORD)lrc, true);
     353    return ErrorMsgEnd(pszMsg8);
     354}
     355
     356
     357static int ErrorBadArg(const char *pszName, wchar_t const *pwszArg, const char *pszValues = NULL)
     358{
     359    ErrorMsgBegin("Bad argument '");
     360    ErrorMsgStr(pszName);
     361    ErrorMsgStr("': ");
     362    ErrorMsgWStr(pwszArg);
     363    if (pszValues)
     364        ErrorMsgStr(", expected: ");
     365    return ErrorMsgEnd(pszValues);
     366}
     367
     368
     369/** Simple fputs(stdout) replacement. */
     370static void PrintStr(const char *pszMsg)
     371{
     372    HANDLE const hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
     373    DWORD        cbIgn;
     374    WriteFile(hStdOut, pszMsg, (DWORD)strlen(pszMsg), &cbIgn, NULL);
     375}
     376
     377
     378/** Simple fputs(stdout) replacement. */
     379static void PrintWStr(const wchar_t *pwszStr)
     380{
     381    OutputWStr(GetStdHandle(STD_OUTPUT_HANDLE), pwszStr);
     382}
     383
     384
     385static void PrintX64(uint64_t uValue)
     386{
     387    char szVal[128];
     388    RTStrFormatU64(szVal, sizeof(szVal), uValue, 16, 0, 0, RTSTR_F_64BIT | RTSTR_F_SPECIAL);
     389    PrintStr(szVal);
     390}
     391
     392
     393static void PrintSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3)
     394{
     395    PrintStr(pszMsg1);
     396    PrintWStr(pwszMsg2);
     397    PrintStr(pszMsg3);
     398}
     399
     400
     401static void PrintSWSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3,
     402                       const wchar_t *pwszMsg4, const char *pszMsg5)
     403{
     404    PrintStr(pszMsg1);
     405    PrintWStr(pwszMsg2);
     406    PrintStr(pszMsg3);
     407    PrintWStr(pwszMsg4);
     408    PrintStr(pszMsg5);
     409}
     410
     411
     412static void PrintSWSWSWS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const wchar_t *pwszMsg4,
     413                         const char *pszMsg5, const wchar_t *pwszMsg6, const char *pszMsg7)
     414{
     415    PrintStr(pszMsg1);
     416    PrintWStr(pwszMsg2);
     417    PrintStr(pszMsg3);
     418    PrintWStr(pwszMsg4);
     419    PrintStr(pszMsg5);
     420    PrintWStr(pwszMsg6);
     421    PrintStr(pszMsg7);
     422}
     423
     424
     425static void PrintSXS(const char *pszMsg1, uint64_t uValue, const char *pszMsg2)
     426{
     427    PrintStr(pszMsg1);
     428    PrintX64(uValue);
     429    PrintStr(pszMsg2);
     430}
     431
     432
     433static void PrintSWSWSWSXS(const char *pszMsg1, const wchar_t *pwszMsg2, const char *pszMsg3, const wchar_t *pwszMsg4,
     434                           const char *pszMsg5, const wchar_t *pwszMsg6, const char *pszMsg7, uint64_t uValue, const char *pszMsg8)
     435{
     436    PrintStr(pszMsg1);
     437    PrintWStr(pwszMsg2);
     438    PrintStr(pszMsg3);
     439    PrintWStr(pwszMsg4);
     440    PrintStr(pszMsg5);
     441    PrintWStr(pwszMsg6);
     442    PrintStr(pszMsg7);
     443    PrintX64(uValue);
     444    PrintStr(pszMsg8);
     445}
     446
     447/** @} */
     448
     449static char *ArgToUtf8(wchar_t const *pwszString, const char *pszArgName)
     450{
     451    char *pszUtf8 = NULL;
     452    int rc = RTUtf16ToUtf8(pwszString, &pszUtf8);
     453    if (RT_SUCCESS(rc))
     454        return pszUtf8;
     455    ErrorMsgBegin("RTUtf16ToUtf8 failed on '");
     456    ErrorMsgStr(pszArgName);
     457    ErrorMsgStr("': ");
     458    ErrorMsgErrVal(rc, true);
     459    ErrorMsgEnd(NULL);
     460    return NULL;
     461}
     462
     463/**
     464 * @returns false.
     465 * @note Frees pszValue
     466 */
     467static bool ErrorArtToNum(int rc, const char *pszArgName, char *pszValue)
     468{
     469    ErrorMsgBegin("Failed to convert the '");
     470    ErrorMsgStr(pszArgName);
     471    ErrorMsgStr("' value '");
     472    ErrorMsgStr(pszValue);
     473    ErrorMsgStr("' to a number: ");
     474    ErrorMsgErrVal(rc, true);
     475    ErrorMsgEnd(NULL);
     476    return false;
     477}
     478
     479
     480static bool ArgToUInt32Full(wchar_t const *pwszString, const char *pszArgName, uint32_t *puValue)
     481{
     482    char *pszValue = ArgToUtf8(pwszString, pszArgName);
     483    if (!pszValue)
    117484        return false;
    118     }
    119     _TCHAR *p = _tcschr(pszMsg, _T('\r'));
    120     if (p != NULL)
    121         *p = _T('\0');
     485    int rc = RTStrToUInt32Full(pszValue, 0, puValue);
     486    if (RT_FAILURE(rc))
     487        return ErrorArtToNum(rc, pszArgName, pszValue);
     488    RTStrFree(pszValue);
    122489    return true;
    123490}
     491
     492
     493static bool ArgToUInt64Full(wchar_t const *pwszString, const char *pszArgName, uint64_t *puValue)
     494{
     495    char *pszValue = ArgToUtf8(pwszString, pszArgName);
     496    if (!pszValue)
     497        return false;
     498    int rc = RTStrToUInt64Full(pszValue, 0, puValue);
     499    if (rc != VINF_SUCCESS)
     500        return ErrorArtToNum(rc, pszArgName, pszValue);
     501    RTStrFree(pszValue);
     502    return true;
     503}
     504
     505
     506
     507static bool GetErrorMsg(DWORD dwLastError, wchar_t *pwszMsg, DWORD cwcMsg)
     508{
     509    if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, pwszMsg, cwcMsg, NULL) == 0)
     510        return false;
     511    wchar_t *pwc = RTUtf16Chr(pwszMsg, '\r');
     512    if (pwc)
     513        *pwc = '\0';
     514    return true;
     515}
     516
    124517
    125518/**
    126519 * Log callback for DIFxAPI calls.
    127520 *
    128  * @param   Event                   The event's structure to log.
    129  * @param   dwError                 The event's error level.
    130  * @param   pEventDescription       The event's text description.
    131  * @param   pCallbackContext        User-supplied callback context.
     521 * @param   enmEvent        Event logging level.
     522 * @param   dwError         Event error number.
     523 * @param   pwszEventDesc   Event description text.
     524 * @param   pvCtx           Log file handle, if we've got one.
    132525 */
    133 void LogCallback(DIFXAPI_LOG Event, DWORD dwError, PCWSTR pEventDescription, PVOID pCallbackContext)
    134 {
     526static void __cdecl VBoxDIFxLogCallback(DIFXAPI_LOG enmEvent, DWORD dwError, PCWSTR pwszEventDesc, PVOID pvCtx)
     527{
     528    const char *pszEvent;
     529    switch (enmEvent)
     530    {
     531        case DIFXAPI_SUCCESS:   pszEvent  =  "DIFXAPI_SUCCESS"; break;
     532        case DIFXAPI_INFO:      pszEvent  =  "DIFXAPI_INFO";    break;
     533        case DIFXAPI_WARNING:   pszEvent  =  "DIFXAPI_WARNING"; break;
     534        case DIFXAPI_ERROR:     pszEvent  =  "DIFXAPI_ERROR";   break;
     535        default:                pszEvent  =  "DIFXAPI_<unknown>"; break;
     536    }
     537
     538    /*
     539     * Log to standard output:
     540     */
     541    PrintStr(pszEvent);
    135542    if (dwError == 0)
    136         _tprintf(_T("(%u) %ws\n"), Event, pEventDescription);
     543        PrintStr(": ");
    137544    else
    138         _tprintf(_T("(%u) ERROR: %lu - %ws\n"), Event, dwError, pEventDescription);
    139 
    140      if (pCallbackContext)
    141          fwprintf((FILE*)pCallbackContext, _T("(%u) %lu - %s\n"), Event, dwError, pEventDescription);
    142 }
     545    {
     546        PrintStr(": ERROR: ");
     547        PrintX64(dwError);
     548        PrintStr(" - ");
     549    }
     550    PrintWStr(pwszEventDesc);
     551    PrintStr("\r\n");
     552
     553    /*
     554     * Write to the log file if we have one (wide char format).
     555     */
     556    HANDLE const hLogFile = (HANDLE)pvCtx;
     557    if (hLogFile != INVALID_HANDLE_VALUE)
     558    {
     559        /* "event: err - desc\r\n" */
     560        wchar_t wszBuf[168];
     561        RTUtf16CopyAscii(wszBuf, RT_ELEMENTS(wszBuf), pszEvent);
     562        RTUtf16CatAscii(wszBuf, RT_ELEMENTS(wszBuf), ": ");
     563        char szVal[128];
     564        RTStrFormatU32(szVal, sizeof(szVal), dwError, 10, 0, 0, 0);
     565        RTUtf16CatAscii(wszBuf, RT_ELEMENTS(wszBuf), szVal);
     566        RTUtf16CatAscii(wszBuf, RT_ELEMENTS(wszBuf), " - ");
     567
     568        DWORD dwIgn;
     569        WriteFile(hLogFile, wszBuf,        (DWORD)(RTUtf16Len(wszBuf)        * sizeof(wchar_t)), &dwIgn, NULL);
     570        WriteFile(hLogFile, pwszEventDesc, (DWORD)(RTUtf16Len(pwszEventDesc) * sizeof(wchar_t)), &dwIgn, NULL);
     571        WriteFile(hLogFile, L"\r\n", 2 * sizeof(wchar_t), &dwIgn, NULL);
     572    }
     573}
     574
    143575
    144576/**
    145  * Loads a system DLL.
     577 * Loads a DLL from the same directory as the installer.
    146578 *
    147  * @returns Module handle or NULL
     579 * @returns Module handle, NULL on failure (fully messaged).
    148580 * @param   pwszName            The DLL name.
    149581 */
    150 static HMODULE loadInstalledDll(const wchar_t *pwszName)
     582static HMODULE LoadAppDll(const wchar_t *pwszName)
    151583{
    152584    /* Get the process image path. */
     
    154586    UINT   cwcPath = GetModuleFileNameW(NULL, wszPath, MAX_PATH);
    155587    if (!cwcPath || cwcPath >= MAX_PATH)
     588    {
     589        ErrorMsgLastErr("LoadAppDll: GetModuleFileNameW failed");
    156590        return NULL;
     591    }
    157592
    158593    /* Drop the image filename. */
    159     UINT   off = cwcPath - 1;
    160     for (;;)
    161     {
    162         if (   wszPath[off] == '\\'
    163             || wszPath[off] == '/'
    164             || wszPath[off] == ':')
     594    do
     595    {
     596        cwcPath--;
     597        if (RTPATH_IS_SEP(wszPath[cwcPath]))
    165598        {
    166             wszPath[off] = '\0';
    167             cwcPath = off;
     599            cwcPath++;
     600            wszPath[cwcPath] = '\0';
    168601            break;
    169602        }
    170         if (!off--)
    171             return NULL; /* No path? Shouldn't ever happen! */
    172     }
    173 
    174     /* Check if there is room in the buffer to construct the desired name. */
    175     size_t cwcName = 0;
    176     while (pwszName[cwcName])
    177         cwcName++;
    178     if (cwcPath + 1 + cwcName + 1 > MAX_PATH)
     603    } while (cwcPath > 0);
     604
     605    if (!cwcPath) /* This should be impossible */
     606    {
     607        ErrorMsg("LoadAppDll: GetModuleFileNameW returned no path!");
    179608        return NULL;
    180 
    181     wszPath[cwcPath] = '\\';
    182     memcpy(&wszPath[cwcPath + 1], pwszName, (cwcName + 1) * sizeof(wszPath[0]));
    183     return LoadLibraryW(wszPath);
    184 }
     609    }
     610
     611    /* Append the dll name if we can. */
     612    size_t const cwcName = RTUtf16Len(pwszName);
     613    if (cwcPath + cwcName >= RT_ELEMENTS(wszPath))
     614    {
     615        ErrorMsgSWSWS("LoadAppDll: Path '", wszPath, "' too long when adding '", pwszName, "'");
     616        return NULL;
     617    }
     618    memcpy(&wszPath[cwcPath], pwszName, (cwcName + 1) * sizeof(wszPath[0]));
     619
     620    /* Try load the module.  We will try restrict the library search to the
     621       system32 directory if supported by the OS. Older OSes doesn't support
     622       this, so we fall back on full search in that case. */
     623    HMODULE hMod = LoadLibraryExW(wszPath, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
     624    if (hMod == NULL && GetLastError() == ERROR_INVALID_PARAMETER)
     625        hMod = LoadLibraryExW(wszPath, NULL, 0);
     626    if (!hMod)
     627        ErrorMsgLastErrSWS("LoadAppDll: LoadLibraryExW failed on '", wszPath, "'");
     628    return hMod;
     629}
     630
    185631
    186632/**
    187  * (Un)Installs a driver from/to the system.
     633 * Installs or uninstalls a driver.
    188634 *
    189635 * @return  Exit code (EXIT_OK, EXIT_FAIL)
    190  * @param   fInstall            Flag indicating whether to install (TRUE) or uninstall (FALSE) a driver.
    191  * @param   pszDriverPath       Pointer to full qualified path to the driver's .INF file (+ driver files).
    192  * @param   fSilent             Flag indicating a silent installation (TRUE) or not (FALSE).
    193  * @param   pszLogFile          Pointer to full qualified path to log file to be written during installation.
    194  *                              Optional.
     636 * @param   fInstall            Set to @c true for installation, and @c false
     637 *                              for uninstallation.
     638 * @param   pwszDriverPath      Path to the driver's .INF file.
     639 * @param   fSilent             Set to @c true for silent installation.
     640 * @param   pwszLogFile         Pointer to full qualified path to log file to be
     641 *                              written during installation. Optional.
    195642 */
    196 int VBoxInstallDriver(const BOOL fInstall, const _TCHAR *pszDriverPath, BOOL fSilent,
    197                       const _TCHAR *pszLogFile)
    198 {
    199     HRESULT hr = S_OK;
    200     HMODULE hDIFxAPI = loadInstalledDll(L"DIFxAPI.dll");
    201     if (NULL == hDIFxAPI)
    202     {
    203         _tprintf(_T("ERROR: Unable to locate DIFxAPI.dll!\n"));
    204         hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
    205     }
     643static int VBoxInstallDriver(const BOOL fInstall, const wchar_t *pwszDriverPath, bool fSilent, const wchar_t *pwszLogFile)
     644{
     645    /*
     646     * Windows 2000 and later.
     647     */
     648    OSVERSIONINFO VerInfo = { sizeof(VerInfo) };
     649    GetVersionEx(&VerInfo);
     650    if (VerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
     651        return ErrorMsg("Platform not supported for driver (un)installation!");
     652    if (VerInfo.dwMajorVersion < 5)
     653        return ErrorMsg("Platform too old to be supported for driver (un)installation!");
     654
     655    /*
     656     * Get the full path to the INF file.
     657     */
     658    wchar_t wszFullDriverInf[MAX_PATH];
     659    if (GetFullPathNameW(pwszDriverPath, MAX_PATH, wszFullDriverInf, NULL) ==0 )
     660        return ErrorMsgLastErrSWS("GetFullPathNameW failed on '", pwszDriverPath, "'");
     661
     662    /*
     663     * Load DIFxAPI.dll from our application directory and resolve the symbols we need
     664     * from it.  We always resolve all for reasons of simplicity and general paranoia.
     665     */
     666    HMODULE hModDifXApi = LoadAppDll(L"DIFxAPI.dll");
     667    if (!hModDifXApi)
     668        return EXIT_FAIL;
     669
     670    static struct { FARPROC *ppfn; const char *pszName; } const s_aFunctions[] =
     671    {
     672        { (FARPROC *)&g_pfnDriverPackageInstall,   "DriverPackageInstallW" },
     673        { (FARPROC *)&g_pfnDriverPackageUninstall, "DriverPackageUninstallW" },
     674        { (FARPROC *)&g_pfnDIFXAPISetLogCallback,  "DIFXAPISetLogCallbackW" },
     675    };
     676    for (size_t i = 0; i < RT_ELEMENTS(s_aFunctions); i++)
     677    {
     678        FARPROC pfn = *s_aFunctions[i].ppfn = GetProcAddress(hModDifXApi, s_aFunctions[i].pszName);
     679        if (!pfn)
     680            return ErrorMsgLastErrSSS("Failed to find symbol '", s_aFunctions[i].pszName, "' in DIFxAPI.dll");
     681    }
     682
     683    /*
     684     * Try open the log file and register a logger callback with DIFx.
     685     * Failures here are non-fatal.
     686     */
     687    HANDLE hLogFile = INVALID_HANDLE_VALUE;
     688    if (pwszLogFile)
     689    {
     690        hLogFile = CreateFileW(pwszLogFile, FILE_GENERIC_WRITE & ~FILE_WRITE_DATA /* append mode */, FILE_SHARE_READ,
     691                               NULL /*pSecAttr*/, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
     692        if (hLogFile == INVALID_HANDLE_VALUE)
     693            ErrorMsgLastErrSWS("Failed to open/create log file '", pwszLogFile, "'");
     694        g_pfnDIFXAPISetLogCallback(VBoxDIFxLogCallback, (void *)hLogFile);
     695    }
     696
     697    PrintStr(fInstall ? "Installing driver ...\r\n" : "Uninstalling driver ...\r\n");
     698    PrintSWS("INF-File: '", wszFullDriverInf, "'\r\n");
     699
     700    INSTALLERINFO InstInfo =
     701    {
     702        L"{7d2c708d-c202-40ab-b3e8-de21da1dc629}", /* Our GUID for representing this installation tool. */
     703        L"VirtualBox Guest Additions Install Helper",
     704        L"VirtualBox Guest Additions", /** @todo Add version! */
     705        L"Oracle Corporation"
     706    };
     707
     708    /* Flags */
     709    DWORD dwFlags = DRIVER_PACKAGE_FORCE;
     710    if (!fInstall)
     711        dwFlags |= DRIVER_PACKAGE_DELETE_FILES;
     712    if (VerInfo.dwMajorVersion < 6 && fInstall)
     713    {
     714        PrintStr("Using legacy mode for install ...\r\n");
     715        dwFlags |= DRIVER_PACKAGE_LEGACY_MODE;
     716    }
     717    if (fSilent)
     718    {
     719        /* Don't add DRIVER_PACKAGE_SILENT to dwFlags here, otherwise the
     720           installation will fail because we don't have WHQL certified drivers.
     721           See CERT_E_WRONG_USAGE on MSDN for more information. */
     722        PrintStr("Installation is silent ...\r\n");
     723    }
     724
     725    /* Do the install/uninstall: */
     726    BOOL  fReboot = FALSE;
     727    DWORD dwErr;
     728    if (fInstall)
     729        dwErr = g_pfnDriverPackageInstall(wszFullDriverInf, dwFlags, &InstInfo, &fReboot);
    206730    else
    207     {
    208         if (fInstall)
     731        dwErr = g_pfnDriverPackageUninstall(wszFullDriverInf, dwFlags, &InstInfo, &fReboot);
     732
     733    /*
     734     * Report error
     735     */
     736    int         rcExit = EXIT_FAIL;
     737    const char *psz    = NULL;
     738    switch (dwErr)
     739    {
     740        case ERROR_SUCCESS:
     741            rcExit = EXIT_OK;
     742            break;
     743
     744        case CRYPT_E_FILE_ERROR:
     745            psz = "The catalog file for the specified driver package was not found!";
     746            break;
     747        case ERROR_ACCESS_DENIED:
     748            psz = fInstall ? "Caller is not in Administrators group to install this driver package!"
     749                           : "Caller is not in Administrators group to uninstall this driver package!";
     750            break;
     751        case ERROR_BAD_ENVIRONMENT:
     752            psz = "The current Microsoft Windows version does not support this operation!";
     753            break;
     754        case ERROR_CANT_ACCESS_FILE:
     755            psz = "The driver package files could not be accessed!";
     756            break;
     757        case ERROR_DEPENDENT_APPLICATIONS_EXIST:
     758            psz = "DriverPackageUninstall removed an association between the driver package and the specified application but the function did not uninstall the driver package because other applications are associated with the driver package!";
     759            break;
     760        case ERROR_DRIVER_PACKAGE_NOT_IN_STORE:
     761            psz = fInstall ? "There is no INF file in the DIFx driver store that corresponds to the INF file being installed!"
     762                           : "There is no INF file in the DIFx driver store that corresponds to the INF file being uninstalled!";
     763            break;
     764        case ERROR_FILE_NOT_FOUND:
     765            psz = "INF-file not found!";
     766            break;
     767        case ERROR_IN_WOW64:
     768            psz = "The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!";
     769            break;
     770        case ERROR_INVALID_FLAGS:
     771            psz = "The flags specified are invalid!";
     772            break;
     773        case ERROR_INSTALL_FAILURE:
     774            psz = fInstall ? "The install operation failed! Consult the Setup API logs for more information."
     775                           : "The uninstall operation failed! Consult the Setup API logs for more information.";
     776            break;
     777        case ERROR_NO_MORE_ITEMS:
     778            psz = "The function found a match for the HardwareId value, but the specified driver was not a better match than the current driver and the caller did not specify the INSTALLFLAG_FORCE flag!";
     779            break;
     780        case ERROR_NO_DRIVER_SELECTED:
     781            psz = "No driver in .INF-file selected!";
     782            break;
     783        case ERROR_SECTION_NOT_FOUND:
     784            psz = "Section in .INF-file was not found!";
     785            break;
     786        case ERROR_SHARING_VIOLATION:
     787            psz = "A component of the driver package in the DIFx driver store is locked by a thread or process!";
     788            break;
     789
     790        /*
     791         * !    sig:           Verifying file against specific Authenticode(tm) catalog failed! (0x800b0109)
     792         * !    sig:           Error 0x800b0109: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
     793         * !!!  sto:           No error message will be displayed as client is running in non-interactive mode.
     794         * !!!  ndv:           Driver package failed signature validation. Error = 0xE0000247
     795         */
     796        case ERROR_DRIVER_STORE_ADD_FAILED:
     797            psz = "Adding driver to the driver store failed!!";
     798            break;
     799        case ERROR_UNSUPPORTED_TYPE:
     800            psz = "The driver package type is not supported of INF-file!";
     801            break;
     802        case ERROR_NO_SUCH_DEVINST:
     803            psz = "The driver package was installed but no matching devices found in the device tree (ERROR_NO_SUCH_DEVINST).";
     804            /* GA installer should ignore this error code and continue */
     805            rcExit = EXIT_OK;
     806            break;
     807
     808        default:
    209809        {
    210             g_pfnDriverPackageInstall = (fnDriverPackageInstall)GetProcAddress(hDIFxAPI, "DriverPackageInstallW");
    211             if (g_pfnDriverPackageInstall == NULL)
     810            /* Try error lookup with GetErrorMsg(). */
     811            ErrorMsgSWS(fInstall ? "Installation of '" : "Uninstallation of '", wszFullDriverInf, "' failed!");
     812            ErrorMsgBegin("dwErr=");
     813            ErrorMsgErrVal(dwErr, false);
     814            WCHAR wszErrMsg[1024];
     815            if (GetErrorMsg(dwErr, wszErrMsg, RT_ELEMENTS(wszErrMsg)))
    212816            {
    213                 _tprintf(_T("ERROR: Unable to retrieve entry point for DriverPackageInstallW!\n"));
    214                 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
     817                ErrorMsgStr(": ");
     818                ErrorMsgWStr(wszErrMsg);
    215819            }
     820            ErrorMsgEnd(NULL);
     821            break;
     822        }
     823    }
     824    if (psz)
     825    {
     826        ErrorMsgSWS(fInstall ? "Installation of '" : "Uninstallation of '", wszFullDriverInf, "' failed!");
     827        ErrorMsgBegin("dwErr=");
     828        ErrorMsgErrVal(dwErr, false);
     829        ErrorMsgStr(": ");
     830        ErrorMsgEnd(psz);
     831    }
     832
     833    /* Close the log file. */
     834    if (pwszLogFile)
     835    {
     836        g_pfnDIFXAPISetLogCallback(NULL, NULL);
     837        if (hLogFile != INVALID_HANDLE_VALUE)
     838            CloseHandle(hLogFile);
     839    }
     840    if (rcExit == EXIT_OK)
     841    {
     842        PrintStr(fInstall ? "Driver was installed successfully!\r\n"
     843                          : "Driver was uninstalled successfully!\r\n");
     844        if (fReboot)
     845        {
     846            PrintStr(fInstall ? "A reboot is needed to complete the driver installation!\r\n"
     847                              : "A reboot is needed to complete the driver uninstallation!\r\n");
     848            /** @todo r=bird: We don't set EXIT_REBOOT here for some reason... The
     849             *        ExecuteInf didn't use EXIT_REBOOT either untill the no-CRT rewrite,
     850             *        so perhaps the EXIT_REBOOT stuff can be removed? */
     851        }
     852    }
     853
     854    return rcExit;
     855}
     856
     857
     858/** Handles 'driver install'. */
     859static int handleDriverInstall(unsigned cArgs, wchar_t **papwszArgs)
     860{
     861    return VBoxInstallDriver(true /*fInstall*/, papwszArgs[1], false /*fSilent*/,
     862                             cArgs > 1 && papwszArgs[1][0] ? papwszArgs[1] : NULL /* pwszLogFile*/);
     863}
     864
     865
     866/** Handles 'driver uninstall'. */
     867static int handleDriverUninstall(unsigned cArgs, wchar_t **papwszArgs)
     868{
     869    return VBoxInstallDriver(false /*fInstall*/, papwszArgs[1], false /*fSilent*/,
     870                             cArgs > 1 && papwszArgs[1][0] ? papwszArgs[1] : NULL /* pwszLogFile*/);
     871}
     872
     873
     874/**
     875 * Implementes PSP_FILE_CALLBACK_W, used by ExecuteInfFile.
     876 */
     877static UINT CALLBACK
     878vboxDrvInstExecuteInfFileCallback(PVOID pvContext, UINT uNotification, UINT_PTR uParam1, UINT_PTR uParam2) RT_NOTHROW_DEF
     879{
     880#ifdef DEBUG
     881    PrintSXS("Got installation notification ", uNotification, "\r\n");
     882#endif
     883
     884    switch (uNotification)
     885    {
     886        case SPFILENOTIFY_NEEDMEDIA:
     887            PrintStr("Requesting installation media ...\r\n");
     888            break;
     889
     890        case SPFILENOTIFY_STARTCOPY:
     891            PrintStr("Copying driver files to destination ...\r\n");
     892            break;
     893
     894        case SPFILENOTIFY_TARGETNEWER:
     895        case SPFILENOTIFY_TARGETEXISTS:
     896            return TRUE;
     897    }
     898
     899    return SetupDefaultQueueCallbackW(pvContext, uNotification, uParam1, uParam2);
     900}
     901
     902
     903/**
     904 * Executes a specific .INF section to install/uninstall drivers and/or
     905 * services.
     906 *
     907 * @return  Exit code (EXIT_OK, EXIT_FAIL, EXIT_REBOOT)
     908 * @param   pwszSection Section to execute; usually it's L"DefaultInstall".
     909 * @param   pwszInf     Path of the .INF file to use.
     910 */
     911static int ExecuteInfFile(const wchar_t *pwszSection, const wchar_t *pwszInf)
     912{
     913    PrintSWSWS("Installing from INF-File: '", pwszInf, "', Section: '", pwszSection, "' ...\r\n");
     914
     915    UINT uErrorLine = 0;
     916    HINF hInf = SetupOpenInfFileW(pwszInf, NULL, INF_STYLE_WIN4, &uErrorLine);
     917    if (hInf == INVALID_HANDLE_VALUE)
     918        return ErrorMsgLastErrSWSRSUS("SetupOpenInfFileW failed to open '", pwszInf, "' ", ", error line ", uErrorLine, NULL);
     919
     920    int   rcExit  = EXIT_FAIL;
     921    PVOID pvQueue = SetupInitDefaultQueueCallback(NULL);
     922    if (pvQueue)
     923    {
     924        if (SetupInstallFromInfSectionW(NULL /*hWndOwner*/, hInf, pwszSection, SPINST_ALL, HKEY_LOCAL_MACHINE,
     925                                        NULL /*pwszSrcRootPath*/, SP_COPY_NEWER_OR_SAME | SP_COPY_NOSKIP,
     926                                        vboxDrvInstExecuteInfFileCallback, pvQueue, NULL /*hDevInfoSet*/, NULL /*pDevInfoData*/))
     927        {
     928            PrintStr("File installation stage successful\r\n");
     929
     930            if (SetupInstallServicesFromInfSectionW(hInf, L"DefaultInstall.Services", 0 /* Flags */))
     931            {
     932                PrintStr("Service installation stage successful. Installation completed.\r\n");
     933                rcExit = EXIT_OK;
     934            }
     935            else if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
     936            {
     937                PrintStr("A reboot is required to complete the installation\r\n");
     938                rcExit = EXIT_REBOOT;
     939            }
     940            else
     941                ErrorMsgLastErrSWSWS("SetupInstallServicesFromInfSectionW failed on '", pwszSection, "' in '", pwszInf, "'");
     942        }
     943        SetupTermDefaultQueueCallback(pvQueue);
     944    }
     945    else
     946        ErrorMsgLastErr("SetupInitDefaultQueueCallback failed");
     947    SetupCloseInfFile(hInf);
     948    return rcExit;
     949}
     950
     951
     952/** Handles 'driver executeinf'. */
     953static int handleDriverExecuteInf(unsigned cArgs, wchar_t **papwszArgs)
     954{
     955    RT_NOREF(cArgs);
     956    return ExecuteInfFile(L"DefaultInstall", papwszArgs[0]);
     957}
     958
     959
     960/**
     961 * Checks if a string is a substring of another one.
     962 *
     963 * Used by the RegistryAddStringToMultiSZ & RegistryRemoveStringToMultiSZ
     964 * routines.
     965 */
     966static bool IsSubStringOf(wchar_t volatile const *pwszStr, size_t cwcStr, wchar_t const *pwszSubStr, size_t cwcSubStr)
     967{
     968    if (cwcStr >= cwcSubStr && cwcSubStr > 0)
     969    {
     970        wchar_t const wcFirst = *pwszSubStr;
     971        cwcStr -= cwcSubStr;
     972        do
     973        {
     974            /* Could've used wmemchr here, but it isn't implemented in noCRT yet. */
     975            if (   *pwszStr == wcFirst
     976                && memcmp((void const *)pwszStr, pwszSubStr, cwcSubStr * sizeof(wchar_t)) == 0)
     977                return true;
     978            pwszStr++;
     979        } while (cwcStr-- > 0);
     980    }
     981    return false;
     982}
     983
     984
     985/**
     986 * Adds a string entry to a MULTI_SZ registry list.
     987 *
     988 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     989 * @param   pwszSubKey      Sub key containing the list.
     990 * @param   pwszValueName   The actual key name of the list.
     991 * @param   pwszItemToAdd   The item to add to the list.
     992 * @param   uPosition       Position (zero-based) of where to add the
     993 *                          value to the list.
     994 */
     995static int RegistryAddStringToMultiSZ(const wchar_t *pwszSubKey, const wchar_t *pwszValueName,
     996                                      const wchar_t *pwszItemToAdd, uint32_t uPosition)
     997{
     998    size_t const cwcItemToAdd = RTUtf16Len(pwszItemToAdd);
     999    size_t const cbItemToAdd  = (cwcItemToAdd + 1) * sizeof(wchar_t);
     1000#ifdef DEBUG
     1001    PrintSWSWSWSXS("AddStringToMultiSZ: Adding MULTI_SZ item '", pwszItemToAdd,
     1002                   "' to HKLM/'", pwszSubKey, "'/'", pwszValueName, "' at position ", uPosition, "\r\n");
     1003#endif
     1004
     1005    /*
     1006     * Open/create the key.
     1007     */
     1008    HKEY    hKey   = NULL;
     1009    DWORD   dwDisp = 0;
     1010    LSTATUS lrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pwszSubKey, 0 /*Reserved*/, NULL /*pClass*/, REG_OPTION_NON_VOLATILE,
     1011                                 KEY_READ | KEY_WRITE, NULL /*pSecAttr*/, &hKey, &dwDisp);
     1012    if (lrc != ERROR_SUCCESS)
     1013        return ErrorMsgLStatusSWSRS("RegistryAddStringToList: RegCreateKeyEx HKLM/'", pwszSubKey, "' failed: ", lrc, NULL);
     1014
     1015    /*
     1016     * Query the current value, first query just gets the buffer size the 2nd does the actual query.
     1017     * We make sure the buffer is large enough to contain the new item we're supposed to add.
     1018     */
     1019    int   rcExit  = EXIT_FAIL;
     1020    PBYTE pbBuf   = NULL;
     1021    DWORD cbValue = 0;
     1022    DWORD dwType  = 0;
     1023    lrc = RegQueryValueEx(hKey, pwszValueName, NULL, &dwType, NULL, &cbValue);
     1024    if (lrc == ERROR_SUCCESS || lrc == ERROR_MORE_DATA)
     1025    {
     1026        cbValue = cbValue + _1K - sizeof(wchar_t)*2; /* 1KB of paranoia fudge, even if we ASSUME no races. */
     1027        pbBuf = (PBYTE)RTMemAllocZ(cbValue + sizeof(wchar_t)*2 /* Two extra wchar_t's for proper zero termination. */
     1028                                   + cbItemToAdd);
     1029        if (!pbBuf)
     1030            lrc = ERROR_OUTOFMEMORY;
     1031        lrc = RegQueryValueEx(hKey, pwszValueName, NULL, &dwType, pbBuf, &cbValue);
     1032    }
     1033    if (lrc == ERROR_FILE_NOT_FOUND)
     1034    {
     1035        PrintStr("RegistryAddStringToList: Value not found, creating a new one...\r\n");
     1036        pbBuf = (PBYTE)RTMemAllocZ(cbItemToAdd + sizeof(wchar_t)*8);
     1037        if (pbBuf)
     1038        {
     1039            cbValue = sizeof(wchar_t);
     1040            dwType  = REG_MULTI_SZ;
     1041            lrc     = ERROR_SUCCESS;
     1042        }
     1043        else
     1044            lrc     = ERROR_OUTOFMEMORY;
     1045    }
     1046    if (   lrc == ERROR_SUCCESS
     1047        && dwType == REG_MULTI_SZ)
     1048    {
     1049#ifdef DEBUG
     1050        PrintSXS("RegistryAddStringToList: Current value length: ", cbValue, "\r\n");
     1051#endif
     1052
     1053        /*
     1054         * Scan the strings in the buffer, inserting the new item and removing any
     1055         * existing duplicates.  We do this in place.
     1056         *
     1057         * We have made sure above that the buffer is both properly zero terminated
     1058         * and large enough to contain the new item, so we need do no buffer size
     1059         * checking here.
     1060         */
     1061        wchar_t volatile *pwszSrc   = (wchar_t volatile *)pbBuf;
     1062        wchar_t volatile *pwszDst   = (wchar_t volatile *)pbBuf;
     1063        size_t            cbLeft    = cbValue;
     1064        for (uint32_t uCurPos = 0; ; uCurPos++)
     1065        {
     1066            size_t const cwcSrc  = RTUtf16Len((wchar_t const *)pwszSrc);
     1067            size_t const cbSrc   = (cwcSrc + 1) * sizeof(wchar_t);
     1068            bool const   fTheEnd = !cwcSrc && cbSrc >= cbLeft;
     1069
     1070            /* Insert the item if we're in the right position now, or if we're
     1071               at the last string and still haven't reached it. */
     1072            if (uCurPos == uPosition || (fTheEnd && uCurPos < uPosition))
     1073            {
     1074                pwszSrc = (wchar_t volatile *)memmove((PBYTE)pwszSrc + cbItemToAdd, (wchar_t const *)pwszSrc, cbLeft);
     1075                memcpy((void *)pwszDst, pwszItemToAdd, cbItemToAdd);
     1076                pwszDst += cwcItemToAdd + 1;
     1077                uCurPos++;
     1078            }
     1079            if (fTheEnd)
     1080                break;
     1081
     1082            /* We do not add empty strings nor strings matching the one we're adding. */
     1083            if (!cwcSrc || IsSubStringOf(pwszSrc, cwcSrc, pwszItemToAdd, cwcItemToAdd))
     1084                uCurPos--;
     1085            else
     1086            {
     1087                if (pwszDst != pwszSrc)
     1088                    memmove((void *)pwszDst, (void const *)pwszSrc, cbSrc);
     1089                pwszDst += cwcSrc + 1;
     1090            }
     1091            pwszSrc += cwcSrc + 1;
     1092            cbLeft  -= cbSrc;
     1093        }
     1094        *pwszDst = '\0';
     1095        DWORD const cbNewValue = (DWORD)((PBYTE)(pwszDst + 1) - pbBuf);
     1096#ifdef DEBUG
     1097        PrintSXS("RegistryAddStringToList: New value length: ", cbNewValue, "\r\n");
     1098#endif
     1099
     1100        /*
     1101         * Always write the value since we cannot tell whether it changed or
     1102         * not without adding a bunch extra code above.
     1103         */
     1104        lrc = RegSetValueExW(hKey, pwszValueName, 0, REG_MULTI_SZ, pbBuf, cbNewValue);
     1105        if (lrc == ERROR_SUCCESS)
     1106        {
     1107#ifdef DEBUG
     1108            PrintSWSWS("RegistryAddStringToList: The item '", pwszItemToAdd, "' was added successfully to '",
     1109                       pwszValueName, "'.\r\n");
     1110#endif
     1111            rcExit = EXIT_OK;
     1112        }
     1113        else
     1114            ErrorMsgLStatusSWSWSRS("RegistryAddStringToList: RegSetValueExW HKLM/'",
     1115                                   pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL);
     1116    }
     1117    else if (lrc != ERROR_SUCCESS)
     1118        ErrorMsgLStatusSWSWSRS("RemoveStringFromMultiSZ: RegQueryValueEx HKLM/'",
     1119                               pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL);
     1120    else
     1121        ErrorMsgLStatusSWSWSRS("RemoveStringFromMultiSZ: Unexpected value type for HKLM/'",
     1122                               pwszSubKey, "'/'", pwszValueName, "': ", (LSTATUS)dwType, ", expected REG_SZ (1)");
     1123    return rcExit;
     1124}
     1125
     1126
     1127/** Handles 'registry addmultisz'. */
     1128static int handleRegistryAddMultiSz(unsigned cArgs, wchar_t **papwszArgs)
     1129{
     1130    RT_NOREF(cArgs);
     1131
     1132    uint32_t uPosition;
     1133    if (!ArgToUInt32Full(papwszArgs[3], "position", &uPosition))
     1134        return EXIT_USAGE;
     1135
     1136    return RegistryAddStringToMultiSZ(papwszArgs[0], papwszArgs[1], papwszArgs[2], uPosition);
     1137}
     1138
     1139
     1140/**
     1141 * Removes a item from a MULTI_SZ registry list.
     1142 *
     1143 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     1144 * @param   pwszSubKey          Sub key containing the list.
     1145 * @param   pwszValueName       The actual key name of the list.
     1146 * @param   pwszItemToRemove    The item to remove from the list.  Actually, we
     1147 *                              only do a substring match on this, so any item
     1148 *                              containing this string will be removed.
     1149 */
     1150static int RegistryRemoveStringFromMultiSZ(const wchar_t *pwszSubKey, const wchar_t *pwszValueName,
     1151                                           const wchar_t *pwszItemToRemove)
     1152{
     1153#ifdef DEBUG
     1154    PrintSWSWSWS("RemoveStringFromMultiSZ: Removing MULTI_SZ string '", pwszItemToRemove,
     1155                 "' from HKLM/'", pwszSubKey, "'/'", pwszValueName, "'\r\n");
     1156#endif
     1157
     1158    /*
     1159     * Open the specified key.
     1160     */
     1161    HKEY hKey = NULL;
     1162    LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwszSubKey, 0 /*dwOptions*/, KEY_READ | KEY_WRITE, &hKey);
     1163    if (lrc != ERROR_SUCCESS)
     1164        return ErrorMsgLStatusSWSRS("RemoveStringFromMultiSZ: RegOpenKeyExW HKLM/'", pwszSubKey, "' failed: ", lrc, NULL);
     1165
     1166    /*
     1167     * Query the current value, first query just gets the buffer size the 2nd does the actual query.
     1168     */
     1169    int   rcExit  = EXIT_FAIL;
     1170    PBYTE pbBuf   = NULL;
     1171    DWORD cbValue = 0;
     1172    DWORD dwType  = 0;
     1173    lrc = RegQueryValueEx(hKey, pwszValueName, NULL, &dwType, NULL, &cbValue);
     1174    if (lrc == ERROR_SUCCESS || lrc  == ERROR_MORE_DATA)
     1175    {
     1176        cbValue = cbValue + _1K - sizeof(wchar_t)*2; /* 1KB of paranoia fudge, even if we ASSUME no races. */
     1177        pbBuf = (PBYTE)RTMemAllocZ(cbValue + sizeof(wchar_t)*2); /* Two extra wchar_t's for proper zero termination, see docs. */
     1178        if (!pbBuf)
     1179            lrc = ERROR_OUTOFMEMORY;
     1180        lrc = RegQueryValueEx(hKey, pwszValueName, NULL, &dwType, pbBuf, &cbValue);
     1181    }
     1182    if (   lrc == ERROR_SUCCESS
     1183        && dwType == REG_MULTI_SZ)
     1184    {
     1185#ifdef DEBUG
     1186        PrintSXS("RemoveStringFromMultiSZ: Current value length: ", cbValue, "\r\n");
     1187#endif
     1188        /*
     1189         * Scan the buffer and remove all strings containing the pwszItemToRemove
     1190         * as a substring.
     1191         */
     1192        size_t const      cwcValueToRemove = RTUtf16Len(pwszItemToRemove);
     1193        wchar_t volatile *pwszSrc          = (wchar_t volatile *)pbBuf;
     1194        wchar_t volatile *pwszDst          = (wchar_t volatile *)pbBuf;
     1195        size_t            cbLeft           = cbValue;
     1196        for (;;)
     1197        {
     1198            /* Find the length for the current string.  We can safely use RTUtf16Len
     1199               here because of a zero terminated buffer with two extra terminator chars. */
     1200            size_t const cwcSrc = RTUtf16Len((wchar_t const *)pwszSrc);
     1201            size_t const cbSrc  = (cwcSrc + 1) * sizeof(wchar_t);
     1202            if (!IsSubStringOf(pwszSrc, cwcSrc, pwszItemToRemove, cwcValueToRemove))
     1203            {
     1204                if (pwszDst != pwszSrc)
     1205                    memmove((void *)pwszDst, (void const *)pwszSrc, cbSrc);
     1206                pwszDst += cwcSrc + 1;
     1207            }
     1208
     1209            /* Advance. */
     1210            if (cbLeft < cbSrc)
     1211                break;
     1212            cbLeft  -= cbSrc;
     1213            pwszSrc += cwcSrc + 1;
     1214        }
     1215        *pwszDst = '\0';
     1216        DWORD const cbNewValue = (DWORD)((PBYTE)(pwszDst + 1) - pbBuf);
     1217#ifdef DEBUG
     1218        PrintSXS("RemoveStringFromMultiSZ: New value length: ", cbNewValue, "\r\n");
     1219#endif
     1220
     1221        /*
     1222         * Update the value if we made any change.
     1223         */
     1224        if (cbNewValue == cbValue)
     1225        {
     1226#ifdef DEBUG
     1227            PrintSWSWS("RemoveStringFromMultiSZ: The item '", pwszItemToRemove, "' was not part of '",
     1228                       pwszValueName, "', so nothing needed doing.\r\n");
     1229#endif
     1230            rcExit = EXIT_OK;
    2161231        }
    2171232        else
    2181233        {
    219             g_pfnDriverPackageUninstall = (fnDriverPackageUninstall)GetProcAddress(hDIFxAPI, "DriverPackageUninstallW");
    220             if (g_pfnDriverPackageUninstall == NULL)
     1234            lrc = RegSetValueExW(hKey, pwszValueName, 0, REG_MULTI_SZ, pbBuf, cbNewValue);
     1235            if (lrc == ERROR_SUCCESS)
    2211236            {
    222                 _tprintf(_T("ERROR: Unable to retrieve entry point for DriverPackageUninstallW!\n"));
    223                 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
     1237#ifdef DEBUG
     1238                PrintSWSWS("RemoveStringFromMultiSZ: The item '", pwszItemToRemove, "' was removed successfully from '",
     1239                           pwszValueName, "'.\r\n");
     1240#endif
     1241                rcExit = EXIT_OK;
    2241242            }
     1243            else
     1244                ErrorMsgLStatusSWSWSRS("RegistryAddStringToList: RegSetValueExW HKLM/'",
     1245                                       pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL);
    2251246        }
    226 
    227         if (SUCCEEDED(hr))
     1247    }
     1248    else if (lrc == ERROR_FILE_NOT_FOUND)
     1249    {
     1250#ifdef DEBUG
     1251        PrintStr("RemoveStringFromMultiSZ: value not present in registry\r\n");
     1252#endif
     1253        rcExit = EXIT_OK;
     1254    }
     1255    else if (lrc != ERROR_SUCCESS)
     1256        ErrorMsgLStatusSWSWSRS("RemoveStringFromMultiSZ: RegQueryValueEx HKLM/'",
     1257                               pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL);
     1258    else
     1259        ErrorMsgLStatusSWSWSRS("RemoveStringFromMultiSZ: Unexpected value type for HKLM/'",
     1260                               pwszSubKey, "'/'", pwszValueName, "': ", (LSTATUS)dwType, ", expected REG_SZ (1)");
     1261    RegCloseKey(hKey);
     1262    RTMemFree(pbBuf);
     1263    return rcExit;
     1264}
     1265
     1266
     1267/** Handles 'registry delmultisz'. */
     1268static int handleRegistryDelMultiSz(unsigned cArgs, wchar_t **papwszArgs)
     1269{
     1270    RT_NOREF(cArgs);
     1271    return RegistryRemoveStringFromMultiSZ(papwszArgs[0], papwszArgs[1], papwszArgs[2]);
     1272}
     1273
     1274
     1275/**
     1276 * Compare the current list item with the one to add/remove.
     1277 *
     1278 * Used by RegistryAddStringToList and RegistryRemoveStringFromList.
     1279 */
     1280static bool IsStringListItemMatch(wchar_t volatile *pwszItem1, size_t cwcItem1,
     1281                                  wchar_t const *pwszItem2, size_t cwcItem2)
     1282{
     1283    if (cwcItem1 == cwcItem2)
     1284    {
     1285#if 0 /* 94720 bytes */
     1286        if (RTUtf16NICmp((wchar_t const *)pwszItem1, pwszItem2, cwcItem1) == 0)
     1287            return true;
     1288#else /* vs 62464 bytes */
     1289        /* Temporarily zero termination of item 1 as it's easier, and therefore
     1290           safer, to use lstrcmpiW than CompareStringW or CompareStringExW.  The
     1291           latter is Vista and later, the former has a big fat warning on it.  */
     1292        wchar_t const wcEnd = pwszItem1[cwcItem1];
     1293        int const iDiff = lstrcmpiW((wchar_t const *)pwszItem1, pwszItem2);
     1294        pwszItem1[cwcItem1] = wcEnd;
     1295        return iDiff == 0;
     1296#endif
     1297    }
     1298    return false;
     1299}
     1300
     1301
     1302/**
     1303 * Adds an item to a comma separated registry string list (REG_SZ).
     1304 *
     1305 * Only operates in HKLM for now, if needed it can be extended later for use
     1306 * with other hives.
     1307 *
     1308 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     1309 * @param   pwszSubKey          Sub key containing the list value.
     1310 * @param   pwszValueName       The name of the value holding the list.
     1311 * @param   pwszItemToAdd       The value to add to the list.
     1312 * @param   uPosition           Position (zero-based) of where to insert the
     1313 *                              value into the list.
     1314 * @param   fFlags              VBOX_REG_STRINGLIST_ALLOW_DUPLICATES or 0.
     1315 */
     1316static int RegistryAddStringToList(const wchar_t *pwszSubKey, const wchar_t *pwszValueName, const wchar_t *pwszItemToAdd,
     1317                                   uint32_t uPosition, uint32_t fFlags)
     1318{
     1319    /* Overflow precaution - see comment below. */
     1320    size_t const cwcItemToAdd = RTUtf16Len(pwszItemToAdd);
     1321    if (cwcItemToAdd >= 256 /* see wszNewValue size below */)
     1322        return ErrorMsg("RegistryAddStringToList: The value to add is too long! Max 256 chars.");
     1323
     1324    /*
     1325     * Open/create the key.
     1326     */
     1327    HKEY    hKey   = NULL;
     1328    DWORD   dwDisp = 0;
     1329    LSTATUS lrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pwszSubKey, 0 /*Reserved*/, NULL /*pClass*/, REG_OPTION_NON_VOLATILE,
     1330                                 KEY_READ | KEY_WRITE, NULL /*pSecAttr*/, &hKey, &dwDisp);
     1331    if (lrc != ERROR_SUCCESS)
     1332        return ErrorMsgLStatusSWSRS("RegistryAddStringToList: RegCreateKeyEx HKLM/'", pwszSubKey, "' failed: ", lrc, NULL);
     1333
     1334    /*
     1335     * Query the current value.
     1336     */
     1337    int     rcExit         = EXIT_FAIL;
     1338    wchar_t wszValue[1024] = { 0 };
     1339    DWORD   cbValue        = sizeof(wszValue) - sizeof(wchar_t);
     1340    DWORD   dwType         = 0;
     1341    lrc = RegQueryValueEx(hKey, pwszValueName, NULL /*pReserved*/, &dwType, (LPBYTE)wszValue, &cbValue);
     1342    if (lrc == ERROR_FILE_NOT_FOUND)
     1343    {
     1344        PrintStr("RegistryAddStringToList: Value not found, creating a new one...\r\n");
     1345        wszValue[0] = '\0';
     1346        cbValue     = sizeof(wchar_t);
     1347        dwType      = REG_SZ;
     1348        lrc = ERROR_SUCCESS;
     1349    }
     1350    if (lrc == ERROR_SUCCESS && dwType == REG_SZ)
     1351    {
     1352#ifdef DEBUG
     1353        PrintSWS("RegistryAddStringToList: Value string: '", wszValue, "'\r\n");
     1354#endif
     1355
     1356        /*
     1357         * Scan the list and make a new copy of it with the new item added
     1358         * in the specified place.
     1359         *
     1360         * Having checked that what we're adding isn't more than 256 + 1 chars long
     1361         * above, we can avoid tedious overflow checking here the simple expedient of
     1362         * using an output buffer that's at least 256 + 1 chars bigger than the source.
     1363         */
     1364        wchar_t  wszNewValue[RT_ELEMENTS(wszValue) + 256 + 4] = { 0 };
     1365        wchar_t *pwszDst = wszNewValue;
     1366        wchar_t *pwszSrc = wszValue;
     1367        unsigned uCurPos = 0;
     1368        for (;;)
    2281369        {
    229             g_pfnDIFXAPISetLogCallback = (fnDIFXAPISetLogCallback)GetProcAddress(hDIFxAPI, "DIFXAPISetLogCallbackW");
    230             if (g_pfnDIFXAPISetLogCallback == NULL)
     1370            /* Skip leading commas: */
     1371            wchar_t wc            = *pwszSrc;
     1372            bool    fLeadingComma = wc == ',';
     1373            if (fLeadingComma)
     1374                do
     1375                    wc = *++pwszSrc;
     1376                while (wc == ',');
     1377
     1378            /* Insert the new item if we're at the right position or have reached
     1379               the end of the list and have yet done so. */
     1380            if (uCurPos == uPosition || (!wc && uCurPos < uPosition))
    2311381            {
    232                 _tprintf(_T("ERROR: Unable to retrieve entry point for DIFXAPISetLogCallbackW!\n"));
    233                 hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
     1382                if (fLeadingComma)
     1383                    *pwszDst++ = ',';
     1384                memcpy(pwszDst, pwszItemToAdd, cwcItemToAdd * sizeof(wchar_t));
     1385                pwszDst += cwcItemToAdd;
     1386                fLeadingComma = true;
    2341387            }
     1388
     1389            /* Get out of the loop if we're at the end of the input. */
     1390            if (!wc)
     1391                break; /* don't preserve trailing commas? Old code didn't (see strtok_r code). */
     1392
     1393            /* Start of a new 'value', so, find the end of it. */
     1394            wchar_t *pwszSrcEnd = pwszSrc + 1;
     1395            do
     1396                wc = *++pwszSrcEnd;
     1397            while (wc != '\0' && wc != ',');
     1398            size_t const cwcItem = (size_t)(pwszSrcEnd - pwszSrc);
     1399
     1400            /* If it matches pwszItemToRemove and the VBOX_REG_STRINGLIST_ALLOW_DUPLICATES
     1401               wasn't specified, we'll skip this value. */
     1402            ASMCompilerBarrier(); /* Paranoia ^ 2*/
     1403            if (   !(fFlags & VBOX_REG_STRINGLIST_ALLOW_DUPLICATES)
     1404                && IsStringListItemMatch(pwszSrc, cwcItem, pwszItemToAdd, cwcItemToAdd))
     1405                pwszSrc = pwszSrcEnd;
     1406            else
     1407            {
     1408                if (fLeadingComma)
     1409                    *pwszDst++ = ',';
     1410                memmove(pwszDst, pwszSrc, cwcItem * sizeof(*pwszDst));
     1411                pwszDst += cwcItem;
     1412                pwszSrc  = pwszSrcEnd;
     1413                ASMCompilerBarrier(); /* Paranoia ^ 3 */
     1414            }
     1415
     1416            /* pwszSrc should not point at a comma or a zero terminator. */
    2351417        }
    236     }
    237 
    238     if (SUCCEEDED(hr))
    239     {
    240         FILE *phFile = NULL;
    241         if (pszLogFile)
     1418        *pwszDst = '\0';
     1419        DWORD const cbNewValue = (DWORD)((pwszDst + 1 - &wszNewValue[0]) * sizeof(wchar_t));
     1420
     1421#ifdef DEBUG
     1422        PrintSWS("RegistryAddStringToList: New value:    '", wszNewValue, "'\r\n");
     1423#endif
     1424
     1425        /*
     1426         * Add the value if changed.
     1427         */
     1428        if (   cbNewValue == cbValue
     1429            && memcmp(wszNewValue, wszValue, cbNewValue) == 0)
     1430            rcExit = EXIT_OK;
     1431        else
    2421432        {
    243             phFile = _wfopen(pszLogFile, _T("a"));
    244             if (!phFile)
    245                 _tprintf(_T("ERROR: Unable to create log file!\n"));
    246             g_pfnDIFXAPISetLogCallback(LogCallback, phFile);
     1433            lrc = RegSetValueExW(hKey, pwszValueName, 0, REG_SZ, (LPBYTE)wszNewValue, cbNewValue);
     1434            if (lrc == ERROR_SUCCESS)
     1435                rcExit = EXIT_OK;
     1436            else
     1437                ErrorMsgLStatusSWSWSWSRS("RegistryAddStringToList: RegSetValueExW HKLM/'",
     1438                                         pwszSubKey, "'/'", pwszValueName, "' = '", wszNewValue, "' failed: ", lrc, NULL);
    2471439        }
    248 
    249         INSTALLERINFO instInfo =
     1440    }
     1441    else if (lrc != ERROR_SUCCESS)
     1442        ErrorMsgLStatusSWSWSRS("RegistryAddStringToList: RegQueryValueEx HKLM/'",
     1443                               pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL);
     1444    else
     1445        ErrorMsgLStatusSWSWSRS("RegistryAddStringToList: Unexpected value type for HKLM/'",
     1446                               pwszSubKey, "'/'", pwszValueName, "': ", (LSTATUS)dwType, ", expected REG_SZ (1)");
     1447
     1448    RegCloseKey(hKey);
     1449    return rcExit;
     1450}
     1451
     1452
     1453/**
     1454 * Handles 'netprovider add'.
     1455 */
     1456static int handleNetProviderAdd(unsigned cArgs, wchar_t **papwszArgs)
     1457{
     1458    const wchar_t * const pwszProvider = papwszArgs[0];
     1459    wchar_t const * const pwszPosition = cArgs > 1 ? papwszArgs[1] : L"0";
     1460    uint32_t              uPosition    = 0;
     1461    if (cArgs > 1 && !ArgToUInt32Full(pwszPosition, "position", &uPosition))
     1462        return EXIT_USAGE;
     1463
     1464    PrintSWSWS("Adding network provider '", pwszProvider, "' (Position = ", pwszPosition, ") ...\r\n");
     1465    int rcExit = RegistryAddStringToList(L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
     1466                                         L"ProviderOrder",
     1467                                         pwszProvider, uPosition, VBOX_REG_STRINGLIST_NONE);
     1468    if (rcExit == EXIT_OK)
     1469        PrintStr("Network provider successfully added!\r\n");
     1470
     1471    return rcExit;
     1472}
     1473
     1474
     1475/**
     1476 * Removes an item from a comma separated registry string (REG_SZ).
     1477 *
     1478 * Only operates in HKLM for now, if needed it can be extended later for use
     1479 * with other hives.
     1480 *
     1481 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     1482 * @param   pwszSubKey          Subkey containing the list value.
     1483 * @param   pwszValueName       The value name.
     1484 * @param   pwszItemToRemove    The item to remove from the list.
     1485 */
     1486static int RegistryRemoveStringFromList(const wchar_t *pwszSubKey, const wchar_t *pwszValueName, const wchar_t *pwszItemToRemove)
     1487{
     1488    /*
     1489     * Open the specified key.
     1490     */
     1491    HKEY hKey = NULL;
     1492    LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwszSubKey, 0 /*dwOptions*/, KEY_READ | KEY_WRITE, &hKey);
     1493    if (lrc != ERROR_SUCCESS)
     1494        return ErrorMsgLStatusSWSRS("RegistryRemoveStringFromList: RegOpenKeyExW HKLM/'", pwszSubKey, "' failed: ", lrc, NULL);
     1495
     1496    /*
     1497     * Query the specified value.
     1498     */
     1499    int     rcExit         = EXIT_FAIL;
     1500    wchar_t wszValue[1296] = { 0 };
     1501    DWORD   cbValue        = sizeof(wszValue) - sizeof(wchar_t);
     1502    DWORD   dwType         = 0;
     1503    lrc = RegQueryValueEx(hKey, pwszValueName, NULL /*pReserved*/, &dwType, (LPBYTE)wszValue, &cbValue);
     1504    if (lrc == ERROR_SUCCESS && dwType == REG_SZ)
     1505    {
     1506#ifdef DEBUG
     1507        PrintSWS("RegistryRemoveStringFromList: Value string: '", wszValue, "'\r\n");
     1508#endif
     1509
     1510        /*
     1511         * Scan for item, shifting the query result as we scan.
     1512         */
     1513        size_t const      cwcItemToRemove = RTUtf16Len(pwszItemToRemove);
     1514        wchar_t volatile *pwszSrc         = wszValue;
     1515        wchar_t volatile *pwszDst         = wszValue;
     1516        for (;;)
    2501517        {
    251             TEXT("{7d2c708d-c202-40ab-b3e8-de21da1dc629}"), /* Our GUID for representing this installation tool. */
    252             TEXT("VirtualBox Guest Additions Install Helper"),
    253             TEXT("VirtualBox Guest Additions"), /** @todo Add version! */
    254             TEXT("Oracle Corporation")
    255         };
    256 
    257         _TCHAR szDriverInf[MAX_PATH + 1];
    258         if (0 == GetFullPathNameW(pszDriverPath, MAX_PATH, szDriverInf, NULL))
     1518            /* Skip leading commas: */
     1519            wchar_t    wc            = *pwszSrc;
     1520            bool const fLeadingComma = wc == ',';
     1521            if (fLeadingComma)
     1522                do
     1523                    wc = *++pwszSrc;
     1524                while (wc == ',');
     1525            if (!wc)
     1526                break; /* don't preserve trailing commas? Old code didn't (see strtok_r code). */
     1527
     1528            /* Start of a new 'value', so, find the end of it. */
     1529            wchar_t volatile *pwszSrcEnd = pwszSrc + 1;
     1530            do
     1531                wc = *++pwszSrcEnd;
     1532            while (wc != '\0' && wc != ',');
     1533            size_t const cwcItem = (size_t)(pwszSrcEnd - pwszSrc);
     1534
     1535            /* If it matches pwszItemToRemove, do not copy it. */
     1536            ASMCompilerBarrier(); /* Paranoia ^ 2 */
     1537            if (IsStringListItemMatch(pwszSrc, cwcItem, pwszItemToRemove, cwcItemToRemove))
     1538                pwszSrc = pwszSrcEnd;
     1539            else
     1540            {
     1541                if (fLeadingComma)
     1542                    *pwszDst++ = ',';
     1543                memmove((void *)pwszDst, (void const *)pwszSrc, cwcItem * sizeof(*pwszDst));
     1544                pwszDst += cwcItem;
     1545                pwszSrc  = pwszSrcEnd;
     1546                ASMCompilerBarrier(); /* paranoia ^ 3 */
     1547            }
     1548
     1549            /* pwszSrc should not point at a comma or a zero terminator. */
     1550        }
     1551        *pwszDst = '\0';
     1552#ifdef DEBUG
     1553        PrintSWS("RegistryRemoveStringFromList: New value:    '", wszValue, "'\r\n");
     1554#endif
     1555
     1556        /*
     1557         * Save the new value if we've made any changes.
     1558         */
     1559        if (pwszDst == pwszSrc)
     1560            rcExit = EXIT_OK;
     1561        else
    2591562        {
    260             _tprintf(_T("ERROR: INF-Path too long / could not be retrieved!\n"));
    261             hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
     1563            cbValue = (DWORD)((pwszDst + 1 - &wszValue[0]) * sizeof(wchar_t));
     1564            lrc = RegSetValueExW(hKey, pwszValueName, 0, REG_SZ, (LPBYTE)wszValue, cbValue);
     1565            if (lrc == ERROR_SUCCESS)
     1566                rcExit = EXIT_OK;
     1567            else
     1568                ErrorMsgLStatusSWSWSWSRS("RegistryRemoveStringFromList: RegSetValueExW HKLM/'",
     1569                                         pwszSubKey, "'/'", pwszValueName, "' = '", wszValue, "' failed: ", lrc, NULL);
     1570        }
     1571    }
     1572    else if (lrc == ERROR_FILE_NOT_FOUND)
     1573    {
     1574#ifdef DEBUG
     1575        PrintStr("RegistryRemoveStringFromList: Value not present in registry\r\n");
     1576#endif
     1577        rcExit = EXIT_OK;
     1578    }
     1579    else if (lrc != ERROR_SUCCESS)
     1580        ErrorMsgLStatusSWSWSRS("RegistryRemoveStringFromList: RegQueryValueEx HKLM/'",
     1581                               pwszSubKey, "'/'", pwszValueName, "' failed: ", lrc, NULL);
     1582    else
     1583        ErrorMsgLStatusSWSWSRS("RegistryRemoveStringFromList: Unexpected value type for HKLM/'",
     1584                               pwszSubKey, "'/'", pwszValueName, "': ", (LSTATUS)dwType, ", expected REG_SZ (1)");
     1585    RegCloseKey(hKey);
     1586    return rcExit;
     1587}
     1588
     1589
     1590/**
     1591 * Handles 'netprovider remove'.
     1592 */
     1593static int handleNetProviderRemove(unsigned cArgs, wchar_t **papwszArgs)
     1594{
     1595    const wchar_t * const pwszProvider = papwszArgs[0];
     1596    PrintSWS("Removing network provider '", pwszProvider, "' ...\r\n");
     1597
     1598    int rcExit = RegistryRemoveStringFromList(L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
     1599                                              L"ProviderOrder",
     1600                                              pwszProvider);
     1601    if (rcExit == EXIT_OK)
     1602        PrintStr("Network provider successfully removed!\r\n");
     1603
     1604    RT_NOREF(cArgs);
     1605    return rcExit;
     1606}
     1607
     1608
     1609/**
     1610 * Worker for the 'service create' handler.
     1611 */
     1612static int CreateService(const wchar_t *pwszService,
     1613                         const wchar_t *pwszDisplayName,
     1614                         uint32_t       uServiceType,
     1615                         uint32_t       uStartType,
     1616                         const wchar_t *pwszBinPath,
     1617                         const wchar_t *pwszLoadOrderGroup,
     1618                         const wchar_t *pwszDependencies,
     1619                         const wchar_t *pwszLogonUser,
     1620                         const wchar_t *pwszLogonPassword)
     1621{
     1622    PrintSWSWS("Installing service '", pwszService, "' ('", pwszDisplayName, ") ...\r\n");
     1623
     1624    /*
     1625     * Transform the dependency list to a REG_MULTI_SZ.
     1626     */
     1627    if (pwszDependencies != NULL)
     1628    {
     1629        /* Copy it into alloca() buffer so we can modify it. */
     1630        size_t cwc = RTUtf16Len(pwszDependencies);
     1631        wchar_t *pwszDup = (wchar_t *)alloca((cwc + 2) * sizeof(wchar_t));
     1632        memcpy(pwszDup, pwszDependencies, cwc * sizeof(wchar_t));
     1633        pwszDup[cwc]     = L'\0';
     1634        pwszDup[cwc + 1] = L'\0';   /* double termination */
     1635
     1636        /* Perform: s/,/\0/g */
     1637        while (cwc-- > 0 )
     1638            if (pwszDup[cwc] == L',')
     1639                pwszDup[cwc] = L'\0';
     1640
     1641        pwszDependencies = pwszDup;
     1642    }
     1643
     1644    SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
     1645    if (hSCManager == NULL)
     1646        return ErrorMsgLastErr("OpenSCManagerW failed");
     1647
     1648    int rcExit = EXIT_FAIL;
     1649    DWORD dwTag = 0xDEADBEAF;
     1650    SC_HANDLE hService = CreateServiceW(hSCManager, pwszService, pwszDisplayName, SERVICE_ALL_ACCESS, uServiceType, uStartType,
     1651                                        SERVICE_ERROR_NORMAL, pwszBinPath, pwszLoadOrderGroup, pwszLoadOrderGroup ? &dwTag : NULL,
     1652                                        pwszDependencies, pwszLogonUser, pwszLogonPassword);
     1653    if (hService != NULL)
     1654    {
     1655        CloseServiceHandle(hService);
     1656        PrintStr("Installation of service successful!\r\n");
     1657        rcExit = EXIT_OK;
     1658    }
     1659    else
     1660    {
     1661        DWORD dwErr = GetLastError();
     1662        if (dwErr == ERROR_SERVICE_EXISTS)
     1663        {
     1664            PrintStr("Service already exists. Updating the service config ...\r\n");
     1665            hService = OpenServiceW(hSCManager, pwszService, SERVICE_ALL_ACCESS);
     1666            if (hService != NULL)
     1667            {
     1668                if (ChangeServiceConfigW(hService, uServiceType, uStartType, SERVICE_ERROR_NORMAL, pwszBinPath,
     1669                                         pwszLoadOrderGroup, pwszLoadOrderGroup ? &dwTag : NULL, pwszDependencies,
     1670                                         pwszLogonUser, pwszLogonPassword, pwszDisplayName))
     1671                {
     1672                    PrintStr("The service config has been successfully updated.\r\n");
     1673                    rcExit = EXIT_OK;
     1674                }
     1675                else
     1676                    rcExit = ErrorMsgLastErrSWS("ChangeServiceConfigW failed on '", pwszService, "'!");
     1677                CloseServiceHandle(hService);
     1678            }
     1679            else
     1680                rcExit = ErrorMsgLastErrSWS("OpenSCManagerW failed on '", pwszService, "'!");
     1681
     1682            /*
     1683             * This branch does not return an error to avoid installations failures,
     1684             * if updating service parameters. Better to have a running system with old
     1685             * parameters and the failure information in the installation log.
     1686             */
     1687            rcExit = EXIT_OK;
    2621688        }
    2631689        else
     1690            rcExit = ErrorMsgLastErrSWS("CreateServiceW for '", pwszService, "'!");
     1691    }
     1692
     1693    CloseServiceHandle(hSCManager);
     1694    return rcExit;
     1695}
     1696
     1697
     1698/** Handles 'service create'. */
     1699static int handleServiceCreate(unsigned cArgs, wchar_t **papwszArgs)
     1700{
     1701    uint32_t uServiceType;
     1702    if (!ArgToUInt32Full(papwszArgs[2], "service-type", &uServiceType))
     1703        return EXIT_USAGE;
     1704
     1705    uint32_t uStartType;
     1706    if (!ArgToUInt32Full(papwszArgs[3], "start-type", &uStartType))
     1707        return EXIT_USAGE;
     1708
     1709    return CreateService(papwszArgs[0], papwszArgs[1], uServiceType, uStartType, papwszArgs[4],
     1710                         cArgs > 5 ? papwszArgs[5] : NULL,
     1711                         cArgs > 6 ? papwszArgs[6] : NULL,
     1712                         cArgs > 7 ? papwszArgs[7] : NULL,
     1713                         cArgs > 8 ? papwszArgs[8] : NULL);
     1714}
     1715
     1716
     1717/**
     1718 * Worker for the 'service delete' handler.
     1719 */
     1720static int DelService(const wchar_t *pwszService)
     1721{
     1722    PrintSWS("Removing service '", pwszService, "' ...\r\n");
     1723
     1724    SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
     1725    if (hSCManager == NULL)
     1726        return ErrorMsgLastErr("OpenSCManagerW failed");
     1727
     1728    int rcExit = EXIT_FAIL;
     1729    SC_HANDLE hService = NULL;
     1730    hService = OpenServiceW(hSCManager, pwszService, SERVICE_ALL_ACCESS);
     1731    if (hService)
     1732    {
     1733        SC_LOCK hSCLock = LockServiceDatabase(hSCManager);
     1734        if (hSCLock != NULL)
    2641735        {
    265             if (fInstall)
    266                 _tprintf(_T("Installing driver ...\n"));
    267             else
    268                 _tprintf(_T("Uninstalling driver ...\n"));
    269             _tprintf(_T("INF-File: %ws\n"), szDriverInf);
    270 
    271             DWORD dwFlags = DRIVER_PACKAGE_FORCE;
    272             if (!fInstall)
    273                 dwFlags |= DRIVER_PACKAGE_DELETE_FILES;
    274 
    275             OSVERSIONINFO osi;
    276             memset(&osi, 0, sizeof(OSVERSIONINFO));
    277             osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    278             if ( (GetVersionEx(&osi) != 0)
    279               && (osi.dwPlatformId == VER_PLATFORM_WIN32_NT)
    280               && (osi.dwMajorVersion < 6))
     1736            if (DeleteService(hService))
    2811737            {
    282                 if (fInstall)
    283                 {
    284                     _tprintf(_T("Using legacy mode for install ...\n"));
    285                     dwFlags |= DRIVER_PACKAGE_LEGACY_MODE;
    286                 }
    287             }
    288 
    289             if (fSilent)
    290             {
    291                 _tprintf(_T("Installation is silent ...\n"));
    292                 /*
    293                  * Don't add DRIVER_PACKAGE_SILENT to dwFlags here, otherwise
    294                  * installation will fail because we (still) don't have WHQL certified
    295                  * drivers. See CERT_E_WRONG_USAGE on MSDN for more information.
    296                  */
    297             }
    298 
    299             BOOL fReboot;
    300             DWORD dwRet = fInstall ?
    301                             g_pfnDriverPackageInstall(szDriverInf, dwFlags, &instInfo, &fReboot)
    302                           : g_pfnDriverPackageUninstall(szDriverInf, dwFlags, &instInfo, &fReboot);
    303             if (dwRet != ERROR_SUCCESS)
    304             {
    305                 switch (dwRet)
    306                 {
    307                     case CRYPT_E_FILE_ERROR:
    308                         _tprintf(_T("ERROR: The catalog file for the specified driver package was not found!\n"));
    309                         break;
    310 
    311                     case ERROR_ACCESS_DENIED:
    312                         _tprintf(_T("ERROR: Caller is not in Administrators group to (un)install this driver package!\n"));
    313                         break;
    314 
    315                     case ERROR_BAD_ENVIRONMENT:
    316                         _tprintf(_T("ERROR: The current Microsoft Windows version does not support this operation!\n"));
    317                         break;
    318 
    319                     case ERROR_CANT_ACCESS_FILE:
    320                         _tprintf(_T("ERROR: The driver package files could not be accessed!\n"));
    321                         break;
    322 
    323                     case ERROR_DEPENDENT_APPLICATIONS_EXIST:
    324                         _tprintf(_T("ERROR: DriverPackageUninstall removed an association between the driver package and the specified application but the function did not uninstall the driver package because other applications are associated with the driver package!\n"));
    325                         break;
    326 
    327                     case ERROR_DRIVER_PACKAGE_NOT_IN_STORE:
    328                         _tprintf(_T("ERROR: There is no INF file in the DIFx driver store that corresponds to the INF file %ws!\n"), szDriverInf);
    329                         break;
    330 
    331                     case ERROR_FILE_NOT_FOUND:
    332                         _tprintf(_T("ERROR: File not found! File = %ws\n"), szDriverInf);
    333                         break;
    334 
    335                     case ERROR_IN_WOW64:
    336                         _tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!\n"));
    337                         break;
    338 
    339                     case ERROR_INVALID_FLAGS:
    340                         _tprintf(_T("ERROR: The flags specified are invalid!\n"));
    341                         break;
    342 
    343                     case ERROR_INSTALL_FAILURE:
    344                         _tprintf(_T("ERROR: The (un)install operation failed! Consult the Setup API logs for more information.\n"));
    345                         break;
    346 
    347                     case ERROR_NO_MORE_ITEMS:
    348                         _tprintf(
    349                                  _T(
    350                                     "ERROR: The function found a match for the HardwareId value, but the specified driver was not a better match than the current driver and the caller did not specify the INSTALLFLAG_FORCE flag!\n"));
    351                         break;
    352 
    353                     case ERROR_NO_DRIVER_SELECTED:
    354                         _tprintf(_T("ERROR: No driver in .INF-file selected!\n"));
    355                         break;
    356 
    357                     case ERROR_SECTION_NOT_FOUND:
    358                         _tprintf(_T("ERROR: Section in .INF-file was not found!\n"));
    359                         break;
    360 
    361                     case ERROR_SHARING_VIOLATION:
    362                         _tprintf(_T("ERROR: A component of the driver package in the DIFx driver store is locked by a thread or process\n"));
    363                         break;
    364 
    365                     /*
    366                      * !    sig:           Verifying file against specific Authenticode(tm) catalog failed! (0x800b0109)
    367                      * !    sig:           Error 0x800b0109: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
    368                      * !!!  sto:           No error message will be displayed as client is running in non-interactive mode.
    369                      * !!!  ndv:           Driver package failed signature validation. Error = 0xE0000247
    370                      */
    371                     case ERROR_DRIVER_STORE_ADD_FAILED:
    372                         _tprintf(_T("ERROR: Adding driver to the driver store failed!!\n"));
    373                         break;
    374 
    375                     case ERROR_UNSUPPORTED_TYPE:
    376                         _tprintf(_T("ERROR: The driver package type is not supported of INF %ws!\n"), szDriverInf);
    377                         break;
    378 
    379                     case ERROR_NO_SUCH_DEVINST:
    380                         _tprintf(_T("INFO: The driver package was installed but no matching devices found in the device tree (ERROR_NO_SUCH_DEVINST).\n"));
    381                     break;
    382 
    383                     default:
    384                     {
    385                         /* Try error lookup with GetErrorMsg(). */
    386                         TCHAR szErrMsg[1024];
    387                         GetErrorMsg(dwRet, szErrMsg, sizeof(szErrMsg));
    388                         _tprintf(_T("ERROR (%08lx): %ws\n"), dwRet, szErrMsg);
    389                         break;
    390                     }
    391                 }
    392 
    393                 if (dwRet == ERROR_NO_SUCH_DEVINST)
    394                 {
    395                     /* GA installer should ignore this error code and continue */
    396                     hr = S_OK;
    397                 }
    398                 else
    399                     hr = HRESULT_FROM_WIN32(dwRet);
    400             }
    401             g_pfnDIFXAPISetLogCallback(NULL, NULL);
    402             if (phFile)
    403                 fclose(phFile);
    404             if (SUCCEEDED(hr))
    405             {
    406                 _tprintf(_T("Driver was %sinstalled successfully!\n"), fInstall ? _T("") : _T("un"));
    407                 if (fReboot)
    408                     _tprintf(_T("A reboot is needed to complete the driver %sinstallation!\n"), fInstall ? _T("") : _T("un"));
    409             }
    410         }
    411     }
    412 
    413     if (NULL != hDIFxAPI)
    414        FreeLibrary(hDIFxAPI);
    415 
    416     return SUCCEEDED(hr) ? EXIT_OK : EXIT_FAIL;
    417 }
    418 
    419 static UINT WINAPI vboxDrvInstExecuteInfFileCallback(PVOID Context,
    420                                                      UINT Notification,
    421                                                      UINT_PTR Param1,
    422                                                      UINT_PTR Param2) RT_NOTHROW_DEF
    423 {
    424 #ifdef DEBUG
    425     _tprintf (_T( "Got installation notification %u\n"), Notification);
    426 #endif
    427 
    428     switch (Notification)
    429     {
    430         case SPFILENOTIFY_NEEDMEDIA:
    431             _tprintf (_T( "Requesting installation media ...\n"));
    432             break;
    433 
    434         case SPFILENOTIFY_STARTCOPY:
    435             _tprintf (_T( "Copying driver files to destination ...\n"));
    436             break;
    437 
    438         case SPFILENOTIFY_TARGETNEWER:
    439         case SPFILENOTIFY_TARGETEXISTS:
    440             return TRUE;
    441     }
    442 
    443     return SetupDefaultQueueCallback(Context, Notification, Param1, Param2);
    444 }
    445 
    446 /**
    447  * Executes a sepcified .INF section to install/uninstall drivers and/or services.
    448  *
    449  * @return  Exit code (EXIT_OK, EXIT_FAIL)
    450  * @param   pszSection          Section to execute; usually it's "DefaultInstall".
    451  * @param   iMode               Execution mode to use (see MSDN).
    452  * @param   pszInf              Full qualified path of the .INF file to use.
    453  */
    454 int ExecuteInfFile(const _TCHAR *pszSection, int iMode, const _TCHAR *pszInf)
    455 {
    456     RT_NOREF(iMode);
    457     _tprintf(_T("Installing from INF-File: %ws (Section: %ws) ...\n"),
    458              pszInf, pszSection);
    459 
    460     UINT uErrorLine = 0;
    461     HINF hINF = SetupOpenInfFile(pszInf, NULL, INF_STYLE_WIN4, &uErrorLine);
    462     if (hINF != INVALID_HANDLE_VALUE)
    463     {
    464         PVOID pvQueue = SetupInitDefaultQueueCallback(NULL);
    465 
    466         BOOL fSuccess = SetupInstallFromInfSection(NULL,
    467                                                     hINF,
    468                                                     pszSection,
    469                                                     SPINST_ALL,
    470                                                     HKEY_LOCAL_MACHINE,
    471                                                     NULL,
    472                                                     SP_COPY_NEWER_OR_SAME | SP_COPY_NOSKIP,
    473                                                     vboxDrvInstExecuteInfFileCallback,
    474                                                     pvQueue,
    475                                                     NULL,
    476                                                     NULL
    477                                                     );
    478         if (fSuccess)
    479         {
    480             _tprintf (_T( "File installation stage successful\n"));
    481 
    482             fSuccess = SetupInstallServicesFromInfSection(hINF,
    483                                                           L"DefaultInstall.Services",
    484                                                           0 /* Flags */);
    485             if (fSuccess)
    486             {
    487                 _tprintf (_T( "Service installation stage successful. Installation completed\n"));
     1738                PrintSWS("Service '", pwszService, "' successfully deleted.\r\n");
     1739                rcExit = EXIT_OK;
    4881740            }
    4891741            else
    4901742            {
    4911743                DWORD dwErr = GetLastError();
    492                 switch (dwErr)
     1744                if (dwErr == ERROR_SERVICE_MARKED_FOR_DELETE)
    4931745                {
    494                     case ERROR_SUCCESS_REBOOT_REQUIRED:
    495                         _tprintf (_T( "A reboot is required to complete the installation\n"));
    496                         break;
    497 
    498                     case ERROR_SECTION_NOT_FOUND:
    499                         break;
    500 
    501                     default:
    502                         _tprintf (_T( "Error %ld while installing service\n"), dwErr);
    503                         break;
     1746                    PrintSWS("Service '", pwszService, "' already marked for deletion.\r\n");
     1747                    rcExit = EXIT_OK;
    5041748                }
    505             }
    506         }
    507         else
    508             _tprintf (_T( "Error %ld while installing files\n"), GetLastError());
    509 
    510         if (pvQueue)
    511             SetupTermDefaultQueueCallback(pvQueue);
    512 
    513         SetupCloseInfFile(hINF);
    514     }
    515     else
    516         _tprintf (_T( "Unable to open %ws: %ld (error line %u)\n"),
    517                   pszInf, GetLastError(), uErrorLine);
    518 
    519     return EXIT_OK;
    520 }
    521 
    522 /**
    523  * Adds a string entry to a MULTI_SZ registry list.
    524  *
    525  * @return  Exit code (EXIT_OK, EXIT_FAIL)
    526  * @param   pszSubKey           Sub key containing the list.
    527  * @param   pszKeyValue         The actual key name of the list.
    528  * @param   pszValueToAdd       The value to add to the list.
    529  * @param   uiOrder             Position (zero-based) of where to add the value to the list.
    530  */
    531 int RegistryAddStringToMultiSZ(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToAdd, unsigned int uiOrder)
    532 {
    533 #ifdef DEBUG
    534     _tprintf(_T("AddStringToMultiSZ: Adding MULTI_SZ string %ws to %ws\\%ws (Order = %d)\n"), pszValueToAdd, pszSubKey, pszKeyValue, uiOrder);
    535 #endif
    536 
    537     HKEY hKey = NULL;
    538     DWORD disp, dwType;
    539     LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
    540     if (lRet != ERROR_SUCCESS)
    541         _tprintf(_T("AddStringToMultiSZ: RegCreateKeyEx %s failed with error %ld!\n"), pszSubKey, lRet);
    542 
    543     if (lRet == ERROR_SUCCESS)
    544     {
    545         TCHAR szKeyValue[512] = { 0 };
    546         TCHAR szNewKeyValue[512] = { 0 };
    547         DWORD cbKeyValue = sizeof(szKeyValue);
    548 
    549         lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
    550         if (   lRet != ERROR_SUCCESS
    551             || dwType != REG_MULTI_SZ)
    552         {
    553            _tprintf(_T("AddStringToMultiSZ: RegQueryValueEx failed with error %ld, key type = %#lx!\n"), lRet, dwType);
    554         }
    555         else
    556         {
    557 
    558             /* Look if the network provider is already in the list. */
    559             unsigned int iPos = 0;
    560             size_t cb = 0;
    561 
    562             /* Replace delimiting "\0"'s with "," to make tokenizing work. */
    563             for (unsigned i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
    564                 if (szKeyValue[i] == '\0') szKeyValue[i] = ',';
    565 
    566             TCHAR *pszToken = wcstok(szKeyValue, _T(","));
    567             TCHAR *pszNewToken = NULL;
    568             TCHAR *pNewKeyValuePos = szNewKeyValue;
    569             while (pszToken != NULL)
    570             {
    571                pszNewToken = wcstok(NULL, _T(","));
    572 
    573                /* Append new value (at beginning if iOrder=0). */
    574                if (iPos == uiOrder)
    575                {
    576                    memcpy(pNewKeyValuePos, pszValueToAdd, wcslen(pszValueToAdd)*sizeof(TCHAR));
    577 
    578                    cb += (wcslen(pszValueToAdd) + 1) * sizeof(TCHAR);  /* Add trailing zero as well. */
    579                    pNewKeyValuePos += wcslen(pszValueToAdd) + 1;
    580                    iPos++;
    581                }
    582 
    583                if (0 != wcsicmp(pszToken, pszValueToAdd))
    584                {
    585                    memcpy(pNewKeyValuePos, pszToken, wcslen(pszToken)*sizeof(TCHAR));
    586                    cb += (wcslen(pszToken) + 1) * sizeof(TCHAR);  /* Add trailing zero as well. */
    587                    pNewKeyValuePos += wcslen(pszToken) + 1;
    588                    iPos++;
    589                }
    590 
    591                pszToken = pszNewToken;
    592             }
    593 
    594             /* Append as last item if needed. */
    595             if (uiOrder >= iPos)
    596             {
    597                 memcpy(pNewKeyValuePos, pszValueToAdd, wcslen(pszValueToAdd)*sizeof(TCHAR));
    598                 cb += wcslen(pszValueToAdd) * sizeof(TCHAR);  /* Add trailing zero as well. */
    599             }
    600 
    601             lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szNewKeyValue, (DWORD)cb);
    602             if (lRet != ERROR_SUCCESS)
    603                _tprintf(_T("AddStringToMultiSZ: RegSetValueEx failed with error %ld!\n"), lRet);
    604         }
    605 
    606         RegCloseKey(hKey);
    607     #ifdef DEBUG
    608         if (lRet == ERROR_SUCCESS)
    609            _tprintf(_T("AddStringToMultiSZ: Value %ws successfully written!\n"), pszValueToAdd);
    610     #endif
    611     }
    612 
    613     return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
    614 }
    615 
    616 /**
    617  * Removes a string entry from a MULTI_SZ registry list.
    618  *
    619  * @return  Exit code (EXIT_OK, EXIT_FAIL)
    620  * @param   pszSubKey           Sub key containing the list.
    621  * @param   pszKeyValue         The actual key name of the list.
    622  * @param   pszValueToRemove    The value to remove from the list.
    623  */
    624 int RegistryRemoveStringFromMultiSZ(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToRemove)
    625 {
    626     /// @todo Make string sizes dynamically allocated!
    627 
    628     const TCHAR *pszKey = pszSubKey;
    629 #ifdef DEBUG
    630     _tprintf(_T("RemoveStringFromMultiSZ: Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), pszValueToRemove, pszSubKey, pszKeyValue);
    631 #endif
    632 
    633     HKEY hkey;
    634     DWORD disp, dwType;
    635     LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp);
    636     if (lRet != ERROR_SUCCESS)
    637         _tprintf(_T("RemoveStringFromMultiSZ: RegCreateKeyEx %s failed with error %ld!\n"), pszKey, lRet);
    638 
    639     if (lRet == ERROR_SUCCESS)
    640     {
    641         TCHAR szKeyValue[1024];
    642         DWORD cbKeyValue = sizeof(szKeyValue);
    643 
    644         lRet = RegQueryValueEx(hkey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
    645         if (   lRet   != ERROR_SUCCESS
    646             || dwType != REG_MULTI_SZ)
    647         {
    648             _tprintf(_T("RemoveStringFromMultiSZ: RegQueryValueEx failed with %ld, key type = %#lx!\n"), lRet, dwType);
    649         }
    650         else
    651         {
    652 #ifdef DEBUG
    653             _tprintf(_T("RemoveStringFromMultiSZ: Current key len: %ld\n"), cbKeyValue);
    654 #endif
    655 
    656             TCHAR szCurString[1024] = { 0 };
    657             TCHAR szFinalString[1024] = { 0 };
    658             int iIndex = 0;
    659             int iNewIndex = 0;
    660             for (unsigned i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
    661             {
    662                 if (szKeyValue[i] != _T('\0'))
    663                     szCurString[iIndex++] = szKeyValue[i];
    664 
    665                 if (   (!szKeyValue[i] == _T('\0'))
    666                     && (szKeyValue[i + 1] == _T('\0')))
    667                 {
    668                     if (NULL == wcsstr(szCurString, pszValueToRemove))
    669                     {
    670                         wcscat(&szFinalString[iNewIndex], szCurString);
    671 
    672                         if (iNewIndex == 0)
    673                             iNewIndex = iIndex;
    674                         else iNewIndex += iIndex;
    675 
    676                         szFinalString[++iNewIndex] = _T('\0');
    677                     }
    678 
    679                     iIndex = 0;
    680                     ZeroMemory(szCurString, sizeof(szCurString));
    681                 }
    682             }
    683             szFinalString[++iNewIndex] = _T('\0');
    684 #ifdef DEBUG
    685             _tprintf(_T("RemoveStringFromMultiSZ: New key value: %ws (%u bytes)\n"),
    686                      szFinalString, (unsigned)(iNewIndex * sizeof(TCHAR)));
    687 #endif
    688 
    689             lRet = RegSetValueExW(hkey, pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR));
    690             if (lRet != ERROR_SUCCESS)
    691                 _tprintf(_T("RemoveStringFromMultiSZ: RegSetValueEx failed with %ld!\n"), lRet);
    692         }
    693 
    694         RegCloseKey(hkey);
    695 #ifdef DEBUG
    696         if (lRet == ERROR_SUCCESS)
    697             _tprintf(_T("RemoveStringFromMultiSZ: Value %ws successfully removed!\n"), pszValueToRemove);
    698 #endif
    699     }
    700 
    701     return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
    702 }
    703 
    704 /**
    705  * Adds a string to a registry string list (STRING_SZ).
    706  * Only operates in HKLM for now, needs to be extended later for
    707  * using other hives. Only processes lists with a "," separator
    708  * at the moment.
    709  *
    710  * @return  Exit code (EXIT_OK, EXIT_FAIL)
    711  * @param   pszSubKey           Sub key containing the list.
    712  * @param   pszKeyValue         The actual key name of the list.
    713  * @param   pszValueToAdd       The value to add to the list.
    714  * @param   uiOrder             Position (zero-based) of where to add the value to the list.
    715  * @param   dwFlags             Flags.
    716  */
    717 int RegistryAddStringToList(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToAdd,
    718                             unsigned int uiOrder, DWORD dwFlags)
    719 {
    720     HKEY hKey = NULL;
    721     DWORD disp, dwType;
    722     LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
    723     if (lRet != ERROR_SUCCESS)
    724         _tprintf(_T("RegistryAddStringToList: RegCreateKeyEx %s failed with error %ld!\n"), pszSubKey, lRet);
    725 
    726     TCHAR szKeyValue[512] = { 0 };
    727     TCHAR szNewKeyValue[512] = { 0 };
    728     DWORD cbKeyValue = sizeof(szKeyValue);
    729 
    730     lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
    731     if (   lRet != ERROR_SUCCESS
    732         || dwType != REG_SZ)
    733     {
    734         _tprintf(_T("RegistryAddStringToList: RegQueryValueEx failed with %ld, key type = %#lx!\n"), lRet, dwType);
    735     }
    736 
    737     if (lRet == ERROR_SUCCESS)
    738     {
    739 #ifdef DEBUG
    740         _tprintf(_T("RegistryAddStringToList: Key value: %ws\n"), szKeyValue);
    741 #endif
    742 
    743         /* Create entire new list. */
    744         unsigned int iPos = 0;
    745         TCHAR *pszToken = wcstok(szKeyValue, _T(","));
    746         TCHAR *pszNewToken = NULL;
    747         while (pszToken != NULL)
    748         {
    749             pszNewToken = wcstok(NULL, _T(","));
    750 
    751             /* Append new provider name (at beginning if iOrder=0). */
    752             if (iPos == uiOrder)
    753             {
    754                 wcscat(szNewKeyValue, pszValueToAdd);
    755                 wcscat(szNewKeyValue, _T(","));
    756                 iPos++;
    757             }
    758 
    759             BOOL fAddToList = FALSE;
    760             if (   !wcsicmp(pszToken, pszValueToAdd)
    761                 && (dwFlags & VBOX_REG_STRINGLIST_ALLOW_DUPLICATES))
    762                 fAddToList = TRUE;
    763             else if (wcsicmp(pszToken, pszValueToAdd))
    764                 fAddToList = TRUE;
    765 
    766             if (fAddToList)
    767             {
    768                 wcscat(szNewKeyValue, pszToken);
    769                 wcscat(szNewKeyValue, _T(","));
    770                 iPos++;
    771             }
    772 
    773 #ifdef DEBUG
    774             _tprintf (_T("RegistryAddStringToList: Temp new key value: %ws\n"), szNewKeyValue);
    775 #endif
    776             pszToken = pszNewToken;
    777         }
    778 
    779         /* Append as last item if needed. */
    780         if (uiOrder >= iPos)
    781             wcscat(szNewKeyValue, pszValueToAdd);
    782 
    783         /* Last char a delimiter? Cut off ... */
    784         if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
    785             szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
    786 
    787         size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
    788 
    789 #ifdef DEBUG
    790         _tprintf(_T("RegistryAddStringToList: New provider list: %ws (%u bytes)\n"), szNewKeyValue, (unsigned)iNewLen);
    791 #endif
    792 
    793         lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
    794         if (lRet != ERROR_SUCCESS)
    795             _tprintf(_T("RegistryAddStringToList: RegSetValueEx failed with %ld!\n"), lRet);
    796     }
    797 
    798     RegCloseKey(hKey);
    799     return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
    800 }
    801 
    802 /**
    803  * Removes a string from a registry string list (STRING_SZ).
    804  * Only operates in HKLM for now, needs to be extended later for
    805  * using other hives. Only processes lists with a "," separator
    806  * at the moment.
    807  *
    808  * @return  Exit code (EXIT_OK, EXIT_FAIL)
    809  * @param   pszSubKey           Sub key containing the list.
    810  * @param   pszKeyValue         The actual key name of the list.
    811  * @param   pszValueToRemove    The value to remove from the list.
    812  */
    813 int RegistryRemoveStringFromList(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToRemove)
    814 {
    815     HKEY hKey = NULL;
    816     DWORD disp, dwType;
    817     LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
    818     if (lRet != ERROR_SUCCESS)
    819         _tprintf(_T("RegistryRemoveStringFromList: RegCreateKeyEx %s failed with error %ld!\n"), pszSubKey, lRet);
    820 
    821     TCHAR szKeyValue[512] = { 0 };
    822     TCHAR szNewKeyValue[512] = { 0 };
    823     DWORD cbKeyValue = sizeof(szKeyValue);
    824 
    825     lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
    826     if (   lRet != ERROR_SUCCESS
    827         || dwType != REG_SZ)
    828     {
    829         _tprintf(_T("RegistryRemoveStringFromList: RegQueryValueEx failed with %ld, key type = %#lx!\n"), lRet, dwType);
    830     }
    831 
    832     if (lRet == ERROR_SUCCESS)
    833     {
    834     #ifdef DEBUG
    835         _tprintf(_T("RegistryRemoveStringFromList: Key value: %ws\n"), szKeyValue);
    836     #endif
    837 
    838         /* Create entire new list. */
    839         int iPos = 0;
    840 
    841         TCHAR *pszToken = wcstok(szKeyValue, _T(","));
    842         TCHAR *pszNewToken = NULL;
    843         while (pszToken != NULL)
    844         {
    845             pszNewToken = wcstok(NULL, _T(","));
    846 
    847             /* Append all list values as long as it's not the
    848              * value we want to remove. */
    849             if (wcsicmp(pszToken, pszValueToRemove))
    850             {
    851                 wcscat(szNewKeyValue, pszToken);
    852                 wcscat(szNewKeyValue, _T(","));
    853                 iPos++;
    854             }
    855 
    856     #ifdef DEBUG
    857             _tprintf (_T("RegistryRemoveStringFromList: Temp new key value: %ws\n"), szNewKeyValue);
    858     #endif
    859             pszToken = pszNewToken;
    860         }
    861 
    862         /* Last char a delimiter? Cut off ... */
    863         if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
    864             szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
    865 
    866         size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
    867 
    868     #ifdef DEBUG
    869         _tprintf(_T("RegistryRemoveStringFromList: New provider list: %ws (%u bytes)\n"), szNewKeyValue, (unsigned)iNewLen);
    870     #endif
    871 
    872         lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
    873         if (lRet != ERROR_SUCCESS)
    874             _tprintf(_T("RegistryRemoveStringFromList: RegSetValueEx failed with %ld!\n"), lRet);
    875     }
    876 
    877     RegCloseKey(hKey);
    878     return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
    879 }
    880 
    881 /**
    882  * Adds a network provider with a specified order to the system.
    883  *
    884  * @return  Exit code (EXIT_OK, EXIT_FAIL)
    885  * @param   pszProvider         Name of network provider to add.
    886  * @param   uiOrder             Position in list (zero-based) of where to add.
    887  */
    888 int AddNetworkProvider(const TCHAR *pszProvider, unsigned int uiOrder)
    889 {
    890     _tprintf(_T("Adding network provider \"%ws\" (Order = %u) ...\n"), pszProvider, uiOrder);
    891     int rc = RegistryAddStringToList(_T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
    892                                      _T("ProviderOrder"),
    893                                      pszProvider, uiOrder, VBOX_REG_STRINGLIST_NONE /* No flags set */);
    894     if (rc == EXIT_OK)
    895         _tprintf(_T("Network provider successfully added!\n"));
    896     return rc;
    897 }
    898 
    899 /**
    900  * Removes a network provider from the system.
    901  *
    902  * @return  Exit code (EXIT_OK, EXIT_FAIL)
    903  * @param   pszProvider         Name of network provider to remove.
    904  */
    905 int RemoveNetworkProvider(const TCHAR *pszProvider)
    906 {
    907     _tprintf(_T("Removing network provider \"%ws\" ...\n"), pszProvider);
    908     int rc = RegistryRemoveStringFromList(_T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
    909                                           _T("ProviderOrder"),
    910                                           pszProvider);
    911     if (rc == EXIT_OK)
    912         _tprintf(_T("Network provider successfully removed!\n"));
    913     return rc;
    914 }
    915 
    916 int CreateService(const TCHAR *pszStartStopName,
    917                   const TCHAR *pszDisplayName,
    918                   int iServiceType,
    919                   int iStartType,
    920                   const TCHAR *pszBinPath,
    921                   const TCHAR *pszLoadOrderGroup,
    922                   const TCHAR *pszDependencies,
    923                   const TCHAR *pszLogonUser,
    924                   const TCHAR *pszLogonPassword)
    925 {
    926     int rc = ERROR_SUCCESS;
    927 
    928     _tprintf(_T("Installing service %ws (%ws) ...\n"), pszDisplayName, pszStartStopName);
    929 
    930     SC_HANDLE hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
    931     if (hSCManager == NULL)
    932     {
    933         _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());
    934         return EXIT_FAIL;
    935     }
    936 
    937     /* Fixup end of multistring. */
    938     TCHAR szDepend[ _MAX_PATH ] = { 0 }; /** @todo Use dynamically allocated string here! */
    939     if (pszDependencies != NULL)
    940     {
    941         _tcsnccpy (szDepend, pszDependencies, wcslen(pszDependencies));
    942         DWORD len = (DWORD)wcslen (szDepend);
    943         szDepend [len + 1] = 0;
    944 
    945         /* Replace comma separator on null separator. */
    946         for (DWORD i = 0; i < len; i++)
    947         {
    948             if (',' == szDepend [i])
    949                 szDepend [i] = 0;
    950         }
    951     }
    952 
    953     DWORD dwTag = 0xDEADBEAF;
    954     SC_HANDLE hService = CreateService (hSCManager,           /* SCManager database handle. */
    955                                         pszStartStopName,     /* Name of service. */
    956                                         pszDisplayName,       /* Name to display. */
    957                                         SERVICE_ALL_ACCESS,   /* Desired access. */
    958                                         iServiceType,         /* Service type. */
    959                                         iStartType,           /* Start type. */
    960                                         SERVICE_ERROR_NORMAL, /* Error control type. */
    961                                         pszBinPath,           /* Service's binary. */
    962                                         pszLoadOrderGroup,    /* Ordering group. */
    963                                         (pszLoadOrderGroup != NULL) ? &dwTag : NULL,           /* Tag identifier. */
    964                                         (pszDependencies != NULL) ? szDepend : NULL,           /* Dependencies. */
    965                                         (pszLogonUser != NULL) ? pszLogonUser: NULL,           /* Account. */
    966                                         (pszLogonPassword != NULL) ? pszLogonPassword : NULL); /* Password. */
    967     if (NULL == hService)
    968     {
    969         DWORD dwErr = GetLastError();
    970         switch (dwErr)
    971         {
    972 
    973         case ERROR_SERVICE_EXISTS:
    974         {
    975             _tprintf(_T("Service already exists. No installation required. Updating the service config.\n"));
    976 
    977             hService = OpenService (hSCManager,          /* SCManager database handle. */
    978                                     pszStartStopName,    /* Name of service. */
    979                                     SERVICE_ALL_ACCESS); /* Desired access. */
    980             if (NULL == hService)
    981             {
    982                 dwErr = GetLastError();
    983                 _tprintf(_T("Could not open service! Error: %ld\n"), dwErr);
    984             }
    985             else
    986             {
    987                 BOOL fResult = ChangeServiceConfig (hService,            /* Service handle. */
    988                                                    iServiceType,         /* Service type. */
    989                                                    iStartType,           /* Start type. */
    990                                                    SERVICE_ERROR_NORMAL, /* Error control type. */
    991                                                    pszBinPath,           /* Service's binary. */
    992                                                    pszLoadOrderGroup,    /* Ordering group. */
    993                                                    (pszLoadOrderGroup != NULL) ? &dwTag : NULL,          /* Tag identifier. */
    994                                                    (pszDependencies != NULL) ? szDepend : NULL,          /* Dependencies. */
    995                                                    (pszLogonUser != NULL) ? pszLogonUser: NULL,          /* Account. */
    996                                                    (pszLogonPassword != NULL) ? pszLogonPassword : NULL, /* Password. */
    997                                                    pszDisplayName);      /* Name to display. */
    998                 if (fResult)
    999                     _tprintf(_T("The service config has been successfully updated.\n"));
    10001749                else
    1001                 {
    1002                     dwErr = GetLastError();
    1003                     _tprintf(_T("Could not change service config! Error: %ld\n"), dwErr);
    1004                 }
    1005                 CloseServiceHandle(hService);
    1006             }
    1007 
    1008             /*
    1009              * This entire branch do not return an error to avoid installations failures,
    1010              * if updating service parameters. Better to have a running system with old
    1011              * parameters and the failure information in the installation log.
    1012              */
    1013             break;
    1014         }
    1015 
    1016         case ERROR_INVALID_PARAMETER:
    1017 
    1018             _tprintf(_T("Invalid parameter specified!\n"));
    1019             rc = EXIT_FAIL;
    1020             break;
    1021 
    1022         default:
    1023 
    1024             _tprintf(_T("Could not create service! Error: %ld\n"), dwErr);
    1025             rc = EXIT_FAIL;
    1026             break;
    1027         }
    1028 
    1029         if (rc == EXIT_FAIL)
    1030             goto cleanup;
    1031     }
    1032     else
    1033     {
    1034         CloseServiceHandle (hService);
    1035         _tprintf(_T("Installation of service successful!\n"));
    1036     }
    1037 
    1038 cleanup:
    1039 
    1040     if (hSCManager != NULL)
    1041         CloseServiceHandle (hSCManager);
    1042 
    1043     return rc;
    1044 }
    1045 
    1046 int DelService(const TCHAR *pszStartStopName)
    1047 {
    1048     int rc = ERROR_SUCCESS;
    1049 
    1050     _tprintf(_T("Deleting service '%ws' ...\n"), pszStartStopName);
    1051 
    1052     SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    1053     SC_HANDLE hService = NULL;
    1054     if (hSCManager == NULL)
    1055     {
    1056         _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());
    1057         rc = EXIT_FAIL;
    1058     }
    1059     else
    1060     {
    1061         hService = OpenService(hSCManager, pszStartStopName, SERVICE_ALL_ACCESS);
    1062         if (NULL == hService)
    1063         {
    1064             _tprintf(_T("Could not open service '%ws'! Error: %ld\n"), pszStartStopName, GetLastError());
    1065             rc = EXIT_FAIL;
    1066         }
    1067     }
    1068 
    1069     if (hService != NULL)
    1070     {
    1071         SC_LOCK hSCLock = LockServiceDatabase(hSCManager);
    1072         if (hSCLock != NULL)
    1073         {
    1074             if (FALSE == DeleteService(hService))
    1075             {
    1076                 DWORD dwErr = GetLastError();
    1077                 switch (dwErr)
    1078                 {
    1079 
    1080                 case ERROR_SERVICE_MARKED_FOR_DELETE:
    1081 
    1082                     _tprintf(_T("Service '%ws' already marked for deletion.\n"), pszStartStopName);
    1083                     break;
    1084 
    1085                 default:
    1086 
    1087                     _tprintf(_T("Could not delete service '%ws'! Error: %ld\n"), pszStartStopName, GetLastError());
    1088                     rc = EXIT_FAIL;
    1089                     break;
    1090                 }
    1091             }
    1092             else
    1093             {
    1094                 _tprintf(_T("Service '%ws' successfully removed!\n"), pszStartStopName);
     1750                    rcExit = ErrorMsgLastErrSWS("Failed to delete service'", pwszService, "'!");
    10951751            }
    10961752            UnlockServiceDatabase(hSCLock);
    10971753        }
    10981754        else
     1755            ErrorMsgLastErr("LockServiceDatabase failed");
     1756        CloseServiceHandle(hService);
     1757    }
     1758    else
     1759        rcExit = ErrorMsgLastErrSWS("Failed to open service'", pwszService, "'!");
     1760    CloseServiceHandle(hSCManager);
     1761    return rcExit;
     1762}
     1763
     1764
     1765/** Handles 'service delete' */
     1766static int handleServiceDelete(unsigned cArgs, wchar_t **papwszArgs)
     1767{
     1768    RT_NOREF(cArgs);
     1769    return DelService(papwszArgs[0]);
     1770}
     1771
     1772
     1773static HKEY ArgToRegistryRoot(const wchar_t *pwszRoot)
     1774{
     1775    HKEY hRootKey = NULL;
     1776    if (RTUtf16ICmpAscii(pwszRoot, "hklm") == 0)
     1777        hRootKey = HKEY_LOCAL_MACHINE;
     1778    else if (RTUtf16ICmpAscii(pwszRoot, "hkcu") == 0)
     1779        hRootKey = HKEY_CURRENT_USER;
     1780    else if (RTUtf16ICmpAscii(pwszRoot, "hkcr") == 0)
     1781        hRootKey = HKEY_CLASSES_ROOT;
     1782    else if (RTUtf16ICmpAscii(pwszRoot, "hku") == 0)
     1783        hRootKey = HKEY_USERS;
     1784    else if (RTUtf16ICmpAscii(pwszRoot, "hkcc") == 0)
     1785        hRootKey = HKEY_CURRENT_CONFIG;
     1786    else
     1787        ErrorBadArg("root", pwszRoot, "hklm, hkcu, hkcr, hku or hkcc");
     1788    return hRootKey;
     1789}
     1790
     1791
     1792/**
     1793 * Handles 'registry write'.
     1794 */
     1795static int handleRegistryWrite(unsigned cArgs, wchar_t **papwszArgs)
     1796{
     1797    /*
     1798     * Mandatory parameters.
     1799     */
     1800    wchar_t const * const pwszRoot      = papwszArgs[0];
     1801    wchar_t const * const pwszSubKey    = papwszArgs[1];
     1802    wchar_t const * const pwszValueName = papwszArgs[2];
     1803    wchar_t const * const pwszType      = papwszArgs[3];
     1804    wchar_t const * const pwszValue     = papwszArgs[4];
     1805
     1806    /*
     1807     * Root key:
     1808     */
     1809    HKEY hRootKey = ArgToRegistryRoot(papwszArgs[0]);
     1810    if (hRootKey == NULL)
     1811        return EXIT_USAGE;
     1812
     1813    /*
     1814     * Type and value with default length.
     1815     */
     1816    union
     1817    {
     1818        uint32_t    dw;
     1819        uint64_t    qw;
     1820    } uValue;
     1821    DWORD           dwType;
     1822    DWORD           cbValue;
     1823    BYTE const     *pbValue;
     1824    if (   RTUtf16ICmpAscii(pwszType, "REG_BINARY") == 0
     1825        || RTUtf16ICmpAscii(pwszType, "REG_BIN") == 0
     1826        || RTUtf16ICmpAscii(pwszType, "BINARY") == 0)
     1827    {
     1828        dwType  = REG_BINARY;
     1829        cbValue = (DWORD)(RTUtf16Len(pwszValue) + 1) * sizeof(wchar_t);
     1830        pbValue = (BYTE const *)pwszValue;
     1831    }
     1832    else if (   RTUtf16ICmpAscii(pwszType, "REG_DWORD") == 0
     1833             || RTUtf16ICmpAscii(pwszType, "DWORD") == 0)
     1834    {
     1835        if (!ArgToUInt32Full(pwszValue, "dword value", &uValue.dw))
     1836            return EXIT_USAGE;
     1837        dwType  = REG_DWORD;
     1838        pbValue = (BYTE const *)&uValue.dw;
     1839        cbValue = sizeof(uValue.dw);
     1840    }
     1841    else if (   RTUtf16ICmpAscii(pwszType, "REG_QWORD") == 0
     1842             || RTUtf16ICmpAscii(pwszType, "QWORD") == 0)
     1843    {
     1844        if (!ArgToUInt64Full(pwszValue, "qword value", &uValue.qw))
     1845            return EXIT_USAGE;
     1846        dwType  = REG_QWORD;
     1847        pbValue = (BYTE const *)&uValue.qw;
     1848        cbValue = sizeof(uValue.qw);
     1849    }
     1850    else if (   RTUtf16ICmpAscii(pwszType, "REG_SZ") == 0
     1851             || RTUtf16ICmpAscii(pwszType, "SZ") == 0)
     1852    {
     1853        dwType  = REG_SZ;
     1854        cbValue = (DWORD)((RTUtf16Len(pwszValue) + 1) * sizeof(wchar_t));
     1855        pbValue = (BYTE const *)pwszValue;
     1856    }
     1857    else
     1858        return ErrorBadArg("type", pwszType, "");
     1859
     1860    /*
     1861     * Binary only: Reinterpret the input as - optional.
     1862     */
     1863    if (cArgs > 5)
     1864    {
     1865        if (dwType != REG_BINARY)
     1866            return ErrorMsg("The 'binary-conversion' argument is currently only supported for REG_BINARY type values!");
     1867        if (RTUtf16ICmpAscii(papwszArgs[5], "dword") == 0)
    10991868        {
    1100             _tprintf(_T("Unable to lock service database! Error: %ld\n"), GetLastError());
    1101             rc = EXIT_FAIL;
     1869            if (!ArgToUInt32Full(pwszValue, "dword(/binary) value", &uValue.dw))
     1870                return EXIT_USAGE;
     1871            pbValue = (BYTE const *)&uValue.dw;
     1872            cbValue = sizeof(uValue.dw);
    11021873        }
    1103         CloseServiceHandle(hService);
    1104     }
    1105 
    1106     if (hSCManager != NULL)
    1107         CloseServiceHandle(hSCManager);
    1108 
    1109     return rc;
    1110 }
    1111 
    1112 DWORD RegistryWrite(HKEY hRootKey,
    1113                     const _TCHAR *pszSubKey,
    1114                     const _TCHAR *pszValueName,
    1115                     DWORD dwType,
    1116                     const BYTE *pbData,
    1117                     DWORD cbData)
    1118 {
    1119     DWORD lRet;
    1120     HKEY hKey;
    1121     lRet = RegCreateKeyEx (hRootKey,
    1122                            pszSubKey,
    1123                            0,           /* Reserved */
    1124                            NULL,        /* lpClass [in, optional] */
    1125                            0,           /* dwOptions [in] */
    1126                            KEY_WRITE,
    1127                            NULL,        /* lpSecurityAttributes [in, optional] */
    1128                            &hKey,
    1129                            NULL);       /* lpdwDisposition [out, optional] */
    1130     if (lRet != ERROR_SUCCESS)
    1131     {
    1132         _tprintf(_T("Could not open registry key! Error: %ld\n"), GetLastError());
    1133     }
    1134     else
    1135     {
    1136         lRet = RegSetValueEx(hKey, pszValueName, 0, dwType, (BYTE*)pbData, cbData);
    1137         if (lRet != ERROR_SUCCESS)
    1138             _tprintf(_T("Could not write to registry! Error: %ld\n"), GetLastError());
     1874        else if (RTUtf16ICmpAscii(papwszArgs[5], "qword") == 0)
     1875        {
     1876            if (!ArgToUInt64Full(pwszValue, "qword(/binary) value", &uValue.qw))
     1877                return EXIT_USAGE;
     1878            pbValue = (BYTE const *)&uValue.qw;
     1879            cbValue = sizeof(uValue.qw);
     1880        }
     1881        else
     1882            return ErrorBadArg("binary-conversion", papwszArgs[0], "dword");
     1883    }
     1884
     1885    /*
     1886     * Binary only: Max length to write - optional.
     1887     */
     1888    if (cArgs> 6)
     1889    {
     1890        if (dwType != REG_BINARY)
     1891            return ErrorMsg("The 'max-size' argument is currently only supported for REG_BINARY type values!");
     1892        uint32_t cbMaxValue;
     1893        if (!ArgToUInt32Full(papwszArgs[6], "max-size", &cbMaxValue))
     1894            return EXIT_USAGE;
     1895        if (cbValue > cbMaxValue)
     1896            cbValue = cbMaxValue;
     1897    }
     1898
     1899    /*
     1900     * Do the writing.
     1901     */
     1902    HKEY    hKey = NULL;
     1903    LSTATUS lrc  = RegCreateKeyExW(hRootKey, pwszSubKey, 0 /*Reserved*/, NULL /*pwszClass*/, 0 /*dwOptions*/,
     1904                                   KEY_WRITE, NULL /*pSecAttr*/, &hKey, NULL /*pdwDisposition*/);
     1905    if (lrc != ERROR_SUCCESS)
     1906        return ErrorMsgLStatusSWSWSRS("RegCreateKeyExW ", pwszRoot, "/'", pwszSubKey, "' failed: ", lrc, NULL);
     1907
     1908    lrc = RegSetValueExW(hKey, pwszValueName, 0, dwType, pbValue, cbValue);
     1909    RegCloseKey(hKey);
     1910    if (lrc != ERROR_SUCCESS)
     1911        return ErrorMsgLStatusSWSWSWSRS("RegSetValueExW ", pwszRoot, "/'", pwszSubKey, "'/'",
     1912                                        pwszValueName, "' failed: ",  lrc, NULL);
     1913    return EXIT_OK;
     1914}
     1915
     1916
     1917/**
     1918 * Handles 'registry delete'.
     1919 */
     1920static int handleRegistryDelete(unsigned cArgs, wchar_t **papwszArgs)
     1921{
     1922    /*
     1923     * Parameters.
     1924     */
     1925    RT_NOREF(cArgs);
     1926    wchar_t const * const pwszRoot      = papwszArgs[0];
     1927    wchar_t const * const pwszSubKey    = papwszArgs[1];
     1928    wchar_t const * const pwszValueName = papwszArgs[2];
     1929
     1930    HKEY const hRootKey = ArgToRegistryRoot(pwszRoot);
     1931    if (hRootKey == NULL)
     1932        return EXIT_USAGE;
     1933
     1934    /*
     1935     * Do the deleting.
     1936     */
     1937    HKEY    hKey = NULL;
     1938    LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, papwszArgs[1] /*pwszSubKey*/, 0 /*dwOptions*/, KEY_READ | KEY_WRITE, &hKey);
     1939    if (lrc != ERROR_FILE_NOT_FOUND)
     1940    {
     1941        if (lrc != ERROR_SUCCESS)
     1942            return ErrorMsgLStatusSWSWSRS("RegOpenKeyExW ", pwszRoot, "/'", pwszSubKey, "' failed: ", lrc, NULL);
     1943
     1944        lrc = RegDeleteValueW(hKey, pwszValueName);
    11391945        RegCloseKey(hKey);
    1140 
    1141     }
    1142     return lRet;
    1143 }
    1144 
    1145 void PrintHelp(void)
    1146 {
    1147     _tprintf(_T("VirtualBox Guest Additions Installation Helper for Windows\n"));
    1148     _tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
    1149     _tprintf(_T("Syntax:\n"));
    1150     _tprintf(_T("\n"));
    1151     _tprintf(_T("Drivers:\n"));
    1152     _tprintf(_T("\tVBoxDrvInst         driver install <inf-file> [log file]\n"));
    1153     _tprintf(_T("\tVBoxDrvInst         driver uninstall <inf-file> [log file]\n"));
    1154     _tprintf(_T("\tVBoxDrvInst         driver executeinf <inf-file>\n"));
    1155     _tprintf(_T("\n"));
    1156     _tprintf(_T("Network Provider:\n"));
    1157     _tprintf(_T("\tVBoxDrvInst         netprovider add <name> [order]\n"));
    1158     _tprintf(_T("\tVBoxDrvInst         netprovider remove <name>\n"));
    1159     _tprintf(_T("\n"));
    1160     _tprintf(_T("Registry:\n"));
    1161     _tprintf(_T("\tVBoxDrvInst         registry write <root> <sub key>\n")
    1162              _T("\t                    <key name> <key type> <value>\n")
    1163              _T("\t                    [type] [size]\n"));
    1164     _tprintf(_T("\tVBoxDrvInst         registry addmultisz <root> <sub key>\n")
    1165              _T("\t                    <value> [order]\n"));
    1166     _tprintf(_T("\tVBoxDrvInst         registry delmultisz <root> <sub key>\n")
    1167              _T("\t                    <key name> <value to remove>\n"));
    1168     /** @todo Add "service" category! */
    1169     _tprintf(_T("\n"));
    1170 }
    1171 
    1172 int __cdecl _tmain(int argc, _TCHAR *argv[])
    1173 {
    1174     int rc = EXIT_USAGE;
    1175 
    1176     OSVERSIONINFO OSinfo;
    1177     OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
    1178     GetVersionEx(&OSinfo);
    1179 
     1946        if (lrc != ERROR_SUCCESS && lrc != ERROR_FILE_NOT_FOUND)
     1947            return ErrorMsgLStatusSWSWSWSRS("RegDeleteValueW ", pwszRoot, "/'", pwszSubKey, "'/'",
     1948                                            pwszValueName, "' failed: ",  lrc, NULL);
     1949    }
     1950    return EXIT_OK;
     1951}
     1952
     1953
     1954/** Handles 'version' and its aliases. */
     1955static int handleVersion(unsigned cArgs, wchar_t **papwszArgs)
     1956{
     1957    PrintStr(RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "r" RT_XSTR(VBOX_SVN_REV) "\r\n");
     1958    RT_NOREF(cArgs, papwszArgs);
     1959    return EXIT_OK;
     1960}
     1961
     1962
     1963/** Handles 'help' and all its aliases. */
     1964static int handleHelp(unsigned cArgs, wchar_t **papwszArgs)
     1965{
     1966    /*       "0         1         2         3         4         5         6         7         8 */
     1967    /*       "012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
     1968    PrintStr("VirtualBox Guest Additions Installation Helper for Windows\r\n"
     1969             "Version: " RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "r" RT_XSTR(VBOX_SVN_REV) "\r\n"
     1970             "\r\n"
     1971             "Syntax: VBoxDrvInst <command> <subcommand>\r\n"
     1972             "\r\n"
     1973             "Drivers:\r\n"
     1974             "    VBoxDrvInst driver install <inf-file> [log-file]\r\n"
     1975             "    VBoxDrvInst driver uninstall <inf-file> [log-file]\r\n"
     1976             "    VBoxDrvInst driver executeinf <inf-file>\r\n"
     1977             "\r\n"
     1978             "Service:\r\n"
     1979             "    VBoxDrvInst service create <name> <display-name> <service-type>\r\n"
     1980             "        <start-type> <binary-path> [load-order] [deps] [user] [password]\r\n"
     1981             "    VBoxDrvInst service delete <name>\r\n"
     1982             "\r\n"
     1983             "Network Provider:\r\n"
     1984             "    VBoxDrvInst netprovider add <name> <position>\r\n"
     1985             "    VBoxDrvInst netprovider remove <name>\r\n"
     1986             "\r\n"
     1987             "Registry:\r\n"
     1988             "    VBoxDrvInst registry write <root> <sub-key> <value-name> <type> <value>\r\n"
     1989             "        [binary-conversion] [max-size]\r\n"
     1990             "    VBoxDrvInst registry delete <root> <sub-key> <value-name>\r\n"
     1991             /** @todo Add roots for these two. */
     1992             "    VBoxDrvInst registry addmultisz <sub-key> <value-name> <to-add> <position>\r\n"
     1993             "    VBoxDrvInst registry delmultisz <sub-key> <value-name> <to-remove>\r\n"
     1994             "\r\n"
     1995             "Standard options:\r\n"
     1996             "    VBoxDrvInst [help|--help|/help|-h|/h|-?|/h] [...]\r\n"
     1997             "    VBoxDrvInst [version|--version|-V]\r\n"
     1998             );
     1999    RT_NOREF(cArgs, papwszArgs);
     2000    return EXIT_OK;
     2001}
     2002
     2003
     2004int wmain(int argc, wchar_t **argv)
     2005{
     2006    /* Not initializing IPRT here, ASSUMING the little bit we use of it does
     2007       not need any initialization.  Reduces the binary size a little. */
     2008
     2009    static struct
     2010    {
     2011        const char *pszCmd;
     2012        const char *pszSubCmd;
     2013        unsigned    cMin, cMax;
     2014        int       (*pfnHandler)(unsigned cArgs, wchar_t **papwszArgs);
     2015    } s_aActions[] =
     2016    {
     2017        { "driver",         "install",      1,  2, handleDriverInstall },
     2018        { "driver",         "uninstall",    1,  2, handleDriverUninstall },
     2019        { "driver",         "executeinf",   1,  1, handleDriverExecuteInf },
     2020        { "netprovider",    "add",          1,  2, handleNetProviderAdd },
     2021        { "netprovider",    "remove",       1,  2, handleNetProviderRemove },
     2022        { "service",        "create",       5,  9, handleServiceCreate },
     2023        { "service",        "delete",       1,  1, handleServiceDelete },
     2024        { "registry",       "addmultisz",   4,  4, handleRegistryAddMultiSz },
     2025        { "registry",       "delmultisz",   3,  3, handleRegistryDelMultiSz },
     2026        { "registry",       "write",        5,  7, handleRegistryWrite },
     2027        { "registry",       "delete",       3,  3, handleRegistryDelete },
     2028
     2029        { "help",           NULL,           0, ~0U, handleHelp },
     2030        { "--help",         NULL,           0, ~0U, handleHelp },
     2031        { "/help",          NULL,           0, ~0U, handleHelp },
     2032        { "-h",             NULL,           0, ~0U, handleHelp },
     2033        { "/h",             NULL,           0, ~0U, handleHelp },
     2034        { "-?",             NULL,           0, ~0U, handleHelp },
     2035        { "/?",             NULL,           0, ~0U, handleHelp },
     2036        { "version",        NULL,           0, ~0U, handleVersion },
     2037        { "--version",      NULL,           0, ~0U, handleVersion },
     2038        { "-V",             NULL,           0, ~0U, handleVersion },
     2039    };
     2040
     2041    /*
     2042     * Lookup the action handler.
     2043     */
     2044    int rcExit = EXIT_USAGE;
    11802045    if (argc >= 2)
    11812046    {
    1182         if (   !_tcsicmp(argv[1], _T("driver"))
    1183             && argc >= 3)
    1184         {
    1185             _TCHAR szINF[_MAX_PATH] = { 0 }; /* Complete path to INF file.*/
    1186             if (   (   !_tcsicmp(argv[2], _T("install"))
    1187                     || !_tcsicmp(argv[2], _T("uninstall")))
    1188                 && argc >= 4)
     2047        const wchar_t * const pwszCmd    = argv[1];
     2048        const wchar_t * const pwszSubCmd = argc > 2 ? argv[2] : NULL;
     2049        unsigned              i          = 0;
     2050        for (i = 0; i < RT_ELEMENTS(s_aActions); i++)
     2051            if (   RTUtf16ICmpAscii(pwszCmd, s_aActions[i].pszCmd) == 0
     2052                && (   !s_aActions[i].pszSubCmd
     2053                    || RTUtf16ICmpAscii(pwszSubCmd, s_aActions[i].pszSubCmd) == 0))
    11892054            {
    1190                 if (OSinfo.dwMajorVersion < 5)
    1191                 {
    1192                     _tprintf(_T("ERROR: Platform not supported for driver (un)installation!\n"));
    1193                     rc = EXIT_FAIL;
    1194                 }
     2055                unsigned   const cArgs      = (unsigned)argc - (s_aActions[i].pszSubCmd ? 3 : 2);
     2056                wchar_t ** const papwszArgs = &argv[s_aActions[i].pszSubCmd ? 3 : 2];
     2057                if (cArgs >= s_aActions[i].cMin && cArgs <= s_aActions[i].cMax)
     2058                    rcExit = s_aActions[i].pfnHandler(cArgs, papwszArgs);
    11952059                else
    11962060                {
    1197                     _sntprintf(szINF, sizeof(szINF) / sizeof(TCHAR), _T("%ws"), argv[3]);
    1198 
    1199                     _TCHAR szLogFile[_MAX_PATH] = { 0 };
    1200                     if (argc > 4)
    1201                         _sntprintf(szLogFile, sizeof(szLogFile) / sizeof(TCHAR), _T("%ws"), argv[4]);
    1202                     rc = VBoxInstallDriver(!_tcsicmp(argv[2], _T("install")) ? TRUE : FALSE, szINF,
    1203                                            FALSE /* Not silent */, szLogFile[0] != NULL ? szLogFile : NULL);
     2061                    bool const fTooFew = cArgs < s_aActions[i].cMin;
     2062                    ErrorMsgBegin(fTooFew ? "Too few parameters for '" : "Too many parameters for '");
     2063                    ErrorMsgStr(s_aActions[i].pszCmd);
     2064                    if (s_aActions[i].pszSubCmd)
     2065                    {
     2066                        ErrorMsgStr(" ");
     2067                        ErrorMsgStr(s_aActions[i].pszSubCmd);
     2068                    }
     2069                    ErrorMsgStr("'! Got ");
     2070                    ErrorMsgU64(cArgs);
     2071                    ErrorMsgStr(fTooFew ? ", expected at least " : ", expected at most ");;
     2072                    ErrorMsgU64(fTooFew ? s_aActions[i].cMin : s_aActions[i].cMax);
     2073                    ErrorMsgEnd(".");
    12042074                }
     2075                break;
    12052076            }
    1206             else if (   !_tcsicmp(argv[2], _T("executeinf"))
    1207                      && argc == 4)
     2077        if (i >= RT_ELEMENTS(s_aActions))
     2078        {
     2079            ErrorMsgBegin("Unknown action '");
     2080            ErrorMsgWStr(pwszCmd);
     2081            if (pwszSubCmd)
    12082082            {
    1209                 _sntprintf(szINF, sizeof(szINF) / sizeof(TCHAR), _T("%ws"), argv[3]);
    1210                 rc = ExecuteInfFile(_T("DefaultInstall"), 132, szINF);
     2083                ErrorMsgBegin(" ");
     2084                ErrorMsgWStr(pwszSubCmd);
    12112085            }
     2086            ErrorMsgEnd("'! Please consult \"--help\" for more information.\r\n");
    12122087        }
    1213         else if (   !_tcsicmp(argv[1], _T("netprovider"))
    1214                  && argc >= 3)
    1215         {
    1216             _TCHAR szProvider[_MAX_PATH] = { 0 }; /* The network provider name for the registry. */
    1217             if (  !_tcsicmp(argv[2], _T("add"))
    1218                 && argc >= 4)
    1219             {
    1220                 int iOrder = 0;
    1221                 if (argc > 4)
    1222                     iOrder = _ttoi(argv[4]);
    1223                 _sntprintf(szProvider, sizeof(szProvider) / sizeof(TCHAR), _T("%ws"), argv[3]);
    1224                 rc = AddNetworkProvider(szProvider, iOrder);
    1225             }
    1226             else if (  !_tcsicmp(argv[2], _T("remove"))
    1227                 && argc >= 4)
    1228             {
    1229                 _sntprintf(szProvider, sizeof(szProvider) / sizeof(TCHAR), _T("%ws"), argv[3]);
    1230                 rc = RemoveNetworkProvider(szProvider);
    1231             }
    1232         }
    1233         else if (   !_tcsicmp(argv[1], _T("service"))
    1234                  && argc >= 3)
    1235         {
    1236             if (   !_tcsicmp(argv[2], _T("create"))
    1237                 && argc >= 8)
    1238             {
    1239                 rc = CreateService(argv[3],
    1240                                    argv[4],
    1241                                    _ttoi(argv[5]),
    1242                                    _ttoi(argv[6]),
    1243                                    argv[7],
    1244                                    (argc > 8) ? argv[8] : NULL,
    1245                                    (argc > 9) ? argv[9] : NULL,
    1246                                    (argc > 10) ? argv[10] : NULL,
    1247                                    (argc > 11) ? argv[11] : NULL);
    1248             }
    1249             else if (   !_tcsicmp(argv[2], _T("delete"))
    1250                      && argc == 4)
    1251             {
    1252                 rc = DelService(argv[3]);
    1253             }
    1254         }
    1255         else if (   !_tcsicmp(argv[1], _T("registry"))
    1256                  && argc >= 3)
    1257         {
    1258             /** @todo add a handleRegistry(argc, argv) method to keep things cleaner */
    1259             if (   !_tcsicmp(argv[2], _T("addmultisz"))
    1260                 && argc == 7)
    1261             {
    1262                 rc = RegistryAddStringToMultiSZ(argv[3], argv[4], argv[5], _ttoi(argv[6]));
    1263             }
    1264             else if (   !_tcsicmp(argv[2], _T("delmultisz"))
    1265                      && argc == 6)
    1266             {
    1267                 rc = RegistryRemoveStringFromMultiSZ(argv[3], argv[4], argv[5]);
    1268             }
    1269             else if (   !_tcsicmp(argv[2], _T("write"))
    1270                      && argc >= 8)
    1271             {
    1272                 HKEY hRootKey = HKEY_LOCAL_MACHINE;  /** @todo needs to be expanded (argv[3]) */
    1273                 DWORD dwValSize = 0;
    1274                 BYTE *pbVal = NULL;
    1275                 DWORD dwVal;
    1276 
    1277                 if (argc > 8)
    1278                 {
    1279                     if (!_tcsicmp(argv[8], _T("dword")))
    1280                     {
    1281                         dwVal = _ttol(argv[7]);
    1282                         pbVal = (BYTE*)&dwVal;
    1283                         dwValSize = sizeof(DWORD);
    1284                     }
    1285                 }
    1286                 if (pbVal == NULL) /* By default interpret value as string */
    1287                 {
    1288                     pbVal = (BYTE *)argv[7];
    1289                     dwValSize = (DWORD)_tcslen(argv[7]);
    1290                 }
    1291                 if (argc > 9)
    1292                     dwValSize = _ttol(argv[9]);      /* Get the size in bytes of the value we want to write */
    1293                 rc = RegistryWrite(hRootKey,
    1294                                    argv[4],          /* Sub key */
    1295                                    argv[5],          /* Value name */
    1296                                    REG_BINARY,       /** @todo needs to be expanded (argv[6]) */
    1297                                    pbVal,            /* The value itself */
    1298                                    dwValSize);       /* Size of the value */
    1299             }
    1300 #if 0
    1301             else if (!_tcsicmp(argv[2], _T("read")))
    1302             {
    1303             }
    1304             else if (!_tcsicmp(argv[2], _T("del")))
    1305             {
    1306             }
     2088    }
     2089    else
     2090        ErrorMsg("No parameters given. Please consult \"--help\" for more information.\r\n");
     2091    return rcExit;
     2092}
     2093
     2094
     2095#ifdef IPRT_NO_CRT
     2096int main(int argc, char **argv)
     2097{
     2098    /*
     2099     * Convert the arguments to UTF16 and call wmain.  We don't bother freeing
     2100     * any of these strings as the process is exiting and it's a waste of time.
     2101     */
     2102    wchar_t **papwszArgs = (wchar_t **)alloca((argc + 1) * sizeof(wchar_t *));
     2103    int i = 0;
     2104    while (i < argc)
     2105    {
     2106        papwszArgs[i] = NULL;
     2107        int rc = RTStrToUtf16(argv[i], &papwszArgs[i]);
     2108        if (RT_SUCCESS(rc))
     2109            i++;
     2110        else
     2111            return ErrorMsg("Failed to convert command line arguments to UTF16!!");
     2112    }
     2113    papwszArgs[i] = NULL;
     2114    return wmain(argc, papwszArgs);
     2115}
    13072116#endif
    1308         }
    1309         else if (!_tcsicmp(argv[1], _T("--version")))
    1310         {
    1311             _tprintf(_T("%d.%d.%d.%d\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
    1312             rc = EXIT_OK;
    1313         }
    1314         else if (   !_tcsicmp(argv[1], _T("--help"))
    1315                  || !_tcsicmp(argv[1], _T("/help"))
    1316                  || !_tcsicmp(argv[1], _T("/h"))
    1317                  || !_tcsicmp(argv[1], _T("/?")))
    1318         {
    1319             PrintHelp();
    1320             rc = EXIT_OK;
    1321         }
    1322     }
    1323 
    1324     if (rc == EXIT_USAGE)
    1325         _tprintf(_T("No or wrong parameters given! Please consult the help (\"--help\" or \"/?\") for more information.\n"));
    1326 
    1327     return rc;
    1328 }
    1329 
     2117
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