VirtualBox

Changeset 35649 in vbox


Ignore:
Timestamp:
Jan 20, 2011 1:45:52 PM (14 years ago)
Author:
vboxsync
Message:

VBoxDrvInst: Now dynamically uses the DIFx API for (un)installing drivers, lot of clean up, some documentation.

File:
1 edited

Legend:

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

    r34544 r35649  
    1 /*++
    2 
    3  Copyright (c) Microsoft Corporation.  All rights reserved.
    4 
    5  Module Name:
    6 
    7  VBoxDrvInst.cpp
    8 
    9  Abstract:
    10 
    11  Command-line interface for installing / uninstalling device drivers
    12  with a given Hardware-ID (and .INF-file).
    13 
    14  --*/
     1/* $Id$ */
     2/** @file
     3 * VBoxDrvInst - Driver and service installation helper for Windows guests.
     4 */
     5
     6/*
     7 * Copyright (C) 2011 Oracle Corporation
     8 *
     9 * This file is part of VirtualBox Open Source Edition (OSE), as
     10 * available from http://www.virtualbox.org. This file is free software;
     11 * you can redistribute it and/or modify it under the terms of the GNU
     12 * General Public License (GPL) as published by the Free Software
     13 * Foundation, in version 2 as it comes in the "COPYING" file of the
     14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
     15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
     16 */
     17
     18
     19/*******************************************************************************
     20*   Header Files                                                               *
     21*******************************************************************************/
    1522
    1623#ifndef UNICODE
     
    2229#include <windows.h>
    2330#include <setupapi.h>
    24 #include <newdev.h>
    25 #include <regstr.h>
    26 #include <cfgmgr32.h>
    27 #include <devguid.h>
    2831#include <stdio.h>
    2932#include <tchar.h>
    30 #include <string.h>
    31 
    32 /*#define _DEBUG*/
    33 
    34 typedef int (*fnCallback) (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context);
    35 
    36 struct IdEntry
    37 {
    38     LPCTSTR szString; /* string looking for */
    39     LPCTSTR szWild; /* first wild character if any */
    40     BOOL bInstanceId;
    41 };
    42 
    43 #define INSTANCEID_PREFIX_CHAR TEXT('@')    /* character used to prefix instance ID's */
    44 #define CLASS_PREFIX_CHAR      TEXT('=')    /* character used to prefix class name */
    45 #define WILD_CHAR              TEXT('*')    /* wild character */
    46 #define QUOTE_PREFIX_CHAR      TEXT('\'')   /* prefix character to ignore wild characters */
    47 #define SPLIT_COMMAND_SEP      TEXT(":=")   /* whole word, indicates end of id's */
    48 
    49 /* @todo Split this program into several modules:
    50 
    51  - Main
    52  - Utility functions
    53  - Dynamic API loading
    54  - Installation / uninstallation routines
    55  - ...
    56  */
     33
     34/*******************************************************************************
     35*   Defines                                                                    *
     36*******************************************************************************/
    5737
    5838/* Exit codes */
     
    6141#define EXIT_FAIL    (2)
    6242#define EXIT_USAGE   (3)
    63 #ifdef VBOX_WITH_WDDM
    64 #define EXIT_FALSE   (4)
     43
     44/* Prototypes */
     45typedef struct {
     46  PWSTR pApplicationId;
     47  PWSTR pDisplayName;
     48  PWSTR pProductName;
     49  PWSTR pMfgName;
     50} INSTALLERINFO, *PINSTALLERINFO;
     51typedef const PINSTALLERINFO PCINSTALLERINFO;
     52
     53typedef enum {
     54  DIFXAPI_SUCCESS,
     55  DIFXAPI_INFO,
     56  DIFXAPI_WARNING,
     57  DIFXAPI_ERROR
     58} DIFXAPI_LOG;
     59
     60typedef void (WINAPI * DIFXLOGCALLBACK_W)( DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);
     61typedef void ( __cdecl* DIFXAPILOGCALLBACK_W)( DIFXAPI_LOG Event, DWORD Error, PCWSTR EventDescription, PVOID CallbackContext);
     62
     63typedef DWORD (WINAPI *fnDriverPackageInstall) (PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);
     64fnDriverPackageInstall g_pfnDriverPackageInstall = NULL;
     65
     66typedef DWORD (WINAPI *fnDriverPackageUninstall) (PCTSTR DriverPackageInfPath, DWORD Flags, PCINSTALLERINFO pInstallerInfo, BOOL *pNeedReboot);
     67fnDriverPackageUninstall g_pfnDriverPackageUninstall = NULL;
     68
     69typedef VOID (WINAPI *fnDIFXAPISetLogCallback) (DIFXAPILOGCALLBACK_W LogCallback, PVOID CallbackContext);
     70fnDIFXAPISetLogCallback g_pfnDIFXAPISetLogCallback = NULL;
     71
     72/* Defines */
     73#define DRIVER_PACKAGE_REPAIR                 0x00000001
     74#define DRIVER_PACKAGE_SILENT                 0x00000002
     75#define DRIVER_PACKAGE_FORCE                  0x00000004
     76#define DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT 0x00000008
     77#define DRIVER_PACKAGE_LEGACY_MODE            0x00000010
     78#define DRIVER_PACKAGE_DELETE_FILES           0x00000020
     79
     80/* DIFx error codes */
     81#define ERROR_DEPENDENT_APPLICATIONS_EXIST \
     82    (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x300)
     83#define ERROR_DRIVER_STORE_ADD_FAILED \
     84    (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x0247L)
     85#define ERROR_DRIVER_PACKAGE_NOT_IN_STORE \
     86    (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR|0x302)
     87
     88/* Registry string list flags */
     89#define VBOX_REG_STRINGLIST_NONE              0x00000000        /* No flags set. */
     90#define VBOX_REG_STRINGLIST_ALLOW_DUPLICATES  0x00000001        /* Allows duplicates in list when adding a value. */
     91
     92#ifdef DEBUG
     93    #define VBOX_DRVINST_LOGFILE              "C:\\Temp\\VBoxDrvInstDIFx.log"
    6594#endif
    6695
    67 /* Dynamic loaded libs */
    68 HMODULE g_hSetupAPI = NULL;
    69 HMODULE g_hNewDev = NULL;
    70 HMODULE g_hCfgMgr = NULL;
    71 
    72 /* Function pointers for dynamic loading of some API calls NT4 hasn't ... */
    73 typedef BOOL (WINAPI *fnSetupDiCreateDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceName, LPGUID ClassGuid, PCTSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
    74                                                   PSP_DEVINFO_DATA DeviceInfoData);
    75 fnSetupDiCreateDeviceInfo g_pfnSetupDiCreateDeviceInfo = NULL;
    76 
    77 typedef BOOL (WINAPI *fnSetupDiOpenDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceInstanceId, HWND hwndParent, DWORD OpenFlags, PSP_DEVINFO_DATA DeviceInfoData);
    78 fnSetupDiOpenDeviceInfo g_pfnSetupDiOpenDeviceInfo = NULL;
    79 
    80 typedef BOOL (WINAPI *fnSetupDiEnumDeviceInfo) (HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData);
    81 fnSetupDiEnumDeviceInfo g_pfnSetupDiEnumDeviceInfo = NULL;
    82 
    83 /***/
    84 
    85 typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoList) (LPGUID ClassGuid, HWND hwndParent);
    86 fnSetupDiCreateDeviceInfoList g_pfnSetupDiCreateDeviceInfoList = NULL;
    87 
    88 typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoListEx) (LPGUID ClassGuid, HWND hwndParent, PCTSTR MachineName, PVOID Reserved);
    89 fnSetupDiCreateDeviceInfoListEx g_pfnSetupDiCreateDeviceInfoListEx = NULL;
    90 
    91 typedef BOOL (WINAPI *fnSetupDiDestroyDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
    92 fnSetupDiDestroyDriverInfoList g_pfnSetupDiDestroyDriverInfoList = NULL;
    93 
    94 typedef BOOL (WINAPI *fnSetupDiDestroyDeviceInfoList) (HDEVINFO DeviceInfoSet);
    95 fnSetupDiDestroyDeviceInfoList g_pfnSetupDiDestroyDeviceInfoList = NULL;
    96 
    97 typedef BOOL (WINAPI *fnSetupDiGetDeviceInfoListDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData);
    98 fnSetupDiGetDeviceInfoListDetail g_pfnSetupDiGetDeviceInfoListDetail = NULL;
    99 
    100 /***/
    101 
    102 typedef BOOL (WINAPI *fnSetupDiSetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, CONST BYTE *PropertyBuffer, DWORD PropertyBufferSize);
    103 fnSetupDiSetDeviceRegistryProperty g_pfnSetupDiSetDeviceRegistryProperty = NULL;
    104 
    105 typedef BOOL (WINAPI *fnSetupDiGetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer,
    106                                                            DWORD PropertyBufferSize, PDWORD RequiredSize);
    107 fnSetupDiGetDeviceRegistryProperty g_pfnSetupDiGetDeviceRegistryProperty = NULL;
    108 
    109 /***/
    110 
    111 typedef BOOL (WINAPI *fnSetupDiCallClassInstaller) (DI_FUNCTION InstallFunction, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData);
    112 fnSetupDiCallClassInstaller g_pfnSetupDiCallClassInstaller = NULL;
    113 
    114 typedef BOOL (WINAPI *fnSetupDiClassGuidsFromNameEx) (PCTSTR ClassName, LPGUID ClassGuidList, DWORD ClassGuidListSize, PDWORD RequiredSize, PCTSTR MachineName, PVOID Reserved);
    115 fnSetupDiClassGuidsFromNameEx g_pfnSetupDiClassGuidsFromNameEx = NULL;
    116 
    117 typedef HDEVINFO (WINAPI *fnSetupDiGetClassDevsEx) (LPGUID ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags, HDEVINFO DeviceInfoSet, PCTSTR MachineName, PVOID Reserved);
    118 fnSetupDiGetClassDevsEx g_pfnSetupDiGetClassDevsEx = NULL;
    119 
    120 typedef BOOL (WINAPI *fnSetupDiSetClassInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_CLASSINSTALL_HEADER ClassInstallParams, DWORD ClassInstallParamsSize);
    121 fnSetupDiSetClassInstallParams g_pfnSetupDiSetClassInstallParams = NULL;
    122 
    123 typedef BOOL (WINAPI *fnSetupDiGetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
    124 fnSetupDiGetDeviceInstallParams g_pfnSetupDiGetDeviceInstallParams = NULL;
    125 
    126 typedef HKEY (WINAPI *fnSetupDiOpenDevRegKey) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired);
    127 fnSetupDiOpenDevRegKey g_pfnSetupDiOpenDevRegKey = NULL;
    128 
    129 typedef BOOL (WINAPI *fnSetupDiBuildDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
    130 fnSetupDiBuildDriverInfoList g_pfnSetupDiBuildDriverInfoList = NULL;
    131 
    132 typedef BOOL (WINAPI *fnSetupDiEnumDriverInfo) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType, DWORD MemberIndex, PSP_DRVINFO_DATA DriverInfoData);
    133 fnSetupDiEnumDriverInfo g_pfnSetupDiEnumDriverInfo = NULL;
    134 
    135 typedef BOOL (WINAPI *fnSetupDiGetDriverInfoDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData, PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
    136                                                      DWORD DriverInfoDetailDataSize, PDWORD RequiredSize);
    137 fnSetupDiGetDriverInfoDetail g_pfnSetupDiGetDriverInfoDetail = NULL;
    138 
    139 typedef BOOL (WINAPI *fnSetupDiSetSelectedDriver) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData);
    140 fnSetupDiSetSelectedDriver g_pfnSetupDiSetSelectedDriver = NULL;
    141 
    142 typedef BOOL (WINAPI *fnSetupDiSetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
    143 fnSetupDiSetDeviceInstallParams g_pfnSetupDiSetDeviceInstallParams = NULL;
    144 
    145 typedef CONFIGRET (WINAPI *fnCM_Get_Device_ID_Ex) (DEVINST dnDevInst, PTCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine);
    146 fnCM_Get_Device_ID_Ex g_pfnCM_Get_Device_ID_Ex = NULL;
    147 
    148 typedef BOOL (WINAPI* fnSetupCopyOEMInf) (PCTSTR SourceInfFileName, PCTSTR OEMSourceMediaLocation, DWORD OEMSourceMediaType, DWORD CopyStyle, PTSTR DestinationInfFileName,
    149                                           DWORD DestinationInfFileNameSize, PDWORD RequiredSize, PTSTR DestinationInfFileNameComponent);
    150 fnSetupCopyOEMInf g_pfnSetupCopyOEMInf = NULL;
    151 
    152 typedef BOOL (WINAPI* fnUpdateDriverForPlugAndPlayDevices) (HWND hwndParent, LPCTSTR HardwareId, LPCTSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
    153 fnUpdateDriverForPlugAndPlayDevices g_pfnUpdateDriverForPlugAndPlayDevices = NULL;
    154 
    155 #define VBOX_LOAD_API( a_hModule, a_Func )                                 \
    156 {                                                                          \
    157     g_pfn##a_Func = (fn##a_Func)GetProcAddress(a_hModule, "##a_Func");     \
    158     _tprintf (_T("API call ##a_Func loaded: %p\n"), g_pfn##a_Func);  \
    159 }
    160 
    161 int LoadAPICalls ()
    162 {
    163     int rc = ERROR_SUCCESS;
    164     OSVERSIONINFO OSinfo;
    165     OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
    166     GetVersionEx(&OSinfo);
    167 
    168 #ifdef _DEBUG
    169     _tprintf (_T("Loading API calls ...\n"));
    170 #endif
    171 
    172     /* Use unicode calls where available. */
    173     if (OSinfo.dwMajorVersion >= 5) /* APIs available only on W2K and up! */
    174     {
    175         g_hSetupAPI = LoadLibrary(_T("SetupAPI"));
    176         if (NULL == g_hSetupAPI)
    177         {
    178             _tprintf(_T("ERROR: SetupAPI.dll not found! Return code: %d\n"), GetLastError());
    179             rc = ERROR_NOT_INSTALLED;
    180         }
    181         else
    182         {
    183             g_pfnSetupDiCreateDeviceInfoList = (fnSetupDiCreateDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoList");
    184             g_pfnSetupDiCreateDeviceInfo = (fnSetupDiCreateDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoW");
    185             g_pfnSetupDiSetDeviceRegistryProperty = (fnSetupDiSetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceRegistryPropertyW");
    186             g_pfnSetupDiCallClassInstaller = (fnSetupDiCallClassInstaller)GetProcAddress(g_hSetupAPI, "SetupDiCallClassInstaller");
    187             g_pfnSetupDiDestroyDeviceInfoList = (fnSetupDiDestroyDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDeviceInfoList");
    188             g_pfnSetupDiClassGuidsFromNameEx = (fnSetupDiClassGuidsFromNameEx)GetProcAddress(g_hSetupAPI, "SetupDiClassGuidsFromNameExW");
    189             g_pfnSetupDiGetDeviceRegistryProperty = (fnSetupDiGetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceRegistryPropertyW");
    190             g_pfnSetupDiGetClassDevsEx = (fnSetupDiGetClassDevsEx)GetProcAddress(g_hSetupAPI, "SetupDiGetClassDevsExW");
    191             g_pfnSetupDiCreateDeviceInfoListEx = (fnSetupDiCreateDeviceInfoListEx)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoListExW");
    192             g_pfnSetupDiOpenDeviceInfo = (fnSetupDiOpenDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiOpenDeviceInfoW");
    193             g_pfnSetupDiGetDeviceInfoListDetail = (fnSetupDiGetDeviceInfoListDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInfoListDetailW");
    194             g_pfnSetupDiEnumDeviceInfo = (fnSetupDiEnumDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDeviceInfo");
    195             g_pfnSetupDiSetClassInstallParams = (fnSetupDiSetClassInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetClassInstallParamsW");
    196             g_pfnSetupDiGetDeviceInstallParams = (fnSetupDiGetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInstallParamsW");
    197             g_pfnSetupDiOpenDevRegKey = (fnSetupDiOpenDevRegKey)GetProcAddress(g_hSetupAPI, "SetupDiOpenDevRegKey");
    198             g_pfnSetupDiBuildDriverInfoList = (fnSetupDiBuildDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiBuildDriverInfoList");
    199             g_pfnSetupDiEnumDriverInfo = (fnSetupDiEnumDriverInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDriverInfoW");
    200             g_pfnSetupDiGetDriverInfoDetail = (fnSetupDiGetDriverInfoDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDriverInfoDetailW");
    201             g_pfnSetupDiDestroyDriverInfoList = (fnSetupDiDestroyDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDriverInfoList");
    202             g_pfnSetupDiSetSelectedDriver = (fnSetupDiSetSelectedDriver)GetProcAddress(g_hSetupAPI, "SetupDiSetSelectedDriverW");
    203             g_pfnSetupDiSetDeviceInstallParams = (fnSetupDiSetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceInstallParamsW");
    204             g_pfnSetupCopyOEMInf = (fnSetupCopyOEMInf)GetProcAddress(g_hSetupAPI, "SetupCopyOEMInfW");
    205         }
    206 
    207         if (rc == ERROR_SUCCESS)
    208         {
    209             g_hNewDev = LoadLibrary(_T("NewDev"));
    210             if (NULL != g_hNewDev)
    211             {
    212                 g_pfnUpdateDriverForPlugAndPlayDevices = (fnUpdateDriverForPlugAndPlayDevices)GetProcAddress(g_hNewDev, "UpdateDriverForPlugAndPlayDevicesW");
    213             }
    214             else
    215             {
    216                 _tprintf(_T("ERROR: NewDev.dll not found! Return code: %d\n"), GetLastError());
    217                 rc = ERROR_FILE_NOT_FOUND;
    218             }
    219         }
    220 
    221         if (rc == ERROR_SUCCESS)
    222         {
    223             g_hCfgMgr = LoadLibrary(_T("CfgMgr32"));
    224             if (NULL != g_hCfgMgr)
    225             {
    226                 g_pfnCM_Get_Device_ID_Ex = (fnCM_Get_Device_ID_Ex)GetProcAddress(g_hCfgMgr, "CM_Get_Device_ID_ExW");
    227             }
    228             else
    229             {
    230                 _tprintf(_T("ERROR: NewDev.dll not found! Return code: %d\n"), GetLastError());
    231                 rc = ERROR_FILE_NOT_FOUND;
    232             }
    233         }
    234     }
    235     else if (OSinfo.dwMajorVersion <= 4) /* Windows NT 4.0. */
    236     {
    237         /* Nothing to do here yet. */
    238     }
    239     else /* Other platforms */
    240     {
    241         _tprintf(_T("ERROR: Platform not supported yet!\n"));
    242         rc = ERROR_NOT_SUPPORTED;
    243     }
    244 
    245     return rc;
    246 }
    247 
    248 void FreeAPICalls ()
    249 {
    250 #ifdef _DEBUG
    251     _tprintf (_T("Freeing API calls ...\n"));
    252 #endif
    253 
    254     if (NULL != g_hSetupAPI)
    255         FreeLibrary(g_hSetupAPI);
    256 
    257     if (NULL != g_hNewDev)
    258         FreeLibrary(g_hNewDev);
    259 
    260     if (NULL != g_hCfgMgr)
    261         FreeLibrary(g_hCfgMgr);
    262 }
    263 
    264 bool GetErrorMsg (DWORD a_dwLastError, _TCHAR* a_pszMsg, DWORD a_dwBufSize)
    265 {
    266     if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_dwLastError, 0, a_pszMsg, a_dwBufSize / sizeof(TCHAR), NULL) == 0)
    267     {
    268         _stprintf(a_pszMsg, _T("Unknown error!\n"), a_dwLastError);
     96bool GetErrorMsg(DWORD dwLastError, _TCHAR *pszMsg, DWORD dwBufSize)
     97{
     98    if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, pszMsg, dwBufSize / sizeof(TCHAR), NULL) == 0)
     99    {
     100        _stprintf(pszMsg, _T("Unknown error!\n"), dwLastError);
    269101        return false;
    270102    }
    271103    else
    272104    {
    273         _TCHAR* p = _tcschr(a_pszMsg, _T('\r'));
     105        _TCHAR *p = _tcschr(pszMsg, _T('\r'));
    274106
    275107        if (p != NULL)
     
    280112}
    281113
    282 /* @todo Add exception handling instead of crappy goto's! */
    283 
    284 int CreateDevice (_TCHAR* a_pszHwID, GUID a_devClass)
    285 {
    286     int iRet = EXIT_OK;
    287     HDEVINFO devInfoSet;
    288     SP_DEVINFO_DATA devInfoData;
    289     DWORD dwErr = 0;
    290     _TCHAR szErrMsg[_MAX_PATH + 1] = { 0 };
    291 
    292     _tprintf(_T("Creating device ...\n"));
    293 
    294     devInfoSet = g_pfnSetupDiCreateDeviceInfoList(&a_devClass, NULL);
    295     if (devInfoSet == INVALID_HANDLE_VALUE)
    296     {
    297         _tprintf(_T("Could not build device info list!\n"));
    298         return EXIT_FAIL;
    299     }
    300 
    301     devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    302     if (FALSE == g_pfnSetupDiCreateDeviceInfo(devInfoSet, a_pszHwID, &a_devClass, NULL, NULL, DICD_GENERATE_ID, &devInfoData))
    303     {
    304         dwErr = GetLastError();
    305 
    306         switch (dwErr)
    307         {
    308 
    309         case ERROR_DEVINST_ALREADY_EXISTS:
    310 
    311             _tprintf(_T("Device already exists.\n"));
    312             break;
    313 
    314         case ERROR_CLASS_MISMATCH:
    315 
    316             _tprintf(_T("ERROR: Device does not match to class ID!\n"));
    317             break;
    318 
    319         case ERROR_INVALID_USER_BUFFER:
    320 
    321             _tprintf(_T("ERROR: Invalid user buffer!\n"));
    322             break;
    323 
    324         case ERROR_INVALID_DEVINST_NAME:
    325 
    326             _tprintf(_T("ERROR: Invalid device instance name!\n"));
    327             break;
    328 
    329         default:
    330 
    331             GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
    332             _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
    333             break;
    334         }
    335 
    336         iRet = EXIT_FAIL;
    337         goto InstallCleanup;
    338     }
    339 
    340     if (FALSE == g_pfnSetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID, (LPBYTE)a_pszHwID, (DWORD)((_tcsclen(a_pszHwID) + 2) * sizeof(_TCHAR))))
    341     {
    342         dwErr = GetLastError();
    343         _tprintf(_T("Could not set device registry info!\n"));
    344         iRet = EXIT_FAIL;
    345         goto InstallCleanup;
    346     }
    347 
    348     if (FALSE == g_pfnSetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))
    349     {
    350         dwErr = GetLastError();
    351         _tprintf(_T("Could not register device!\n"));
    352         iRet = EXIT_FAIL;
    353         goto InstallCleanup;
    354     }
    355 
    356     InstallCleanup: g_pfnSetupDiDestroyDeviceInfoList(devInfoSet);
    357 
    358     return iRet;
    359 }
    360 
    361 int InstallDriver (_TCHAR* a_pszInfFile, _TCHAR* a_pszHwID, _TCHAR* a_pszDevClass)
    362 {
    363     int rc = EXIT_OK; /** @todo Use IPRT values! */
    364 
    365     DWORD dwErr = 0;
    366     BOOL bReboot = FALSE;
    367 
    368     _TCHAR szInf[_MAX_PATH] = { 0 }; /* Full path + .INF file */
    369     _TCHAR szInfPath[_MAX_PATH] = { 0 }; /* Full path to .INF file */
    370     GUID devClassArr[32]; /* The device class GUID  array */
    371     DWORD dwReqSize = 0; /* Number of GUIDs in array after lookup */
    372 
    373     _tprintf(_T("Installing driver ...\n"));
    374     _tprintf(_T("HardwareID: %ws\n"), a_pszHwID);
    375     _tprintf(_T("Device class name: %ws\n"), a_pszDevClass);
    376 
    377     /* Retrieve GUID of device class */
    378     /* Not used here: g_pfnSetupDiClassNameFromGuidEx( ... ) */
    379     if (FALSE == g_pfnSetupDiClassGuidsFromNameEx(a_pszDevClass, devClassArr, 32, &dwReqSize, NULL, NULL))
    380     {
    381         _tprintf(_T("Could not retrieve device class GUID! Error: %ld\n"), GetLastError());
    382         rc = EXIT_FAIL;
    383     }
     114/**
     115 * Log callback for DIFxAPI calls.
     116 *
     117 * @param   Event                   The event's structure to log.
     118 * @param   dwError                 The event's error level.
     119 * @param   pEventDescription       The event's text description.
     120 * @param   pCallbackContext        User-supplied callback context.
     121 */
     122void LogCallback(DIFXAPI_LOG Event, DWORD dwError, PCWSTR pEventDescription, PVOID pCallbackContext)
     123{
     124#ifdef DEBUG
     125    if (dwError == 0)
     126        _tprintf(_T("(%u) %ws\n"), Event, pEventDescription);
    384127    else
    385     {
    386         /* Do not fail if dwReqSize is 0. For whatever reason Windows Server 2008 Core does not have the "Media"
    387            device class installed. Maybe they stripped down too much? :-/ */
    388         if (dwReqSize <= 0)
    389         {
    390             _tprintf(_T("WARNING: No device class with this name found! ReqSize: %ld, Error: %ld\n"), dwReqSize, GetLastError());
     128        _tprintf(_T("(%u) ERROR: %u - %ws\n"), Event, dwError, pEventDescription);
     129#else
     130    if (dwError > 0)
     131        _tprintf(_T("ERROR: (%u) %u - %ws\n"), Event, dwError, pEventDescription);
     132#endif
     133
     134     if (pCallbackContext)
     135         fwprintf((FILE*)pCallbackContext, _T("(%u) %u - %s\n"), Event, dwError, pEventDescription);
     136}
     137
     138/**
     139 * (Un)Installs a driver from/to the system.
     140 *
     141 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     142 * @param   fInstall            Flag indicating whether to install (TRUE) or uninstall (FALSE) a driver.
     143 * @param   pszDriverPath       Full qualified path to the driver's .INF file (+ driver files).
     144 * @param   fSilent             Flag indicating a silent installation (TRUE) or not (FALSE).
     145 */
     146int VBoxInstallDriver(const BOOL fInstall, const _TCHAR *pszDriverPath, BOOL fSilent)
     147{
     148    HRESULT hr = ERROR_SUCCESS;
     149    HMODULE hDIFxAPI = LoadLibrary(_T("DIFxAPI.dll"));
     150    if (NULL == hDIFxAPI)
     151    {
     152        _tprintf(_T("ERROR: Unable to locate DIFxAPI.dll!\n"));
     153        hr = ERROR_FILE_NOT_FOUND;
     154    }
     155    else
     156    {
     157        if (fInstall)
     158        {
     159            g_pfnDriverPackageInstall = (fnDriverPackageInstall)GetProcAddress(hDIFxAPI, "DriverPackageInstallW");
     160            if (g_pfnDriverPackageInstall == NULL)
     161            {
     162                _tprintf(_T("ERROR: Unable to retrieve entry point for DriverPackageInstallW!\n"));
     163                hr = ERROR_PROC_NOT_FOUND;
     164            }
    391165        }
    392166        else
    393167        {
    394             _tprintf(_T("Number of GUIDs found: %ld\n"), dwReqSize);
    395         }
    396 
    397         /* Not needed for now!
    398         if (EXIT_FAIL == CreateDevice (a_pszHwID, devClassArr[0]))
    399             return EXIT_FAIL;*/
    400     }
    401 
    402     if (rc == EXIT_OK)
    403     {
    404         _TCHAR* pcFile = NULL;
    405         if (0 == GetFullPathName(a_pszInfFile, _MAX_PATH, szInf, &pcFile))
    406         {
    407             dwErr = GetLastError();
    408 
     168            g_pfnDriverPackageUninstall = (fnDriverPackageUninstall)GetProcAddress(hDIFxAPI, "DriverPackageUninstallW");
     169            if (g_pfnDriverPackageUninstall == NULL)
     170            {
     171                _tprintf(_T("ERROR: Unable to retrieve entry point for DriverPackageUninstallW!\n"));
     172                hr = ERROR_PROC_NOT_FOUND;
     173            }
     174        }
     175
     176        if (SUCCEEDED(hr))
     177        {
     178            g_pfnDIFXAPISetLogCallback = (fnDIFXAPISetLogCallback)GetProcAddress(hDIFxAPI, "DIFXAPISetLogCallbackW");
     179            if (g_pfnDIFXAPISetLogCallback == NULL)
     180            {
     181                _tprintf(_T("ERROR: Unable to retrieve entry point for DIFXAPISetLogCallbackW!\n"));
     182                hr = ERROR_PROC_NOT_FOUND;
     183            }
     184        }
     185    }
     186
     187    if (SUCCEEDED(hr))
     188    {
     189        FILE *fh = NULL;
     190#ifdef DEBUG
     191        char szLogFile[MAX_PATH + 1];
     192        sprintf(szLogFile, VBOX_DRVINST_LOGFILE);
     193        fh = fopen(szLogFile, "a");
     194        if (!fh)
     195            _tprintf(_T("ERROR: Unable to create log file!\n"));
     196        else
     197             _tprintf(_T("Logging enabled ...\n"));
     198#endif
     199        g_pfnDIFXAPISetLogCallback(LogCallback, fh);
     200
     201        INSTALLERINFO instInfo =
     202        {
     203            TEXT("{7d2c708d-c202-40ab-b3e8-de21da1dc629}"), /* Our GUID for representing this installation tool. */
     204            TEXT("VirtualBox Guest Additions Install Helper"),
     205            TEXT("VirtualBox Guest Additions"), /** @todo Add version! */
     206            TEXT("Oracle Corporation")
     207        };
     208
     209        _TCHAR szDriverInf[MAX_PATH + 1];
     210        if (0 == GetFullPathNameW(pszDriverPath, MAX_PATH, szDriverInf, NULL))
     211        {
    409212            _tprintf(_T("ERROR: INF-Path too long / could not be retrieved!\n"));
    410             rc = EXIT_FAIL;
    411         }
    412 
    413         /* Extract path from path+INF */
    414         if (pcFile != NULL)
    415             _tcsnccpy(szInfPath, szInf, pcFile - szInf);
    416 
    417         _tprintf(_T("INF-File: %ws\n"), szInf);
    418         _tprintf(_T("INF-Path: %ws\n"), szInfPath);
    419 
    420         _tprintf(_T("Updating driver for plug'n play devices ...\n"));
    421         if (!g_pfnUpdateDriverForPlugAndPlayDevices(NULL, a_pszHwID, szInf, INSTALLFLAG_FORCE, &bReboot))
    422         {
    423             DWORD dwErr = GetLastError();
    424             _TCHAR szErrMsg[_MAX_PATH + 1] = { 0 };
    425 
    426             if (dwErr == ERROR_NO_SUCH_DEVINST)
    427             {
    428                 _TCHAR szDestInf[_MAX_PATH] = { 0 };
    429                 _tprintf(_T("The device is not plugged in (yet), pre-installing drivers ...\n"));
    430 
    431                 if (FALSE == g_pfnSetupCopyOEMInf(szInf, szInfPath, SPOST_PATH, 0, szDestInf, sizeof(szDestInf), NULL, NULL))
     213            hr = ERROR_INVALID_PARAMETER;
     214        }
     215        else
     216        {
     217            if (fInstall)
     218                _tprintf(_T("Installing driver ...\n"));
     219            else
     220                _tprintf(_T("Uninstalling driver ...\n"));
     221            _tprintf(_T("INF-File: %ws\n"), szDriverInf);
     222
     223            DWORD dwFlags = DRIVER_PACKAGE_FORCE;
     224            if (!fInstall)
     225                dwFlags |= DRIVER_PACKAGE_DELETE_FILES;
     226
     227            OSVERSIONINFO osi;
     228            memset(&osi, 0, sizeof(OSVERSIONINFO));
     229            osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
     230            if ( (GetVersionEx(&osi) != 0)
     231              && (osi.dwPlatformId == VER_PLATFORM_WIN32_NT)
     232              && (osi.dwMajorVersion < 6))
     233            {
     234                if (fInstall)
    432235                {
    433                     dwErr = GetLastError();
    434                     GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
    435                     _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
    436 
    437                     rc = EXIT_FAIL;
     236                    _tprintf(_T("Using legacy mode for install ...\n"));
     237                    dwFlags |= DRIVER_PACKAGE_LEGACY_MODE;
    438238                }
    439                 else
    440                     _tprintf(_T("OK. Installed to: %ws\n"), szDestInf);
    441             }
    442             else
    443             {
    444                 switch (dwErr)
     239            }
     240
     241            if (fSilent)
     242            {
     243                _tprintf(_T("Installation is silent ...\n"));
     244                dwFlags |= DRIVER_PACKAGE_SILENT;
     245            }
     246
     247            BOOL fReboot;
     248            DWORD dwRet = fInstall ?
     249                            g_pfnDriverPackageInstall(szDriverInf, dwFlags, &instInfo, &fReboot)
     250                          : g_pfnDriverPackageUninstall(szDriverInf, dwFlags, &instInfo, &fReboot);
     251            if (dwRet != ERROR_SUCCESS)
     252            {
     253                switch (dwRet)
    445254                {
    446 
    447                 case ERROR_INVALID_FLAGS:
    448 
    449                     _tprintf(_T("ERROR: The value specified for InstallFlags is invalid!\n"));
     255                    case CRYPT_E_FILE_ERROR:
     256                        _tprintf(_T("ERROR: The catalog file for the specified driver package was not found!\n"));
     257                        break;
     258
     259                    case ERROR_ACCESS_DENIED:
     260                        _tprintf(_T("ERROR: Caller is not in Administrators group to (un)install this driver package!\n"));
     261                        break;
     262
     263                    case ERROR_BAD_ENVIRONMENT:
     264                        _tprintf(_T("ERROR: The current Microsoft Windows version does not support this operation!\n"));
     265                        break;
     266
     267                    case ERROR_CANT_ACCESS_FILE:
     268                        _tprintf(_T("ERROR: The driver package files could not be accessed!\n"));
     269                        break;
     270
     271                    case ERROR_DEPENDENT_APPLICATIONS_EXIST:
     272                        _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"));
     273                        break;
     274
     275                    case ERROR_DRIVER_PACKAGE_NOT_IN_STORE:
     276                        _tprintf(_T("ERROR: There is no INF file in the DIFx driver store that corresponds to the INF file %ws!\n"), szDriverInf);
     277                        break;
     278
     279                    case ERROR_FILE_NOT_FOUND:
     280                        _tprintf(_T("ERROR: File not found! File = %ws\n"), szDriverInf);
     281                        break;
     282
     283                    case ERROR_IN_WOW64:
     284                        _tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!\n"));
     285                        break;
     286
     287                    case ERROR_INVALID_FLAGS:
     288                        _tprintf(_T("ERROR: The flags specified are invalid!\n"));
     289                        break;
     290
     291                    case ERROR_INSTALL_FAILURE:
     292                        _tprintf(_T("ERROR: The (un)install operation failed! Consult the Setup API logs for more information.\n"));
     293                        break;
     294
     295                    case ERROR_NO_MORE_ITEMS:
     296                        _tprintf(
     297                                 _T(
     298                                    "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"));
     299                        break;
     300
     301                    case ERROR_NO_DRIVER_SELECTED:
     302                        _tprintf(_T("ERROR: No driver in .INF-file selected!\n"));
     303                        break;
     304
     305                    case ERROR_SECTION_NOT_FOUND:
     306                        _tprintf(_T("ERROR: Section in .INF-file was not found!\n"));
     307                        break;
     308
     309                case ERROR_SHARING_VIOLATION:
     310                    _tprintf(_T("ERROR: A component of the driver package in the DIFx driver store is locked by a thread or process\n"));
    450311                    break;
    451312
    452                 case ERROR_NO_MORE_ITEMS:
    453 
    454                     _tprintf(
    455                              _T(
    456                                 "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"));
     313                    /*
     314                     * !    sig:           Verifying file against specific Authenticode(tm) catalog failed! (0x800b0109)
     315                     * !    sig:           Error 0x800b0109: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
     316                     * !!!  sto:           No error message will be displayed as client is running in non-interactive mode.
     317                     * !!!  ndv:           Driver package failed signature validation. Error = 0xE0000247
     318                     */
     319                    case ERROR_DRIVER_STORE_ADD_FAILED:
     320                        _tprintf(_T("ERROR: Adding driver to the driver store failed!!\n"));
     321                        break;
     322
     323                case ERROR_UNSUPPORTED_TYPE:
     324                    _tprintf(_T("ERROR: The driver package type is not supported of INF %ws!\n"), szDriverInf);
    457325                    break;
    458326
    459                 case ERROR_FILE_NOT_FOUND:
    460 
    461                     _tprintf(_T("ERROR: File not found! File = %ws\n"), szInf);
    462                     break;
    463 
    464                 case ERROR_IN_WOW64:
    465 
    466                     _tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!"));
    467                     break;
    468 
    469                 case ERROR_NO_DRIVER_SELECTED:
    470 
    471                     _tprintf(_T("ERROR: No driver in .INF-file selected!\n"));
    472                     break;
    473 
    474                 case ERROR_SECTION_NOT_FOUND:
    475 
    476                     _tprintf(_T("ERROR: Section in .INF-file was not found!\n"));
    477                     break;
    478 
    479                 default:
    480 
    481                     /* Try error lookup with GetErrorMsg() */
    482                     GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
    483                     _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
    484                     break;
    485                 }
    486 
    487                 rc = EXIT_FAIL;
    488             }
    489         }
    490     }
    491 
    492     if (rc == EXIT_OK)
    493         _tprintf(_T("Installation successful.\n"));
    494     return rc;
    495 }
    496 
    497 /*++
    498 
    499  Routine Description:
    500 
    501  Determine if this is instance id or hardware id and if there's any wildcards
    502  instance ID is prefixed by '@'
    503  wildcards are '*'
    504 
    505 
    506  Arguments:
    507 
    508  Id - ptr to string to check
    509 
    510  Return Value:
    511 
    512  IdEntry
    513 
    514  --*/
    515 IdEntry GetIdType (LPCTSTR Id)
    516 {
    517     IdEntry Entry;
    518 
    519     Entry.bInstanceId = FALSE;
    520     Entry.szWild = NULL;
    521     Entry.szString = Id;
    522 
    523     if (Entry.szString[0] == INSTANCEID_PREFIX_CHAR)
    524     {
    525         Entry.bInstanceId = TRUE;
    526         Entry.szString = CharNext(Entry.szString);
    527     }
    528     if (Entry.szString[0] == QUOTE_PREFIX_CHAR)
    529     {
    530         /* prefix to treat rest of string literally */
    531         Entry.szString = CharNext(Entry.szString);
    532     }
    533     else
    534     {
    535         /* see if any wild characters exist */
    536         Entry.szWild = _tcschr(Entry.szString, WILD_CHAR);
    537     }
    538     return Entry;
    539 }
    540 
    541 /*++
    542 
    543  Routine Description:
    544 
    545  Get an index array pointing to the MultiSz passed in
    546 
    547  Arguments:
    548 
    549  MultiSz - well formed multi-sz string
    550 
    551  Return Value:
    552 
    553  array of strings. last entry+1 of array contains NULL
    554  returns NULL on failure
    555 
    556  --*/
    557 LPTSTR * GetMultiSzIndexArray (LPTSTR MultiSz)
    558 {
    559     LPTSTR scan;
    560     LPTSTR * array;
    561     int elements;
    562 
    563     for (scan = MultiSz, elements = 0; scan[0]; elements++)
    564     {
    565         scan += lstrlen(scan) + 1;
    566     }
    567     array = new LPTSTR[elements + 2];
    568     if (!array)
    569     {
    570         return NULL;
    571     }
    572     array[0] = MultiSz;
    573     array++;
    574     if (elements)
    575     {
    576         for (scan = MultiSz, elements = 0; scan[0]; elements++)
    577         {
    578             array[elements] = scan;
    579             scan += lstrlen(scan) + 1;
    580         }
    581     }
    582     array[elements] = NULL;
    583     return array;
    584 }
    585 
    586 /*++
    587 
    588  Routine Description:
    589 
    590  Deletes the string array allocated by GetDevMultiSz/GetRegMultiSz/GetMultiSzIndexArray
    591 
    592  Arguments:
    593 
    594  Array - pointer returned by GetMultiSzIndexArray
    595 
    596  Return Value:
    597 
    598  None
    599 
    600  --*/
    601 void DelMultiSz (LPTSTR * Array)
    602 {
    603     if (Array)
    604     {
    605         Array--;
    606         if (Array[0])
    607         {
    608             delete[] Array[0];
    609         }
    610         delete[] Array;
    611     }
    612 }
    613 
    614 /*++
    615 
    616  Routine Description:
    617 
    618  Get a multi-sz device property
    619  and return as an array of strings
    620 
    621  Arguments:
    622 
    623  Devs    - HDEVINFO containing DevInfo
    624  DevInfo - Specific device
    625  Prop    - SPDRP_HARDWAREID or SPDRP_COMPATIBLEIDS
    626 
    627  Return Value:
    628 
    629  array of strings. last entry+1 of array contains NULL
    630  returns NULL on failure
    631 
    632  --*/
    633 LPTSTR * GetDevMultiSz (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Prop)
    634 {
    635     LPTSTR buffer;
    636     DWORD size;
    637     DWORD reqSize;
    638     DWORD dataType;
    639     LPTSTR * array;
    640     DWORD szChars;
    641 
    642     size = 8192; /* initial guess, nothing magic about this */
    643     buffer = new TCHAR[(size / sizeof(TCHAR)) + 2];
    644     if (!buffer)
    645     {
    646         return NULL;
    647     }
    648     while (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, Prop, &dataType, (LPBYTE)buffer, size, &reqSize))
    649     {
    650         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    651         {
    652             goto failed;
    653         }
    654         if (dataType != REG_MULTI_SZ)
    655         {
    656             goto failed;
    657         }
    658         size = reqSize;
    659         delete[] buffer;
    660         buffer = new TCHAR[(size / sizeof(TCHAR)) + 2];
    661         if (!buffer)
    662         {
    663             goto failed;
    664         }
    665     }
    666     szChars = reqSize / sizeof(TCHAR);
    667     buffer[szChars] = TEXT('\0');
    668     buffer[szChars + 1] = TEXT('\0');
    669     array = GetMultiSzIndexArray(buffer);
    670     if (array)
    671     {
    672         return array;
    673     }
    674 
    675     failed: if (buffer)
    676     {
    677         delete[] buffer;
    678     }
    679     return NULL;
    680 }
    681 
    682 /*++
    683 
    684  Routine Description:
    685 
    686  Compare a single item against wildcard
    687  I'm sure there's better ways of implementing this
    688  Other than a command-line management tools
    689  it's a bad idea to use wildcards as it implies
    690  assumptions about the hardware/instance ID
    691  eg, it might be tempting to enumerate root\* to
    692  find all root devices, however there is a CfgMgr
    693  API to query status and determine if a device is
    694  root enumerated, which doesn't rely on implementation
    695  details.
    696 
    697  Arguments:
    698 
    699  Item - item to find match for eg a\abcd\c
    700  MatchEntry - eg *\*bc*\*
    701 
    702  Return Value:
    703 
    704  TRUE if any match, otherwise FALSE
    705 
    706  --*/
    707 BOOL WildCardMatch (LPCTSTR Item, const IdEntry & MatchEntry)
    708 {
    709     LPCTSTR scanItem;
    710     LPCTSTR wildMark;
    711     LPCTSTR nextWild;
    712     size_t matchlen;
    713 
    714     /* Before attempting anything else,
    715      try and compare everything up to first wild */
    716     //
    717     if (!MatchEntry.szWild)
    718     {
    719         return _tcsicmp(Item, MatchEntry.szString) ? FALSE : TRUE;
    720     }
    721     if (_tcsnicmp(Item, MatchEntry.szString, MatchEntry.szWild - MatchEntry.szString) != 0)
    722     {
    723         return FALSE;
    724     }
    725     wildMark = MatchEntry.szWild;
    726     scanItem = Item + (MatchEntry.szWild - MatchEntry.szString);
    727 
    728     for (; wildMark[0];)
    729     {
    730         /* If we get here, we're either at or past a wildcard */
    731         if (wildMark[0] == WILD_CHAR)
    732         {
    733             /* So skip wild chars */
    734             wildMark = CharNext(wildMark);
    735             continue;
    736         }
    737 
    738         /* Find next wild-card */
    739         nextWild = _tcschr(wildMark, WILD_CHAR);
    740 
    741         if (nextWild)
    742         {
    743             /* Substring */
    744             matchlen = nextWild - wildMark;
    745         }
    746         else
    747         {
    748             /* Last portion of match */
    749             size_t scanlen = lstrlen(scanItem);
    750             matchlen = lstrlen(wildMark);
    751 
    752             if (scanlen < matchlen)
    753             {
    754                 return FALSE;
    755             }
    756 
    757             return _tcsicmp(scanItem + scanlen - matchlen, wildMark) ? FALSE : TRUE;
    758         }
    759 
    760         if (_istalpha(wildMark[0]))
    761         {
    762             /* Scan for either lower or uppercase version of first character */
    763             TCHAR u = _totupper(wildMark[0]);
    764             TCHAR l = _totlower(wildMark[0]);
    765             while (scanItem[0] && scanItem[0] != u && scanItem[0] != l)
    766             {
    767                 scanItem = CharNext(scanItem);
    768             }
    769 
    770             if (!scanItem[0])
    771             {
    772                 /* Ran out of string */
    773                 return FALSE;
    774             }
    775         }
    776         else
    777         {
    778             /* Scan for first character (no case) */
    779             scanItem = _tcschr(scanItem, wildMark[0]);
    780             if (!scanItem)
    781             {
    782                 /* Ran out of string */
    783                 return FALSE;
    784             }
    785         }
    786 
    787         /* Try and match the sub-string at wildMark against scanItem */
    788         if (_tcsnicmp(scanItem, wildMark, matchlen) != 0)
    789         {
    790             /* Nope, try again */
    791             scanItem = CharNext(scanItem);
    792             continue;
    793         }
    794 
    795         /* Substring matched */
    796         scanItem += matchlen;
    797         wildMark += matchlen;
    798     }
    799     return (wildMark[0] ? FALSE : TRUE);
    800 }
    801 
    802 /*++
    803 
    804  Routine Description:
    805 
    806  Compares all strings in Array against Id
    807  Use WildCardMatch to do real compare
    808 
    809  Arguments:
    810 
    811  Array - pointer returned by GetDevMultiSz
    812  MatchEntry - string to compare against
    813 
    814  Return Value:
    815 
    816  TRUE if any match, otherwise FALSE
    817 
    818  --*/
    819 BOOL WildCompareHwIds (LPTSTR * Array, const IdEntry & MatchEntry)
    820 {
    821     if (Array)
    822     {
    823         while (Array[0])
    824         {
    825             if (WildCardMatch(Array[0], MatchEntry))
    826             {
    827                 return TRUE;
    828             }
    829             Array++;
    830         }
    831     }
    832     return FALSE;
    833 }
    834 
    835 /*++
    836 
    837  Routine Description:
    838 
    839  Generic enumerator for devices that will be passed the following arguments:
    840  <id> [<id>...]
    841  =<class> [<id>...]
    842  where <id> can either be @instance-id, or hardware-id and may contain wildcards
    843  <class> is a class name
    844 
    845  Arguments:
    846 
    847  BaseName - name of executable
    848  Machine  - name of machine to enumerate
    849  Flags    - extra enumeration flags (eg DIGCF_PRESENT)
    850  argc/argv - remaining arguments on command line
    851  Callback - function to call for each hit
    852  Context  - data to pass function for each hit
    853 
    854  Return Value:
    855 
    856  EXIT_xxxx
    857 
    858  --*/
    859 int EnumerateDevices (LPCTSTR BaseName, LPCTSTR Machine, DWORD Flags, int argc, LPTSTR argv[], fnCallback Callback, LPVOID Context)
    860 {
    861     HDEVINFO devs = INVALID_HANDLE_VALUE;
    862     IdEntry * templ = NULL;
    863     int failcode = EXIT_FAIL;
    864     int retcode;
    865     int argIndex;
    866     DWORD devIndex;
    867     SP_DEVINFO_DATA devInfo;
    868     SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
    869     BOOL doSearch = FALSE;
    870     BOOL match;
    871     BOOL all = FALSE;
    872     GUID cls;
    873     DWORD numClass = 0;
    874     int skip = 0;
    875 
    876     if (!argc)
    877     {
    878         return EXIT_USAGE;
    879     }
    880 
    881     templ = new IdEntry[argc];
    882     if (!templ)
    883     {
    884         goto final;
    885     }
    886 
    887     /* Determine if a class is specified */
    888     if (argc > skip && argv[skip][0] == CLASS_PREFIX_CHAR && argv[skip][1])
    889     {
    890         if (!g_pfnSetupDiClassGuidsFromNameEx(argv[skip] + 1, &cls, 1, &numClass, Machine, NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    891         {
    892             goto final;
    893         }
    894         if (!numClass)
    895         {
    896             failcode = EXIT_OK;
    897             goto final;
    898         }
    899         skip++;
    900     }
    901 
    902     if (argc > skip && argv[skip][0] == WILD_CHAR && !argv[skip][1])
    903     {
    904         /* Catch convenient case of specifying a single argument '*' */
    905         all = TRUE;
    906         skip++;
    907     }
    908     else if (argc <= skip)
    909     {
    910         /* At least one parameter, but no <id>'s */
    911         all = TRUE;
    912     }
    913 
    914     /* Determine if any instance id's were specified */
    915 
    916     /* Note, if =<class> was specified with no id's
    917      we'll mark it as not doSearch
    918      but will go ahead and add them all */
    919     for (argIndex = skip; argIndex < argc; argIndex++)
    920     {
    921         templ[argIndex] = GetIdType(argv[argIndex]);
    922         if (templ[argIndex].szWild || !templ[argIndex].bInstanceId)
    923         {
    924             /* Anything other than simple bInstanceId's require a search */
    925             doSearch = TRUE;
    926         }
    927     }
    928     if (doSearch || all)
    929     {
    930         /* Add all id's to list
    931          If there's a class, filter on specified class */
    932         devs = g_pfnSetupDiGetClassDevsEx(numClass ? &cls : NULL, NULL, NULL, (numClass ? 0 : DIGCF_ALLCLASSES) | Flags, NULL, Machine, NULL);
    933 
    934     }
    935     else
    936     {
    937         /* Blank list, we'll add instance id's by hand */
    938         devs = g_pfnSetupDiCreateDeviceInfoListEx(numClass ? &cls : NULL, NULL, Machine, NULL);
    939     }
    940     if (devs == INVALID_HANDLE_VALUE)
    941     {
    942         goto final;
    943     }
    944     for (argIndex = skip; argIndex < argc; argIndex++)
    945     {
    946         /* Add explicit instances to list (even if enumerated all,
    947          this gets around DIGCF_PRESENT)
    948          do this even if wildcards appear to be detected since they
    949          might actually be part of the instance ID of a non-present device */
    950         if (templ[argIndex].bInstanceId)
    951         {
    952             g_pfnSetupDiOpenDeviceInfo(devs, templ[argIndex].szString, NULL, 0, NULL);
    953         }
    954     }
    955 
    956     devInfoListDetail.cbSize = sizeof(devInfoListDetail);
    957     if (!g_pfnSetupDiGetDeviceInfoListDetail(devs, &devInfoListDetail))
    958     {
    959         goto final;
    960     }
    961 
    962     /* Now enumerate them */
    963     if (all)
    964     {
    965         doSearch = FALSE;
    966     }
    967 
    968     devInfo.cbSize = sizeof(devInfo);
    969     for (devIndex = 0; g_pfnSetupDiEnumDeviceInfo(devs, devIndex, &devInfo); devIndex++)
    970     {
    971 
    972         if (doSearch)
    973         {
    974             for (argIndex = skip, match = FALSE; (argIndex < argc) && !match; argIndex++)
    975             {
    976                 TCHAR devID[MAX_DEVICE_ID_LEN];
    977                 LPTSTR *hwIds = NULL;
    978                 LPTSTR *compatIds = NULL;
    979 
    980                 /* Determine instance ID */
    981                 if (g_pfnCM_Get_Device_ID_Ex(devInfo.DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle) != CR_SUCCESS)
    982                 {
    983                     devID[0] = TEXT('\0');
    984                 }
    985 
    986                 if (templ[argIndex].bInstanceId)
    987                 {
    988                     /* Match on the instance ID */
    989                     if (WildCardMatch(devID, templ[argIndex]))
    990                         match = TRUE;
    991 
    992                 }
    993                 else
    994                 {
    995                     /* Determine hardware ID's and search for matches */
    996                     hwIds = GetDevMultiSz(devs, &devInfo, SPDRP_HARDWAREID);
    997                     compatIds = GetDevMultiSz(devs, &devInfo, SPDRP_COMPATIBLEIDS);
    998 
    999                     if (WildCompareHwIds(hwIds, templ[argIndex]) || WildCompareHwIds(compatIds, templ[argIndex]))
     327                    default:
    1000328                    {
    1001                         match = TRUE;
     329                        /* Try error lookup with GetErrorMsg(). */
     330                        TCHAR szErrMsg[1024];
     331                        GetErrorMsg(dwRet, szErrMsg, sizeof(szErrMsg));
     332                        _tprintf(_T("ERROR (%08x): %ws\n"), dwRet, szErrMsg);
     333                        break;
    1002334                    }
    1003335                }
    1004                 DelMultiSz(hwIds);
    1005                 DelMultiSz(compatIds);
    1006             }
    1007         }
    1008         else
    1009         {
    1010             match = TRUE;
    1011         }
    1012         if (match)
    1013         {
    1014             retcode = Callback(devs, &devInfo, devIndex, Context);
    1015             if (retcode)
    1016             {
    1017                 failcode = retcode;
    1018                 goto final;
    1019             }
    1020         }
    1021     }
    1022 
    1023     failcode = EXIT_OK;
    1024 
    1025     final: if (templ)
    1026     {
    1027         delete[] templ;
    1028     }
    1029     if (devs != INVALID_HANDLE_VALUE)
    1030     {
    1031         g_pfnSetupDiDestroyDeviceInfoList(devs);
    1032     }
    1033     return failcode;
    1034 
    1035 }
    1036 
    1037 /*++
    1038 
    1039  Routine Description:
    1040 
    1041  Callback for use by Remove
    1042  Invokes DIF_REMOVE
    1043  uses g_pfnSetupDiCallClassInstaller so cannot be done for remote devices
    1044  Don't use CM_xxx API's, they bypass class/co-installers and this is bad.
    1045 
    1046  Arguments:
    1047 
    1048  Devs    )_ uniquely identify the device
    1049  DevInfo )
    1050  Index    - index of device
    1051  Context  - GenericContext
    1052 
    1053  Return Value:
    1054 
    1055  EXIT_xxxx
    1056 
    1057  --*/
    1058 int UninstallCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context)
    1059 {
    1060     SP_REMOVEDEVICE_PARAMS rmdParams;
    1061     SP_DEVINSTALL_PARAMS devParams;
    1062     LPCTSTR action = NULL;
    1063 
    1064     /* Need hardware ID before trying to remove, as we wont have it after */
    1065     TCHAR devID[MAX_DEVICE_ID_LEN];
    1066     SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
    1067 
    1068     devInfoListDetail.cbSize = sizeof(devInfoListDetail);
    1069 
    1070     if ((!g_pfnSetupDiGetDeviceInfoListDetail(Devs, &devInfoListDetail)) || (g_pfnCM_Get_Device_ID_Ex(DevInfo->DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle)
    1071             != CR_SUCCESS))
    1072     {
    1073         /* Skip this */
    1074         return EXIT_OK;
    1075     }
    1076 
    1077     rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
    1078     rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
    1079     rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
    1080     rmdParams.HwProfile = 0;
    1081 
    1082     if (!g_pfnSetupDiSetClassInstallParams(Devs, DevInfo, &rmdParams.ClassInstallHeader, sizeof(rmdParams)) || !g_pfnSetupDiCallClassInstaller(DIF_REMOVE, Devs, DevInfo))
    1083     {
    1084         /* Failed to invoke DIF_REMOVE, TODO! */
    1085         _tprintf(_T("Failed to invoke interface!\n"));
    1086         return EXIT_FAIL;
    1087     }
    1088 
    1089     /* See if device needs reboot */
    1090     devParams.cbSize = sizeof(devParams);
    1091     if (g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &devParams) && (devParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)))
    1092     {
    1093         /* Reboot required */
    1094         _tprintf(_T("To fully uninstall, a reboot is required!\n"));
    1095     }
    1096     else
    1097     {
    1098         /* Appears to have succeeded */
    1099         _tprintf(_T("Uninstall succeeded!\n"));
    1100     }
    1101 
    1102     return EXIT_OK;
    1103 }
    1104 
    1105 /*++
    1106 
    1107  Routine Description:
    1108 
    1109  Find the driver that is associated with the current device
    1110  We can do this either the quick way (available in WinXP)
    1111  or the long way that works in Win2k.
    1112 
    1113  Arguments:
    1114 
    1115  Devs    )_ uniquely identify device
    1116  DevInfo )
    1117 
    1118  Return Value:
    1119 
    1120  TRUE if we managed to determine and select current driver
    1121 
    1122  --*/
    1123 BOOL FindCurrentDriver (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, PSP_DRVINFO_DATA DriverInfoData)
    1124 {
    1125     SP_DEVINSTALL_PARAMS deviceInstallParams;
    1126     WCHAR SectionName[LINE_LEN];
    1127     WCHAR DrvDescription[LINE_LEN];
    1128     WCHAR MfgName[LINE_LEN];
    1129     WCHAR ProviderName[LINE_LEN];
    1130     HKEY hKey = NULL;
    1131     DWORD RegDataLength;
    1132     DWORD RegDataType;
    1133     DWORD c;
    1134     BOOL match = FALSE;
    1135     long regerr;
    1136 
    1137     ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams));
    1138     deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
    1139 
    1140     if (!g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
    1141     {
    1142         printf("Could not retrieve install params!");
    1143         return FALSE;
    1144     }
    1145 
    1146 #ifdef DI_FLAGSEX_INSTALLEDDRIVER
    1147 
    1148     /* Set the flags that tell g_pfnSetupDiBuildDriverInfoList to just put the
    1149      currently installed driver node in the list, and that it should allow
    1150      excluded drivers. This flag introduced in WinXP. */
    1151     deviceInstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
    1152 
    1153     if (g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
    1154     {
    1155         /* We were able to specify this flag, so proceed the easy way
    1156          We should get a list of no more than 1 driver */
    1157         if (!g_pfnSetupDiBuildDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER))
    1158         {
    1159             return FALSE;
    1160         }
    1161         if (!g_pfnSetupDiEnumDriverInfo(Devs, DevInfo, SPDIT_CLASSDRIVER, 0, DriverInfoData))
    1162         {
    1163             return FALSE;
    1164         }
    1165 
    1166         /* We've selected the current driver */
    1167         return TRUE;
    1168     }
    1169 
    1170     deviceInstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
    1171 
     336                hr = ERROR_INSTALL_FAILURE;
     337            }
     338            g_pfnDIFXAPISetLogCallback(NULL, NULL);
     339#ifdef DEBUG
     340            if (fh)
     341                fclose(fh);
    1172342#endif
    1173 
    1174     /* The following method works in Win2k, but it's slow and painful.
    1175      First, get driver key - if it doesn't exist, no driver */
    1176     hKey = g_pfnSetupDiOpenDevRegKey(Devs, DevInfo, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ
    1177     );
    1178 
    1179     if (hKey == INVALID_HANDLE_VALUE)
    1180     {
    1181 
    1182         _tprintf(_T("No associated driver found in registry!"));
    1183 
    1184         /* No such value exists, so there can't be an associated driver */
    1185         RegCloseKey(hKey);
    1186         return FALSE;
    1187     }
    1188 
    1189     /* Obtain path of INF - we'll do a search on this specific INF */
    1190     RegDataLength = sizeof(deviceInstallParams.DriverPath); /* Bytes!!! */
    1191     regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFPATH, NULL, &RegDataType, (PBYTE)deviceInstallParams.DriverPath, &RegDataLength);
    1192 
    1193     if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
    1194     {
    1195 
    1196         _tprintf(_T("No associated .inf path found in registry!"));
    1197 
    1198         /* No such value exists, so no associated driver */
    1199         RegCloseKey(hKey);
    1200         return FALSE;
    1201     }
    1202 
    1203     /* Obtain name of Provider to fill into DriverInfoData */
    1204     RegDataLength = sizeof(ProviderName); /* Bytes!!! */
    1205     regerr = RegQueryValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, NULL, &RegDataType, (PBYTE)ProviderName, &RegDataLength);
    1206 
    1207     if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
    1208     {
    1209         /* No such value exists, so we don't have a valid associated driver */
    1210         RegCloseKey(hKey);
    1211         return FALSE;
    1212     }
    1213 
    1214     /* Obtain name of section - for final verification */
    1215     RegDataLength = sizeof(SectionName); /* Bytes!!! */
    1216     regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFSECTION, NULL, &RegDataType, (PBYTE)SectionName, &RegDataLength);
    1217 
    1218     if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
    1219     {
    1220         /* No such value exists, so we don't have a valid associated driver */
    1221         RegCloseKey(hKey);
    1222         return FALSE;
    1223     }
    1224 
    1225     /* Driver description (need not be same as device description) - for final verification */
    1226     RegDataLength = sizeof(DrvDescription); /* Bytes!!! */
    1227     regerr = RegQueryValueEx(hKey, REGSTR_VAL_DRVDESC, NULL, &RegDataType, (PBYTE)DrvDescription, &RegDataLength);
    1228 
    1229     RegCloseKey(hKey);
    1230 
    1231     if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
    1232     {
    1233         /* No such value exists, so we don't have a valid associated driver */
    1234         return FALSE;
    1235     }
    1236 
    1237     /* Manufacturer (via SPDRP_MFG, don't access registry directly!) */
    1238     if (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, SPDRP_MFG, NULL, /* Datatype is guaranteed to always be REG_SZ */
    1239     (PBYTE)MfgName, sizeof(MfgName), /* Bytes!!! */
    1240     NULL))
    1241     {
    1242         /* No such value exists, so we don't have a valid associated driver */
    1243         return FALSE;
    1244     }
    1245 
    1246     /* Now search for drivers listed in the INF */
    1247     deviceInstallParams.Flags |= DI_ENUMSINGLEINF;
    1248     deviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
    1249 
    1250     if (!g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
    1251     {
    1252         return FALSE;
    1253     }
    1254     if (!g_pfnSetupDiBuildDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER))
    1255     {
    1256         return FALSE;
    1257     }
    1258 
    1259     /* Find the entry in the INF that was used to install the driver for this device */
    1260     for (c = 0; g_pfnSetupDiEnumDriverInfo(Devs, DevInfo, SPDIT_CLASSDRIVER, c, DriverInfoData); c++)
    1261     {
    1262         if ((_tcscmp(DriverInfoData->MfgName, MfgName) == 0) && (_tcscmp(DriverInfoData->ProviderName, ProviderName) == 0))
    1263         {
    1264             /* These two fields match, try more detailed info to ensure we have the exact driver entry used */
    1265             SP_DRVINFO_DETAIL_DATA detail;
    1266             detail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
    1267             if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, DriverInfoData, &detail, sizeof(detail), NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
    1268             {
    1269                 continue;
    1270             }
    1271             if ((_tcscmp(detail.SectionName, SectionName) == 0) && (_tcscmp(detail.DrvDescription, DrvDescription) == 0))
    1272             {
    1273                 match = TRUE;
    1274                 break;
    1275             }
    1276         }
    1277     }
    1278     if (!match)
    1279     {
    1280         g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER);
    1281     }
    1282     return match;
    1283 }
    1284 
    1285 /*++
    1286 
    1287  Routine Description:
    1288 
    1289  if Context provided, Simply count
    1290  otherwise dump files indented 2
    1291 
    1292  Arguments:
    1293 
    1294  Context      - DWORD Count
    1295  Notification - SPFILENOTIFY_QUEUESCAN
    1296  Param1       - scan
    1297 
    1298  Return Value:
    1299 
    1300  none
    1301 
    1302  --*/
    1303 UINT DumpDeviceDriversCallback (IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2)
    1304 {
    1305     LPDWORD count = (LPDWORD)Context;
    1306     LPTSTR file = (LPTSTR)Param1;
    1307     if (count)
    1308     {
    1309         count[0]++;
    1310     }
    1311     else
    1312     {
    1313         _tprintf(TEXT("%s\n"), file);
    1314     }
    1315 
    1316     return NO_ERROR;
    1317 }
    1318 
    1319 /*++
    1320 
    1321  Routine Description:
    1322 
    1323  Dump information about what files were installed for driver package
    1324  <tab>Installed using OEM123.INF section [abc.NT]
    1325  <tab><tab>file...
    1326 
    1327  Arguments:
    1328 
    1329  Devs    )_ uniquely identify device
    1330  DevInfo )
    1331 
    1332  Return Value:
    1333 
    1334  none
    1335 
    1336  --*/
    1337 int DeleteOEMInfCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context)
    1338 {
    1339     /* Do this by 'searching' for the current driver
    1340      mimicking a copy-only install to our own file queue
    1341      and then parsing that file queue */
    1342     SP_DEVINSTALL_PARAMS deviceInstallParams;
    1343     SP_DRVINFO_DATA driverInfoData;
    1344     SP_DRVINFO_DETAIL_DATA driverInfoDetail;
    1345     HSPFILEQ queueHandle = INVALID_HANDLE_VALUE;
    1346     DWORD count;
    1347     DWORD scanResult;
    1348     int success = EXIT_FAIL;
    1349 
    1350     ZeroMemory(&driverInfoData,sizeof(driverInfoData));
    1351     driverInfoData.cbSize = sizeof(driverInfoData);
    1352 
    1353     if (!FindCurrentDriver(Devs, DevInfo, &driverInfoData))
    1354         return EXIT_FAIL;
    1355 
    1356     _tprintf(_T("Driver files found!\n"));
    1357 
    1358     /* Get useful driver information */
    1359     driverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
    1360     if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, &driverInfoData, &driverInfoDetail, sizeof(SP_DRVINFO_DETAIL_DATA), NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    1361     {
    1362         /* No information about driver or section */
    1363         _tprintf(_T("No information about driver or section!\n"));
    1364         goto final;
    1365     }
    1366 
    1367     if (!driverInfoDetail.InfFileName[0] || !driverInfoDetail.SectionName[0])
    1368     {
    1369         _tprintf(_T("Driver or section name is empty!\n"));
    1370         goto final;
    1371     }
    1372 
    1373     _tprintf(_T("Desc: %s\n"), driverInfoDetail.DrvDescription);
    1374     _tprintf(_T("SecName: %s\n"), driverInfoDetail.SectionName);
    1375     _tprintf(_T("INF-File: %s\n"), driverInfoDetail.InfFileName);
    1376 
    1377     /* Pretend to do the file-copy part of a driver install
    1378      to determine what files are used
    1379      the specified driver must be selected as the active driver */
    1380     if (!g_pfnSetupDiSetSelectedDriver(Devs, DevInfo, &driverInfoData))
    1381         goto final;
    1382 
    1383     /* Create a file queue so we can look at this queue later */
    1384     queueHandle = SetupOpenFileQueue();
    1385 
    1386     if (queueHandle == (HSPFILEQ)INVALID_HANDLE_VALUE)
    1387     {
    1388         goto final;
    1389     }
    1390 
    1391     /* Modify flags to indicate we're providing our own queue */
    1392     ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams));
    1393     deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
    1394     if (!g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
    1395         goto final;
    1396 
    1397     /* We want to add the files to the file queue, not install them! */
    1398     deviceInstallParams.FileQueue = queueHandle;
    1399     deviceInstallParams.Flags |= DI_NOVCP;
    1400 
    1401     if (!g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
    1402         goto final;
    1403 
    1404     /* Now fill queue with files that are to be installed this involves all class/co-installers */
    1405     if (!g_pfnSetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, Devs, DevInfo))
    1406         goto final;
    1407 
    1408     /* We now have a list of delete/rename/copy files
    1409      iterate the copy queue twice - 1st time to get # of files
    1410      2nd time to get files (WinXP has API to get # of files, but we want this to work
    1411      on Win2k too */
    1412     count = 0;
    1413     scanResult = 0;
    1414 
    1415     /* Call once to count (NOT YET IMPLEMENTED!) */
    1416     //SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,&count,&scanResult);
    1417     //FormatToStream(stdout, count ? MSG_DUMP_DRIVER_FILES : MSG_DUMP_NO_DRIVER_FILES, count, driverInfoDetail.InfFileName, driverInfoDetail.SectionName);
    1418 
    1419     /* Call again to dump the files (NOT YET IMPLEMENTED!) */
    1420     //SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,NULL,&scanResult);
    1421 
    1422     if (!DeleteFile(driverInfoDetail.InfFileName))
    1423         scanResult = GetLastError();
    1424     else
    1425     {
    1426         DWORD index = 0;
    1427 
    1428         index = lstrlen(driverInfoDetail.InfFileName);
    1429         if (index > 3)
    1430         {
    1431             lstrcpy(driverInfoDetail.InfFileName + index - 3, TEXT( "pnf" ) );
    1432 
    1433             if (!DeleteFile(driverInfoDetail.InfFileName))
    1434                 scanResult = GetLastError();
    1435         }
    1436     }
    1437 
    1438     success = EXIT_OK;
    1439 
    1440     final:
    1441 
    1442     g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER);
    1443 
    1444     if (queueHandle != (HSPFILEQ)INVALID_HANDLE_VALUE)
    1445     {
    1446         SetupCloseFileQueue(queueHandle);
    1447     }
    1448 
    1449     if (EXIT_OK != success)
    1450     {
    1451         _tprintf(_T("Something went wrong while delete the OEM INF-files!\n\n"));
    1452     }
    1453 
    1454     return success;
    1455 
    1456 }
    1457 
    1458 int UninstallDriver (_TCHAR* a_pszHwID)
    1459 {
    1460     _tprintf(_T("Uninstalling device: %ws\n"), a_pszHwID);
    1461 
    1462     _tprintf(_T("Removing driver files ...\n\n"));
    1463     int iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, DeleteOEMInfCallback, NULL);
    1464 
    1465     if (EXIT_OK != iRet)
    1466         return iRet;
    1467 
    1468     _tprintf(_T("Uninstalling driver ...\n\n"));
    1469     iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, UninstallCallback, NULL);
    1470 
    1471     return iRet;
    1472 }
    1473 
    1474 #ifdef VBOX_WITH_WDDM
    1475 /*++
    1476 
    1477  Routine Description:
    1478 
    1479  Dump information about what files were installed for driver package
    1480  <tab>Installed using OEM123.INF section [abc.NT]
    1481  <tab><tab>file...
    1482 
    1483  Arguments:
    1484 
    1485  Devs    )_ uniquely identify device
    1486  DevInfo )
    1487 
    1488  Return Value:
    1489 
    1490  none
    1491 
    1492  --*/
    1493 int MatchDriverCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context)
    1494 {
    1495     /* Do this by 'searching' for the current driver
    1496      mimicking a copy-only install to our own file queue
    1497      and then parsing that file queue */
    1498     SP_DRVINFO_DATA driverInfoData;
    1499     SP_DRVINFO_DETAIL_DATA driverInfoDetail;
    1500     LPCTSTR pStr = (LPCTSTR)Context;
    1501     int success = EXIT_FAIL;
    1502 
    1503     ZeroMemory(&driverInfoData,sizeof(driverInfoData));
    1504     driverInfoData.cbSize = sizeof(driverInfoData);
    1505 
    1506     if (!FindCurrentDriver(Devs, DevInfo, &driverInfoData))
    1507         return EXIT_FAIL;
    1508 
    1509     _tprintf(_T("Driver files found!\n"));
    1510 
    1511     /* Get useful driver information */
    1512     driverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
    1513     if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, &driverInfoData, &driverInfoDetail, sizeof(SP_DRVINFO_DETAIL_DATA), NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    1514     {
    1515         /* No information about driver or section */
    1516         _tprintf(_T("No information about driver or section!\n"));
    1517         goto final;
    1518     }
    1519 
    1520     if (!driverInfoDetail.InfFileName[0] || !driverInfoDetail.SectionName[0])
    1521     {
    1522         _tprintf(_T("Driver or section name is empty!\n"));
    1523         goto final;
    1524     }
    1525 
    1526     _tprintf(_T("Desc: %s\n"), driverInfoDetail.DrvDescription);
    1527     _tprintf(_T("SecName: %s\n"), driverInfoDetail.SectionName);
    1528     _tprintf(_T("INF-File: %s\n"), driverInfoDetail.InfFileName);
    1529 
    1530     if (_tcsstr(driverInfoDetail.DrvDescription, pStr))
    1531     {
    1532         _tprintf(_T("Driver name matched\n"));
    1533         success = EXIT_OK;
    1534     }
    1535     else
    1536     {
    1537         _tprintf(_T("Driver name NOT matched\n"));
    1538         success = EXIT_FALSE;
    1539     }
    1540 
    1541     final:
    1542 
    1543     g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER);
    1544 
    1545     if (EXIT_OK != success && EXIT_FALSE != success)
    1546     {
    1547         _tprintf(_T("Something went wrong while delete the OEM INF-files!\n\n"));
    1548     }
    1549 
    1550     return success;
    1551 }
    1552 
    1553 int MatchDriver (_TCHAR* a_pszHwID, _TCHAR* a_pszDrvName)
    1554 {
    1555     _tprintf(_T("Checking Device: %ws ; for driver desc string %ws\n"), a_pszHwID, a_pszDrvName);
    1556 
    1557     int iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, MatchDriverCallback, a_pszDrvName);
    1558 
    1559     return iRet;
    1560 }
    1561 #endif
    1562 
    1563 int ExecuteInfFile (_TCHAR* a_pszSection, int a_iMode, _TCHAR* a_pszInf)
    1564 {
    1565     _tprintf(_T("Executing INF-File: %ws (%ws) ...\n"), a_pszInf, a_pszSection);
     343            if (SUCCEEDED(hr))
     344            {
     345                if (fReboot)
     346                    _tprintf(_T("A reboot is needed to complete the driver (un)installation!\n"));
     347            }
     348        }
     349    }
     350
     351    if (NULL != hDIFxAPI)
     352       FreeLibrary(hDIFxAPI);
     353
     354    return SUCCEEDED(hr) ? EXIT_OK : EXIT_FAIL;
     355}
     356
     357/**
     358 * Executes a sepcified .INF section to install/uninstall drivers and/or services.
     359 *
     360 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     361 * @param   pszSection          Section to execute; usually it's "DefaultInstall".
     362 * @param   iMode               Execution mode to use (see MSDN).
     363 * @param   pszInf              Full qualified path of the .INF file to use.
     364 */
     365int ExecuteInfFile(const _TCHAR *pszSection, int iMode, const _TCHAR *pszInf)
     366{
     367    _tprintf(_T("Executing INF-File: %ws (Section: %ws) ...\n"), pszInf, pszSection);
    1566368
    1567369    /* Executed by the installer that already has proper privileges. */
    1568370    _TCHAR szCommandLine[_MAX_PATH + 1] = { 0 };
    1569     swprintf(szCommandLine, sizeof(szCommandLine), TEXT( "%ws %d %ws" ), a_pszSection, a_iMode, a_pszInf);
    1570 
    1571 #ifdef _DEBUG
     371    swprintf(szCommandLine, sizeof(szCommandLine), TEXT( "%ws %d %ws" ), pszSection, iMode, pszInf);
     372
     373#ifdef DEBUG
    1572374    _tprintf (_T( "Commandline: %ws\n"), szCommandLine);
    1573375#endif
    1574376
    1575377    InstallHinfSection(NULL, NULL, szCommandLine, SW_SHOW);
     378    /* No return value given! */
    1576379
    1577380    return EXIT_OK;
    1578381}
    1579382
    1580 int AddNetworkProvider (TCHAR* a_pszProvider, int a_iOrder)
    1581 {
     383/**
     384 * Adds a string entry to a MULTI_SZ registry list.
     385 *
     386 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     387 * @param   pszSubKey           Sub key containing the list.
     388 * @param   pszKeyValue         The actual key name of the list.
     389 * @param   pszValueToRemove    The value to add to the list.
     390 * @param   uiOrder             Position (zero-based) of where to add the value to the list.
     391 */
     392int RegistryAddStringToMultiSZ(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToAdd, unsigned int uiOrder)
     393{
     394#ifdef DEBUG
     395    _tprintf(_T("AddStringToMultiSZ: Adding MULTI_SZ string %ws to %ws\\%ws (Order = %d)\n"), pszValueToAdd, pszSubKey, pszKeyValue, uiOrder);
     396#endif
     397
     398    HKEY hKey = NULL;
     399    DWORD disp, dwType;
     400    LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
     401    if (lRet != ERROR_SUCCESS)
     402        _tprintf(_T("AddStringToMultiSZ: RegCreateKeyEx %ts failed with error %ld!\n"), pszSubKey, lRet);
     403
     404    if (lRet == ERROR_SUCCESS)
     405    {
     406        TCHAR szKeyValue[512] = { 0 };
     407        TCHAR szNewKeyValue[512] = { 0 };
     408        DWORD cbKeyValue = sizeof(szKeyValue);
     409
     410        lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
     411        if (   lRet != ERROR_SUCCESS
     412            || dwType != REG_MULTI_SZ)
     413        {
     414           _tprintf(_T("AddStringToMultiSZ: RegQueryValueEx failed with error %ld, key type = 0x%x!\n"), lRet, dwType);
     415        }
     416        else
     417        {
     418
     419            /* Look if the network provider is already in the list. */
     420            int iPos = 0;
     421            size_t cb = 0;
     422
     423            /* Replace delimiting "\0"'s with "," to make tokenizing work. */
     424            for (int i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
     425                if (szKeyValue[i] == '\0') szKeyValue[i] = ',';
     426
     427            TCHAR *pszToken = wcstok(szKeyValue, _T(","));
     428            TCHAR *pszNewToken = NULL;
     429            TCHAR *pNewKeyValuePos = szNewKeyValue;
     430            while (pszToken != NULL)
     431            {
     432               pszNewToken = wcstok(NULL, _T(","));
     433
     434               /* Append new value (at beginning if iOrder=0). */
     435               if (iPos == uiOrder)
     436               {
     437                   memcpy(pNewKeyValuePos, pszValueToAdd, wcslen(pszValueToAdd)*sizeof(TCHAR));
     438
     439                   cb += (wcslen(pszValueToAdd) + 1) * sizeof(TCHAR);  /* Add trailing zero as well. */
     440                   pNewKeyValuePos += wcslen(pszValueToAdd) + 1;
     441                   iPos++;
     442               }
     443
     444               if (0 != wcsicmp(pszToken, pszValueToAdd))
     445               {
     446                   memcpy(pNewKeyValuePos, pszToken, wcslen(pszToken)*sizeof(TCHAR));
     447                   cb += (wcslen(pszToken) + 1) * sizeof(TCHAR);  /* Add trailing zero as well. */
     448                   pNewKeyValuePos += wcslen(pszToken) + 1;
     449                   iPos++;
     450               }
     451
     452               pszToken = pszNewToken;
     453            }
     454
     455            /* Append as last item if needed. */
     456            if (uiOrder >= iPos)
     457            {
     458                memcpy(pNewKeyValuePos, pszValueToAdd, wcslen(pszValueToAdd)*sizeof(TCHAR));
     459                cb += wcslen(pszValueToAdd) * sizeof(TCHAR);  /* Add trailing zero as well. */
     460            }
     461
     462            lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szNewKeyValue, (DWORD)cb);
     463            if (lRet != ERROR_SUCCESS)
     464               _tprintf(_T("AddStringToMultiSZ: RegSetValueEx failed with error %ld!\n"), lRet);
     465        }
     466
     467        RegCloseKey(hKey);
     468    #ifdef DEBUG
     469        if (lRet == ERROR_SUCCESS)
     470           _tprintf(_T("AddStringToMultiSZ: Value %ws successfully written!\n"), pszValueToAdd);
     471    #endif
     472    }
     473
     474    return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
     475}
     476
     477/**
     478 * Removes a string entry from a MULTI_SZ registry list.
     479 *
     480 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     481 * @param   pszSubKey           Sub key containing the list.
     482 * @param   pszKeyValue         The actual key name of the list.
     483 * @param   pszValueToRemove    The value to remove from the list.
     484 */
     485int RegistryRemoveStringFromMultiSZ(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToRemove)
     486{
     487    // @todo Make string sizes dynamically allocated!
     488
     489    const TCHAR *pszKey = pszSubKey;
     490#ifdef DEBUG
     491    _tprintf(_T("RemoveStringFromMultiSZ: Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), pszValueToRemove, pszSubKey, pszKeyValue);
     492#endif
     493
     494    HKEY hkey;
     495    DWORD disp, dwType;
     496    LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp);
     497    if (lRet != ERROR_SUCCESS)
     498        _tprintf(_T("RemoveStringFromMultiSZ: RegCreateKeyEx %ts failed with error %ld!\n"), pszKey, lRet);
     499
     500    if (lRet == ERROR_SUCCESS)
     501    {
     502        TCHAR szKeyValue[1024];
     503        DWORD cbKeyValue = sizeof(szKeyValue);
     504
     505        lRet = RegQueryValueEx(hkey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
     506        if (   lRet   != ERROR_SUCCESS
     507            || dwType != REG_MULTI_SZ)
     508        {
     509            _tprintf(_T("RemoveStringFromMultiSZ: RegQueryValueEx failed with %d, key type = 0x%x!\n"), lRet, dwType);
     510        }
     511        else
     512        {
     513        #ifdef DEBUG
     514            _tprintf(_T("RemoveStringFromMultiSZ: Current key len: %ld\n"), cbKeyValue);
     515        #endif
     516
     517            TCHAR szCurString[1024] = { 0 };
     518            TCHAR szFinalString[1024] = { 0 };
     519            int iIndex = 0;
     520            int iNewIndex = 0;
     521            for (int i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
     522            {
     523                if (szKeyValue[i] != _T('\0'))
     524                    szCurString[iIndex++] = szKeyValue[i];
     525
     526                if (   (!szKeyValue[i] == _T('\0'))
     527                    && (szKeyValue[i + 1] == _T('\0')))
     528                {
     529                    if (NULL == wcsstr(szCurString, pszValueToRemove))
     530                    {
     531                        wcscat(&szFinalString[iNewIndex], szCurString);
     532
     533                        if (iNewIndex == 0)
     534                            iNewIndex = iIndex;
     535                        else iNewIndex += iIndex;
     536
     537                        szFinalString[++iNewIndex] = _T('\0');
     538                    }
     539
     540                    iIndex = 0;
     541                    ZeroMemory(szCurString, sizeof(szCurString));
     542                }
     543            }
     544            szFinalString[++iNewIndex] = _T('\0');
     545        #ifdef DEBUG
     546            _tprintf(_T("RemoveStringFromMultiSZ: New key value: %ws (%u bytes)\n"),
     547                     szFinalString, iNewIndex * sizeof(TCHAR));
     548        #endif
     549
     550            lRet = RegSetValueExW(hkey, pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR));
     551            if (lRet != ERROR_SUCCESS)
     552                _tprintf(_T("RemoveStringFromMultiSZ: RegSetValueEx failed with %d!\n"), lRet);
     553        }
     554
     555        RegCloseKey(hkey);
     556    #ifdef DEBUG
     557        if (lRet == ERROR_SUCCESS)
     558            _tprintf(_T("RemoveStringFromMultiSZ: Value %ws successfully removed!\n"), pszValueToRemove);
     559    #endif
     560    }
     561
     562    return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
     563}
     564
     565/**
     566 * Adds a string to a registry string list (STRING_SZ).
     567 * Only operates in HKLM for now, needs to be extended later for
     568 * using other hives. Only processes lists with a "," separator
     569 * at the moment.
     570 *
     571 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     572 * @param   pszSubKey           Sub key containing the list.
     573 * @param   pszKeyValue         The actual key name of the list.
     574 * @param   pszValueToAdd       The value to add to the list.
     575 * @param   uiOrder             Position (zero-based) of where to add the value to the list.
     576 * @param   dwFlags             Flags.
     577 */
     578int RegistryAddStringToList(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToAdd,
     579                            unsigned int uiOrder, DWORD dwFlags)
     580{
     581    HKEY hKey = NULL;
     582    DWORD disp, dwType;
     583    LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
     584    if (lRet != ERROR_SUCCESS)
     585        _tprintf(_T("RegistryAddStringToList: RegCreateKeyEx %ts failed with error %ld!\n"), pszSubKey, lRet);
     586
    1582587    TCHAR szKeyValue[512] = { 0 };
    1583588    TCHAR szNewKeyValue[512] = { 0 };
     589    DWORD cbKeyValue = sizeof(szKeyValue);
     590
     591    lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
     592    if (   lRet != ERROR_SUCCESS
     593        || dwType != REG_SZ)
     594    {
     595        _tprintf(_T("RegistryAddStringToList: RegQueryValueEx failed with %d, key type = 0x%x!\n"), lRet, dwType);
     596    }
     597
     598    if (lRet == ERROR_SUCCESS)
     599    {
     600    #ifdef DEBUG
     601        _tprintf(_T("RegistryAddStringToList: Key value: %ws\n"), szKeyValue);
     602    #endif
     603
     604        /* Create entire new list. */
     605        unsigned int iPos = 0;
     606        TCHAR *pszToken = wcstok(szKeyValue, _T(","));
     607        TCHAR *pszNewToken = NULL;
     608        while (pszToken != NULL)
     609        {
     610            pszNewToken = wcstok(NULL, _T(","));
     611
     612            /* Append new provider name (at beginning if iOrder=0). */
     613            if (iPos == uiOrder)
     614            {
     615                wcscat(szNewKeyValue, pszValueToAdd);
     616                wcscat(szNewKeyValue, _T(","));
     617                iPos++;
     618            }
     619
     620            BOOL fAddToList = FALSE;
     621            if (   !wcsicmp(pszToken, pszValueToAdd)
     622                && (dwFlags & VBOX_REG_STRINGLIST_ALLOW_DUPLICATES))
     623                fAddToList = TRUE;
     624            else if (wcsicmp(pszToken, pszValueToAdd))
     625                fAddToList = TRUE;
     626
     627            if (fAddToList)
     628            {
     629                wcscat(szNewKeyValue, pszToken);
     630                wcscat(szNewKeyValue, _T(","));
     631                iPos++;
     632            }
     633
     634    #ifdef DEBUG
     635            _tprintf (_T("RegistryAddStringToList: Temp new key value: %ws\n"), szNewKeyValue);
     636    #endif
     637            pszToken = pszNewToken;
     638        }
     639
     640        /* Append as last item if needed. */
     641        if (uiOrder >= iPos)
     642            wcscat(szNewKeyValue, pszValueToAdd);
     643
     644        /* Last char a delimiter? Cut off ... */
     645        if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
     646            szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
     647
     648        size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
     649
     650    #ifdef DEBUG
     651        _tprintf(_T("RegistryAddStringToList: New provider list: %ws (%u bytes)\n"), szNewKeyValue, iNewLen);
     652    #endif
     653
     654        lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
     655        if (lRet != ERROR_SUCCESS)
     656            _tprintf(_T("RegistryAddStringToList: RegSetValueEx failed with %ld!\n"), lRet);
     657    }
     658
     659    RegCloseKey(hKey);
     660    return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
     661}
     662
     663/**
     664 * Removes a string from a registry string list (STRING_SZ).
     665 * Only operates in HKLM for now, needs to be extended later for
     666 * using other hives. Only processes lists with a "," separator
     667 * at the moment.
     668 *
     669 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     670 * @param   pszSubKey           Sub key containing the list.
     671 * @param   pszKeyValue         The actual key name of the list.
     672 * @param   pszValueToRemove    The value to remove from the list.
     673 */
     674int RegistryRemoveStringFromList(const TCHAR *pszSubKey, const TCHAR *pszKeyValue, const TCHAR *pszValueToRemove)
     675{
    1584676    HKEY hKey = NULL;
    1585677    DWORD disp, dwType;
    1586     int rc;
    1587 
    1588     _tprintf(_T("Adding network provider: %ws (Order = %d)\n"), a_pszProvider, a_iOrder);
    1589 
    1590     /* Note: HWOrder is not accessible in Windows 2000; it is updated automatically anyway. */
    1591     TCHAR *pszKey = _T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
    1592 
    1593     rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
    1594     if (rc != ERROR_SUCCESS)
    1595     {
    1596         _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), pszKey, rc);
    1597         return EXIT_FAIL;
    1598     }
    1599     DWORD cbKeyValue = sizeof(szKeyValue);
    1600 
    1601     rc = RegQueryValueEx(hKey, _T("ProviderOrder"), NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
    1602     if (rc != ERROR_SUCCESS || dwType != REG_SZ)
    1603     {
    1604         _tprintf(_T("RegQueryValueEx failed with %d dwType = 0x%x!\n"), rc, dwType);
    1605         return EXIT_FAIL;
    1606     }
    1607 
    1608 #ifdef _DEBUG
    1609     _tprintf(_T("Key value: %ws\n"), szKeyValue);
    1610 #endif
    1611 
    1612     /* Create entire new list. */
    1613     int iPos = 0;
    1614 
    1615     TCHAR* pszToken = wcstok(szKeyValue, _T(","));
    1616     TCHAR* pszNewToken = NULL;
    1617     while (pszToken != NULL)
    1618     {
    1619         pszNewToken = wcstok(NULL, _T(","));
    1620 
    1621         /* Append new provider name (at beginning if a_iOrder=0). */
    1622         if (iPos == a_iOrder)
    1623         {
    1624             wcscat(szNewKeyValue, a_pszProvider);
    1625             wcscat(szNewKeyValue, _T(","));
    1626             iPos++;
    1627         }
    1628 
    1629         if (0 != wcsicmp(pszToken, a_pszProvider))
    1630         {
    1631             wcscat(szNewKeyValue, pszToken);
    1632             wcscat(szNewKeyValue, _T(","));
    1633             iPos++;
    1634         }
    1635 
    1636 #ifdef _DEBUG
    1637         _tprintf (_T("Temp new key value: %ws\n"), szNewKeyValue);
    1638 #endif
    1639 
    1640         pszToken = pszNewToken;
    1641     }
    1642 
    1643     /* Append as last item if needed. */
    1644     if (a_iOrder >= iPos)
    1645         wcscat(szNewKeyValue, a_pszProvider);
    1646 
    1647     /* Last char a delimiter? Cut off ... */
    1648     if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
    1649         szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
    1650 
    1651     size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
    1652 
    1653     _tprintf(_T("New provider list (%u bytes): %ws\n"), iNewLen, szNewKeyValue);
    1654 
    1655     rc = RegSetValueExW(hKey, _T("ProviderOrder"), 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
    1656 
    1657     if (rc != ERROR_SUCCESS)
    1658     {
    1659         _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
    1660         return EXIT_FAIL;
    1661     }
    1662 
    1663     rc = RegCloseKey(hKey);
    1664 
    1665     if (rc == ERROR_SUCCESS)
    1666     {
    1667         _tprintf(_T("Network provider successfully installed!\n"), rc);
    1668         rc = EXIT_OK;
    1669     }
    1670 
    1671     return rc;
    1672 }
    1673 
    1674 int AddStringToMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToAdd, int a_iOrder)
    1675 {
     678    LONG lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
     679    if (lRet != ERROR_SUCCESS)
     680        _tprintf(_T("RegistryRemoveStringFromList: RegCreateKeyEx %ts failed with error %ld!\n"), pszSubKey, lRet);
     681
    1676682    TCHAR szKeyValue[512] = { 0 };
    1677683    TCHAR szNewKeyValue[512] = { 0 };
    1678     HKEY hKey = NULL;
    1679     DWORD disp, dwType;
    1680     int rc = 0;
    1681 
    1682     _tprintf(_T("Adding MULTI_SZ string: %ws to %ws\\%ws (Order = %d)\n"), a_pszValueToAdd, a_pszSubKey, a_pszKeyValue, a_iOrder);
    1683 
    1684     rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, a_pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
    1685     if (rc != ERROR_SUCCESS)
    1686     {
    1687        _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), a_pszSubKey, rc);
    1688        return EXIT_FAIL;
    1689     }
    1690684    DWORD cbKeyValue = sizeof(szKeyValue);
    1691685
    1692     rc = RegQueryValueEx(hKey, a_pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
    1693     if (rc != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
    1694     {
    1695        _tprintf(_T("RegQueryValueEx failed with %d, dwType = 0x%x!\n"), rc, dwType);
    1696        return EXIT_FAIL;
    1697     }
    1698 
    1699     /* Look if the network provider is already in the list. */
    1700     int iPos = 0;
    1701     size_t cb = 0;
    1702 
    1703     /* Replace delimiting "\0"'s with "," to make tokenizing work. */
    1704     for (int i=0; i<cbKeyValue/sizeof(TCHAR);i++)
    1705         if (szKeyValue[i] == '\0') szKeyValue[i] = ',';
    1706 
    1707     TCHAR* pszToken = wcstok(szKeyValue, _T(","));
    1708     TCHAR* pszNewToken = NULL;
    1709     TCHAR* pNewKeyValuePos = szNewKeyValue;
    1710     while (pszToken != NULL)
    1711     {
    1712        pszNewToken = wcstok(NULL, _T(","));
    1713 
    1714        /* Append new value (at beginning if a_iOrder=0). */
    1715        if (iPos == a_iOrder)
    1716        {
    1717            memcpy(pNewKeyValuePos, a_pszValueToAdd, wcslen(a_pszValueToAdd)*sizeof(TCHAR));
    1718 
    1719            cb += (wcslen(a_pszValueToAdd) + 1) * sizeof(TCHAR);  /* Add trailing zero as well. */
    1720            pNewKeyValuePos += wcslen(a_pszValueToAdd) + 1;
    1721            iPos++;
    1722        }
    1723 
    1724        if (0 != wcsicmp(pszToken, a_pszValueToAdd))
    1725        {
    1726            memcpy(pNewKeyValuePos, pszToken, wcslen(pszToken)*sizeof(TCHAR));
    1727            cb += (wcslen(pszToken) + 1) * sizeof(TCHAR);  /* Add trailing zero as well. */
    1728            pNewKeyValuePos += wcslen(pszToken) + 1;
    1729            iPos++;
    1730        }
    1731 
    1732        pszToken = pszNewToken;
    1733     }
    1734 
    1735     /* Append as last item if needed. */
    1736     if (a_iOrder >= iPos)
    1737     {
    1738         memcpy(pNewKeyValuePos, a_pszValueToAdd, wcslen(a_pszValueToAdd)*sizeof(TCHAR));
    1739         cb += wcslen(a_pszValueToAdd) * sizeof(TCHAR);  /* Add trailing zero as well. */
    1740     }
    1741 
    1742     rc = RegSetValueExW(hKey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szNewKeyValue, (DWORD)cb);
    1743 
    1744     if (rc != ERROR_SUCCESS)
    1745     {
    1746        _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
    1747        return EXIT_FAIL;
    1748     }
    1749 
    1750     rc = RegCloseKey(hKey);
    1751 
    1752     if (rc == ERROR_SUCCESS)
    1753     {
    1754        _tprintf(_T("Value successfully written (%u bytes)!\n"), cb);
    1755        rc = EXIT_OK;
    1756     }
    1757 
     686    lRet = RegQueryValueEx(hKey, pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
     687    if (   lRet != ERROR_SUCCESS
     688        || dwType != REG_SZ)
     689    {
     690        _tprintf(_T("RegistryRemoveStringFromList: RegQueryValueEx failed with %d, key type = 0x%x!\n"), lRet, dwType);
     691    }
     692
     693    if (lRet == ERROR_SUCCESS)
     694    {
     695    #ifdef DEBUG
     696        _tprintf(_T("RegistryRemoveStringFromList: Key value: %ws\n"), szKeyValue);
     697    #endif
     698
     699        /* Create entire new list. */
     700        int iPos = 0;
     701
     702        TCHAR *pszToken = wcstok(szKeyValue, _T(","));
     703        TCHAR *pszNewToken = NULL;
     704        while (pszToken != NULL)
     705        {
     706            pszNewToken = wcstok(NULL, _T(","));
     707
     708            /* Append all list values as long as it's not the
     709             * value we want to remove. */
     710            if (wcsicmp(pszToken, pszValueToRemove))
     711            {
     712                wcscat(szNewKeyValue, pszToken);
     713                wcscat(szNewKeyValue, _T(","));
     714                iPos++;
     715            }
     716
     717    #ifdef DEBUG
     718            _tprintf (_T("RegistryRemoveStringFromList: Temp new key value: %ws\n"), szNewKeyValue);
     719    #endif
     720            pszToken = pszNewToken;
     721        }
     722
     723        /* Last char a delimiter? Cut off ... */
     724        if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
     725            szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
     726
     727        size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
     728
     729    #ifdef DEBUG
     730        _tprintf(_T("RegistryRemoveStringFromList: New provider list: %ws (%u bytes)\n"), szNewKeyValue, iNewLen);
     731    #endif
     732
     733        lRet = RegSetValueExW(hKey, pszKeyValue, 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
     734        if (lRet != ERROR_SUCCESS)
     735            _tprintf(_T("RegistryRemoveStringFromList: RegSetValueEx failed with %ld!\n"), lRet);
     736    }
     737
     738    RegCloseKey(hKey);
     739    return (lRet == ERROR_SUCCESS) ? EXIT_OK : EXIT_FAIL;
     740}
     741
     742/**
     743 * Adds a network provider with a specified order to the system.
     744 *
     745 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     746 * @param   pszProvider         Name of network provider to add.
     747 * @param   uiOrder             Position in list (zero-based) of where to add.
     748 */
     749int AddNetworkProvider(const TCHAR *pszProvider, unsigned int uiOrder)
     750{
     751    _tprintf(_T("Adding network provider \"%ws\" (Order = %u) ...\n"), pszProvider, uiOrder);
     752    int rc = RegistryAddStringToList(_T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
     753                                     _T("ProviderOrder"),
     754                                     pszProvider, uiOrder, VBOX_REG_STRINGLIST_NONE /* No flags set */);
     755    if (rc == EXIT_OK)
     756        _tprintf(_T("Network provider successfully added!\n"));
    1758757    return rc;
    1759758}
    1760759
    1761 int RemoveStringFromMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToRemove)
    1762 {
    1763     // @todo Make string sizes dynamically allocated!
    1764 
    1765     TCHAR szKeyValue[1024];
    1766     HKEY hkey;
    1767     DWORD disp, dwType;
    1768     int rc;
    1769 
    1770     TCHAR *pszKey = a_pszSubKey;
    1771 
    1772     _tprintf(_T("Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), a_pszValueToRemove, a_pszSubKey, a_pszKeyValue);
    1773 
    1774     rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp);
    1775     if (rc != ERROR_SUCCESS)
    1776     {
    1777         _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), pszKey, rc);
    1778         return EXIT_FAIL;
    1779     }
    1780     DWORD cbKeyValue = sizeof(szKeyValue);
    1781 
    1782     rc = RegQueryValueEx(hkey, a_pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
    1783     if (rc != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
    1784     {
    1785         _tprintf(_T("RegQueryValueEx failed with %d dwType = 0x%x!\n"), rc, dwType);
    1786         return EXIT_FAIL;
    1787     }
    1788 
    1789 #ifdef _DEBUG
    1790     _tprintf(_T("Current key len: %d\n"), cbKeyValue);
    1791 #endif
    1792 
    1793     TCHAR szCurString[1024] = { 0 };
    1794     TCHAR szFinalString[1024] = { 0 };
    1795     int iIndex = 0;
    1796     int iNewIndex = 0;
    1797     for (int i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
    1798     {
    1799         if (szKeyValue[i] != _T('\0'))
    1800             szCurString[iIndex++] = szKeyValue[i];
    1801 
    1802         if ((!szKeyValue[i] == _T('\0')) && szKeyValue[i + 1] == _T('\0'))
    1803         {
    1804             if (NULL == wcsstr(szCurString, a_pszValueToRemove))
    1805             {
    1806                 wcscat(&szFinalString[iNewIndex], szCurString);
    1807 
    1808                 if (iNewIndex == 0)
    1809                     iNewIndex = iIndex;
    1810                 else iNewIndex += iIndex;
    1811 
    1812                 szFinalString[++iNewIndex] = _T('\0');
    1813             }
    1814 
    1815             iIndex = 0;
    1816             ZeroMemory( szCurString, sizeof(szCurString));
    1817         }
    1818     }
    1819 
    1820     szFinalString[++iNewIndex] = _T('\0');
    1821 
    1822 #ifdef _DEBUG
    1823     _tprintf(_T("New key len: %d\n"), iNewIndex * sizeof(TCHAR));
    1824     _tprintf(_T("New key value: %ws\n"), szFinalString);
    1825 #endif
    1826 
    1827     rc = RegSetValueExW(hkey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR));
    1828 
    1829     if (rc != ERROR_SUCCESS)
    1830     {
    1831         _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
    1832         return EXIT_FAIL;
    1833     }
    1834 
    1835     rc = RegCloseKey(hkey);
    1836 
    1837     if (rc == ERROR_SUCCESS)
    1838     {
    1839         _tprintf(_T("Value successfully removed!\n"), rc);
    1840         rc = EXIT_OK;
    1841     }
    1842 
     760/**
     761 * Removes a network provider from the system.
     762 *
     763 * @return  Exit code (EXIT_OK, EXIT_FAIL)
     764 * @param   pszProvider         Name of network provider to remove.
     765 */
     766int RemoveNetworkProvider(const TCHAR *pszProvider)
     767{
     768    _tprintf(_T("Removing network provider \"%ws\" ...\n"), pszProvider);
     769    int rc = RegistryRemoveStringFromList(_T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"),
     770                                          _T("ProviderOrder"),
     771                                          pszProvider);
     772    if (rc == EXIT_OK)
     773        _tprintf(_T("Network provider successfully removed!\n"));
    1843774    return rc;
    1844775}
    1845776
    1846 int CreateService (TCHAR* a_pszStartStopName,
    1847                    TCHAR* a_pszDisplayName,
    1848                    int a_iServiceType,
    1849                    int a_iStartType,
    1850                    TCHAR* a_pszBinPath,
    1851                    TCHAR* a_pszLoadOrderGroup,
    1852                    TCHAR* a_pszDependencies,
    1853                    TCHAR* a_pszLogonUser,
    1854                    TCHAR* a_pszLogonPw)
     777int CreateService(const TCHAR *pszStartStopName,
     778                  const TCHAR *pszDisplayName,
     779                  int iServiceType,
     780                  int iStartType,
     781                  const TCHAR *pszBinPath,
     782                  const TCHAR *pszLoadOrderGroup,
     783                  const TCHAR *pszDependencies,
     784                  const TCHAR *pszLogonUser,
     785                  const TCHAR *pszLogonPassword)
    1855786{
    1856787    int rc = ERROR_SUCCESS;
    1857788
    1858     _tprintf(_T("Installing service %ws (%ws) ...\n"), a_pszDisplayName, a_pszStartStopName);
     789    _tprintf(_T("Installing service %ws (%ws) ...\n"), pszDisplayName, pszStartStopName);
    1859790
    1860791    SC_HANDLE hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
     
    1865796    }
    1866797
    1867     /* Fixup end of multistring */
    1868     TCHAR szDepend[ _MAX_PATH ] = { 0 };        /* @todo Use dynamically allocated string here! */
    1869     if (a_pszDependencies != NULL)
    1870     {
    1871         _tcsnccpy (szDepend, a_pszDependencies, wcslen(a_pszDependencies));
     798    /* Fixup end of multistring. */
     799    TCHAR szDepend[ _MAX_PATH ] = { 0 }; /* @todo Use dynamically allocated string here! */
     800    if (pszDependencies != NULL)
     801    {
     802        _tcsnccpy (szDepend, pszDependencies, wcslen(pszDependencies));
    1872803        DWORD len = (DWORD)wcslen (szDepend);
    1873804        szDepend [len + 1] = 0;
    1874805
    1875         /* Replace comma separator on null separator */
     806        /* Replace comma separator on null separator. */
    1876807        for (DWORD i = 0; i < len; i++)
    1877808        {
     
    1882813
    1883814    DWORD dwTag = 0xDEADBEAF;
    1884     SC_HANDLE hService = CreateService (hSCManager,             // SCManager database
    1885                                         a_pszStartStopName,     // name of service
    1886                                         a_pszDisplayName,       // name to display
    1887                                         SERVICE_ALL_ACCESS,     // desired access
    1888                                         a_iServiceType,         // service type
    1889                                         a_iStartType,           // start type
    1890                                         SERVICE_ERROR_NORMAL,   // error control type
    1891                                         a_pszBinPath,           // service's binary
    1892                                         a_pszLoadOrderGroup,    // ordering group
    1893                                         (a_pszLoadOrderGroup != NULL) ? &dwTag : NULL,    // tag identifier
    1894                                         (a_pszDependencies != NULL) ? szDepend : NULL,    // dependencies
    1895                                         (a_pszLogonUser != NULL) ? a_pszLogonUser: NULL,  // account
    1896                                         (a_pszLogonPw != NULL) ? a_pszLogonPw : NULL);    // password
     815    SC_HANDLE hService = CreateService (hSCManager,           /* SCManager database handle. */
     816                                        pszStartStopName,     /* Name of service. */
     817                                        pszDisplayName,       /* Name to display. */
     818                                        SERVICE_ALL_ACCESS,   /* Desired access. */
     819                                        iServiceType,         /* Service type. */
     820                                        iStartType,           /* Start type. */
     821                                        SERVICE_ERROR_NORMAL, /* Error control type. */
     822                                        pszBinPath,           /* Service's binary. */
     823                                        pszLoadOrderGroup,    /* Ordering group. */
     824                                        (pszLoadOrderGroup != NULL) ? &dwTag : NULL,           /* Tag identifier. */
     825                                        (pszDependencies != NULL) ? szDepend : NULL,           /* Dependencies. */
     826                                        (pszLogonUser != NULL) ? pszLogonUser: NULL,           /* Account. */
     827                                        (pszLogonPassword != NULL) ? pszLogonPassword : NULL); /* Password. */
    1897828    if (NULL == hService)
    1898829    {
     
    1905836            _tprintf(_T("Service already exists. No installation required. Updating the service config.\n"));
    1906837
    1907             hService = OpenService (hSCManager,             // SCManager database
    1908                                     a_pszStartStopName,     // name of service
    1909                                     SERVICE_ALL_ACCESS);    // desired access
     838            hService = OpenService (hSCManager,          /* SCManager database handle. */
     839                                    pszStartStopName,    /* Name of service. */
     840                                    SERVICE_ALL_ACCESS); /* Desired access. */
    1910841            if (NULL == hService)
    1911842            {
     
    1915846            else
    1916847            {
    1917                 BOOL Result = ChangeServiceConfig (hService,               // service handle
    1918                                                    a_iServiceType,         // service type
    1919                                                    a_iStartType,           // start type
    1920                                                    SERVICE_ERROR_NORMAL,   // error control type
    1921                                                    a_pszBinPath,           // service's binary
    1922                                                    a_pszLoadOrderGroup,    // ordering group
    1923                                                    (a_pszLoadOrderGroup != NULL) ? &dwTag : NULL,    // tag identifier
    1924                                                    (a_pszDependencies != NULL) ? szDepend : NULL,    // dependencies
    1925                                                    (a_pszLogonUser != NULL) ? a_pszLogonUser: NULL,  // account
    1926                                                    (a_pszLogonPw != NULL) ? a_pszLogonPw : NULL,     // password
    1927                                                    a_pszDisplayName);      // name to display
    1928                 if (Result)
    1929                 {
     848                BOOL fResult = ChangeServiceConfig (hService,            /* Service handle. */
     849                                                   iServiceType,         /* Service type. */
     850                                                   iStartType,           /* Start type. */
     851                                                   SERVICE_ERROR_NORMAL, /* Error control type. */
     852                                                   pszBinPath,           /* Service's binary. */
     853                                                   pszLoadOrderGroup,    /* Ordering group. */
     854                                                   (pszLoadOrderGroup != NULL) ? &dwTag : NULL,          /* Tag identifier. */
     855                                                   (pszDependencies != NULL) ? szDepend : NULL,          /* Dependencies. */
     856                                                   (pszLogonUser != NULL) ? pszLogonUser: NULL,          /* Account. */
     857                                                   (pszLogonPassword != NULL) ? pszLogonPassword : NULL, /* Password. */
     858                                                   pszDisplayName);      /* Name to display. */
     859                if (fResult)
    1930860                    _tprintf(_T("The service config has been successfully updated.\n"));
    1931                 }
    1932861                else
    1933862                {
     
    1935864                    _tprintf(_T("Could not change service config! Error: %ld\n"), dwErr);
    1936865                }
    1937 
    1938                 CloseServiceHandle (hService);
    1939             }
    1940 
    1941             /* This entire branch do not return an error to avoid installations failures,
     866                CloseServiceHandle(hService);
     867            }
     868
     869            /*
     870             * This entire branch do not return an error to avoid installations failures,
    1942871             * if updating service parameters. Better to have a running system with old
    1943872             * parameters and the failure information in the installation log.
     
    1976905}
    1977906
    1978 int DelService (TCHAR* a_pszStartStopName)
     907int DelService(const TCHAR *pszStartStopName)
    1979908{
    1980909    int rc = ERROR_SUCCESS;
    1981910
    1982     _tprintf(_T("Deleting service '%ws' ...\n"), a_pszStartStopName);
     911    _tprintf(_T("Deleting service '%ws' ...\n"), pszStartStopName);
    1983912
    1984913    SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
     
    1991920    else
    1992921    {
    1993         hService = OpenService(hSCManager, a_pszStartStopName, SERVICE_ALL_ACCESS);
     922        hService = OpenService(hSCManager, pszStartStopName, SERVICE_ALL_ACCESS);
    1994923        if (NULL == hService)
    1995924        {
    1996             _tprintf(_T("Could not open service '%ws'! Error: %ld\n"), a_pszStartStopName, GetLastError());
     925            _tprintf(_T("Could not open service '%ws'! Error: %ld\n"), pszStartStopName, GetLastError());
    1997926            rc = EXIT_FAIL;
    1998927        }
     
    2011940                case ERROR_SERVICE_MARKED_FOR_DELETE:
    2012941
    2013                     _tprintf(_T("Service '%ws' already marked for deletion.\n"), a_pszStartStopName);
     942                    _tprintf(_T("Service '%ws' already marked for deletion.\n"), pszStartStopName);
    2014943                    break;
    2015944
    2016945                default:
    2017946
    2018                     _tprintf(_T("Could not delete service '%ws'! Error: %ld\n"), a_pszStartStopName, GetLastError());
     947                    _tprintf(_T("Could not delete service '%ws'! Error: %ld\n"), pszStartStopName, GetLastError());
    2019948                    rc = EXIT_FAIL;
    2020949                    break;
     
    2023952            else
    2024953            {
    2025                 _tprintf(_T("Service '%ws' successfully removed!\n"), a_pszStartStopName);
     954                _tprintf(_T("Service '%ws' successfully removed!\n"), pszStartStopName);
    2026955            }
    2027956            UnlockServiceDatabase(hSCManager);
     
    20741003}
    20751004
    2076 void PrintHelp (void)
    2077 {
    2078     _tprintf(_T("Installs / Uninstalls VirtualBox drivers for Windows XP/2K/Vista\n"));
     1005void PrintHelp(void)
     1006{
     1007    _tprintf(_T("VirtualBox Guest Additions Installation Helper for Windows\n"));
    20791008    _tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
    20801009    _tprintf(_T("Syntax:\n"));
    2081     _tprintf(_T("\tTo install: VBoxDrvInst /i <HardwareID> <INF-File> <Device Class>\n"));
    2082     _tprintf(_T("\tTo uninstall: VBoxDrvInst /u <HardwareID>\n"));
    2083     _tprintf(_T("\tTo execute an INF-File: VBoxDrvInst /inf <INF-File>\n"));
    2084     _tprintf(_T("\tTo add a network provider: VBoxDrvInst /addnetprovider <Name> [Order]\n\n"));
    2085     _tprintf(_T("\tTo write registry values: VBoxDrvInst /registry write <root> <sub key> <key name> <key type> <value> [type] [size]\n\n"));
    2086     _tprintf(_T("Examples:\n"));
    2087     _tprintf(_T("\tVBoxDrvInst /i \"PCI\\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00\" VBoxVideo.inf Display\n"));
    2088     _tprintf(_T("\tVBoxDrvInst /addnetprovider VboxSF 1\n\n"));
    2089 }
    2090 
    2091 int __cdecl _tmain (int argc, _TCHAR* argv[])
    2092 {
    2093     int rc;
     1010    _tprintf(_T("\n"));
     1011    _tprintf(_T("Drivers:\n"));
     1012    _tprintf(_T("\tVBoxDrvInst         driver install <inf-file>\n"));
     1013    _tprintf(_T("\tVBoxDrvInst         driver uninstall <inf-file>\n"));
     1014    _tprintf(_T("\tVBoxDrvInst         driver executeinf <inf-file>\n"));
     1015    _tprintf(_T("\n"));
     1016    _tprintf(_T("Network Provider:\n"));
     1017    _tprintf(_T("\tVBoxDrvInst         netprovider add <name> [order]\n"));
     1018    _tprintf(_T("\tVBoxDrvInst         netprovider remove <name>\n"));
     1019    _tprintf(_T("\n"));
     1020    _tprintf(_T("Registry:\n"));
     1021    _tprintf(_T("\tVBoxDrvInst         registry write <root> <sub key>\n")
     1022             _T("\t                    <key name> <key type> <value>\n")
     1023             _T("\t                    [type] [size]\n"));
     1024    _tprintf(_T("\tVBoxDrvInst         registry addmultisz <root> <sub key>\n")
     1025             _T("\t                    <value> [order]\n"));
     1026    _tprintf(_T("\tVBoxDrvInst         registry delmultisz <root> <sub key>\n")
     1027             _T("\t                    <key name> <value to remove>\n"));
     1028    /** @todo Add "service" category! */
     1029    _tprintf(_T("\n"));
     1030}
     1031
     1032int __cdecl _tmain(int argc, _TCHAR *argv[])
     1033{
     1034    int rc = EXIT_USAGE;
     1035
    20941036    OSVERSIONINFO OSinfo;
    2095 
    2096     _TCHAR szHwID[_MAX_PATH] = { 0 }; /* Hardware ID. */
    2097     _TCHAR szINF[_MAX_PATH] = { 0 }; /* Complete path to INF file.*/
    2098     _TCHAR szDevClass[_MAX_PATH] = { 0 }; /* Device class. */
    2099     _TCHAR szProvider[_MAX_PATH] = { 0 }; /* The network provider name for the registry. */
    2100 
    2101     rc = LoadAPICalls();
    2102     if (   rc == ERROR_SUCCESS
    2103         && argc >= 2)
    2104     {
    2105         OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
    2106         GetVersionEx(&OSinfo);
    2107 
    2108         if (0 == _tcsicmp(argv[1], _T("/i")))
    2109         {
    2110             if (argc < 5)
    2111             {
    2112                 rc = EXIT_USAGE;
    2113             }
    2114             else
     1037    OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
     1038    GetVersionEx(&OSinfo);
     1039
     1040    if (argc >= 2)
     1041    {
     1042        if (   !_tcsicmp(argv[1], _T("driver"))
     1043            && argc >= 3)
     1044        {
     1045            _TCHAR szINF[_MAX_PATH] = { 0 }; /* Complete path to INF file.*/
     1046            if (   (   !_tcsicmp(argv[2], _T("install"))
     1047                    || !_tcsicmp(argv[2], _T("uninstall")))
     1048                && argc == 4)
    21151049            {
    21161050                if (OSinfo.dwMajorVersion < 5)
    21171051                {
    2118                     _tprintf(_T("ERROR: Platform not supported yet!\n"));
    2119                     rc = ERROR_NOT_SUPPORTED;
     1052                    _tprintf(_T("ERROR: Platform not supported for driver (un)installation!\n"));
     1053                    rc = EXIT_FAIL;
    21201054                }
    2121 
    2122                 if (rc == ERROR_SUCCESS)
     1055                else
    21231056                {
    2124                     _stprintf(szHwID, _T("%ws"), argv[2]);
    21251057                    _stprintf(szINF, _T("%ws"), argv[3]);
    2126                     _stprintf(szDevClass, _T("%ws"), argv[4]);
    2127 
    2128                     rc = InstallDriver(szINF, szHwID, szDevClass);
     1058                    rc = VBoxInstallDriver(!_tcsicmp(argv[2], _T("install")) ? TRUE : FALSE, szINF, FALSE);
    21291059                }
    21301060            }
    2131         }
    2132         else if (0 == _tcsicmp(argv[1], _T("/u")))
    2133         {
    2134             if (argc < 3)
    2135             {
    2136                 rc = EXIT_USAGE;
    2137             }
    2138             else
    2139             {
    2140                 if (OSinfo.dwMajorVersion < 5)
     1061            else if (   !_tcsicmp(argv[2], _T("executeinf"))
     1062                     && argc == 4)
     1063            {
     1064                _stprintf(szINF, _T("%ws"), argv[3]);
     1065                rc = ExecuteInfFile(_T("DefaultInstall"), 132, szINF);
     1066            }
     1067        }
     1068        else if (   !_tcsicmp(argv[1], _T("netprovider"))
     1069                 && argc >= 3)
     1070        {
     1071            _TCHAR szProvider[_MAX_PATH] = { 0 }; /* The network provider name for the registry. */
     1072            if (  !_tcsicmp(argv[2], _T("add"))
     1073                && argc >= 4)
     1074            {
     1075                int iOrder = 0;
     1076                if (argc > 4)
     1077                    iOrder = _ttoi(argv[4]);
     1078                _stprintf(szProvider, _T("%ws"), argv[3]);
     1079                rc = AddNetworkProvider(szProvider, iOrder);
     1080            }
     1081            else if (  !_tcsicmp(argv[2], _T("remove"))
     1082                && argc >= 4)
     1083            {
     1084                _stprintf(szProvider, _T("%ws"), argv[3]);
     1085                rc = RemoveNetworkProvider(szProvider);
     1086            }
     1087        }
     1088        else if (   !_tcsicmp(argv[1], _T("service"))
     1089                 && argc >= 3)
     1090        {
     1091            if (   !_tcsicmp(argv[2], _T("create"))
     1092                && argc >= 8)
     1093            {
     1094                rc = CreateService(argv[3],
     1095                                   argv[4],
     1096                                   _ttoi(argv[5]),
     1097                                   _ttoi(argv[6]),
     1098                                   argv[7],
     1099                                   (argc > 8) ? argv[8] : NULL,
     1100                                   (argc > 9) ? argv[9] : NULL,
     1101                                   (argc > 10) ? argv[10] : NULL,
     1102                                   (argc > 11) ? argv[11] : NULL);
     1103            }
     1104            else if (   !_tcsicmp(argv[2], _T("delete"))
     1105                     && argc == 4)
     1106            {
     1107                rc = DelService(argv[3]);
     1108            }
     1109        }
     1110        else if (   !_tcsicmp(argv[1], _T("registry"))
     1111                 && argc >= 3)
     1112        {
     1113            /** @todo add a handleRegistry(argc, argv) method to keep things cleaner */
     1114            if (   !_tcsicmp(argv[2], _T("addmultisz"))
     1115                && argc == 7)
     1116            {
     1117                rc = RegistryAddStringToMultiSZ(argv[3], argv[4], argv[5], _ttoi(argv[6]));
     1118            }
     1119            else if (   !_tcsicmp(argv[2], _T("delmultisz"))
     1120                     && argc == 6)
     1121            {
     1122                rc = RegistryRemoveStringFromMultiSZ(argv[3], argv[4], argv[5]);
     1123            }
     1124            else if (   !_tcsicmp(argv[2], _T("write"))
     1125                     && argc >= 8)
     1126            {
     1127                HKEY hRootKey = HKEY_LOCAL_MACHINE;  /** @todo needs to be expanded (argv[3]) */
     1128                DWORD dwValSize;
     1129                BYTE *pbVal = NULL;
     1130                DWORD dwVal;
     1131
     1132                if (argc > 8)
    21411133                {
    2142                     _tprintf(_T("ERROR: Platform not supported yet!\n"));
    2143                     rc = ERROR_NOT_SUPPORTED;
     1134                    if (!_tcsicmp(argv[8], _T("dword")))
     1135                    {
     1136                        dwVal = _ttol(argv[7]);
     1137                        pbVal = (BYTE*)&dwVal;
     1138                        dwValSize = sizeof(DWORD);
     1139                    }
    21441140                }
    2145 
    2146                 if (rc == ERROR_SUCCESS)
     1141                if (pbVal == NULL) /* By default interpret value as string */
    21471142                {
    2148                     _stprintf(szHwID, _T("%ws"), argv[2]);
    2149                     rc = UninstallDriver(szHwID);
     1143                    pbVal = (BYTE*)argv[7];
     1144                    dwValSize = _tcslen(argv[7]);
    21501145                }
    2151             }
    2152         }
    2153         else if (0 == _tcsicmp(argv[1], _T("/inf")))
    2154         {
    2155             if (argc < 3)
    2156             {
    2157                 rc = EXIT_USAGE;
    2158             }
    2159             else
    2160             {
    2161                 if (OSinfo.dwMajorVersion < 5)
    2162                 {
    2163                     _tprintf(_T("ERROR: Platform not supported yet!\n"));
    2164                     rc = ERROR_NOT_SUPPORTED;
    2165                 }
    2166 
    2167                 if (rc == ERROR_SUCCESS)
    2168                 {
    2169                     _stprintf(szINF, _T("%ws"), argv[2]);
    2170                     rc = ExecuteInfFile(_T("DefaultInstall"), 132, szINF);
    2171                 }
    2172             }
    2173         }
    2174         else if (0 == _tcsicmp(argv[1], _T("/addnetprovider")))
    2175         {
    2176             if (argc < 3)
    2177             {
    2178                 rc = EXIT_USAGE;
    2179             }
    2180             else
    2181             {
    2182 
    2183                 int iOrder = 0;
    2184                 if (argc > 3)
    2185                     iOrder = _ttoi(argv[3]);
    2186                 _stprintf(szProvider, _T("%ws"), argv[2]);
    2187                 rc = AddNetworkProvider(szProvider, iOrder);
    2188             }
    2189         }
    2190         else if (0 == _tcsicmp(argv[1], _T("/reg_addmultisz")))
    2191         {
    2192             if (argc < 6)
    2193             {
    2194                 rc = EXIT_USAGE;
    2195             }
    2196             else
    2197             {
    2198                 rc = AddStringToMultiSZ(argv[2], argv[3], argv[4], _ttoi(argv[5]));
    2199             }
    2200         }
    2201         else if (0 == _tcsicmp(argv[1], _T("/reg_delmultisz")))
    2202         {
    2203             if (argc < 5)
    2204             {
    2205                 rc = EXIT_USAGE;
    2206             }
    2207             else
    2208             {
    2209                 rc = RemoveStringFromMultiSZ(argv[2], argv[3], argv[4]);
    2210             }
    2211         }
    2212         else if (0 == _tcsicmp(argv[1], _T("/createsvc")))
    2213         {
    2214             if (argc < 7)
    2215             {
    2216                 rc = EXIT_USAGE;
    2217             }
    2218             else
    2219             {
    2220                 rc = CreateService(
    2221                          argv[2],
    2222                          argv[3],
    2223                          _ttoi(argv[4]),
    2224                          _ttoi(argv[5]),
    2225                          argv[6],
    2226                          (argc > 7) ? argv[7] : NULL,
    2227                          (argc > 8) ? argv[8] : NULL,
    2228                          (argc > 9) ? argv[9] : NULL,
    2229                          (argc > 10) ? argv[10] : NULL);
    2230             }
    2231         }
    2232         else if (0 == _tcsicmp(argv[1], _T("/delsvc")))
    2233         {
    2234             if (argc < 3)
    2235             {
    2236                 rc = EXIT_USAGE;
    2237             }
    2238             else
    2239             {
    2240                 rc = DelService(argv[2]);
    2241             }
    2242         }
    2243         else if (0 == _tcsicmp(argv[1], _T("/registry")))
    2244         {
    2245             if (argc < 8)
    2246             {
    2247                 rc = EXIT_USAGE;
    2248             }
    2249             else
    2250             {
    2251                 /** @todo add a handleRegistry(argc, argv) method to keep things cleaner */
    2252                 if (0 == _tcsicmp(argv[2], _T("write")))
    2253                 {
    2254                     HKEY hRootKey = HKEY_LOCAL_MACHINE;  /** @todo needs to be expanded (argv[3]) */
    2255                     DWORD dwValSize;
    2256                     BYTE *pbVal = NULL;
    2257                     DWORD dwVal;
    2258 
    2259                     if (argc > 8)
    2260                     {
    2261                         if (0 == _tcsicmp(argv[8], _T("dword")))
    2262                         {
    2263                             dwVal = _ttol(argv[7]);
    2264                             pbVal = (BYTE*)&dwVal;
    2265                             dwValSize = sizeof(DWORD);
    2266                         }
    2267                     }
    2268                     if (pbVal == NULL) /* By default interpret value as string */
    2269                     {
    2270                         pbVal = (BYTE*)argv[7];
    2271                         dwValSize = _tcslen(argv[7]);
    2272                     }
    2273                     if (argc > 9)
    2274                         dwValSize = _ttol(argv[9]);      /* Get the size in bytes of the value we want to write */
    2275                     rc = RegistryWrite(hRootKey,
    2276                                        argv[4],          /* Sub key */
    2277                                        argv[5],          /* Value name */
    2278                                        REG_BINARY,       /** @todo needs to be expanded (argv[6]) */
    2279                                        pbVal,            /* The value itself */
    2280                                        dwValSize);       /* Size of the value */
    2281                 }
    2282                 /*else if (0 == _tcsicmp(argv[2], _T("read")))
    2283                 {
    2284                 }
    2285                 else if (0 == _tcsicmp(argv[2], _T("del")))
    2286                 {
    2287                 }*/
    2288                 else
    2289                     rc = EXIT_USAGE;
    2290             }
    2291         }
    2292 #ifdef VBOX_WITH_WDDM
    2293         else if (0 == _tcsicmp(argv[1], _T("/matchdrv")))
    2294         {
    2295             if (argc < 4)
    2296             {
    2297                 rc = EXIT_USAGE;
    2298             }
    2299             else
    2300             {
    2301                 if (OSinfo.dwMajorVersion < 5)
    2302                 {
    2303                     _tprintf(_T("ERROR: Platform not supported yet!\n"));
    2304                     rc = ERROR_NOT_SUPPORTED;
    2305                 }
    2306 
    2307                 if (rc == ERROR_SUCCESS)
    2308                 {
    2309                     _stprintf(szHwID, _T("%ws"), argv[2]);
    2310                     rc = MatchDriver(szHwID, argv[3]);
    2311                 }
    2312             }
    2313         }
     1146                if (argc > 9)
     1147                    dwValSize = _ttol(argv[9]);      /* Get the size in bytes of the value we want to write */
     1148                rc = RegistryWrite(hRootKey,
     1149                                   argv[4],          /* Sub key */
     1150                                   argv[5],          /* Value name */
     1151                                   REG_BINARY,       /** @todo needs to be expanded (argv[6]) */
     1152                                   pbVal,            /* The value itself */
     1153                                   dwValSize);       /* Size of the value */
     1154            }
     1155#if 0
     1156            else if (!_tcsicmp(argv[2], _T("read")))
     1157            {
     1158            }
     1159            else if (!_tcsicmp(argv[2], _T("del")))
     1160            {
     1161            }
    23141162#endif
     1163        }
     1164        else if (!_tcsicmp(argv[1], _T("--version")))
     1165        {
     1166            _tprintf(_T("%d.%d.%d.%d\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
     1167            rc = EXIT_OK;
     1168        }
     1169        else if (   !_tcsicmp(argv[1], _T("--help"))
     1170                 || !_tcsicmp(argv[1], _T("/help"))
     1171                 || !_tcsicmp(argv[1], _T("/h"))
     1172                 || !_tcsicmp(argv[1], _T("/?")))
     1173        {
     1174            PrintHelp();
     1175            rc = EXIT_OK;
     1176        }
    23151177    }
    23161178
    23171179    if (rc == EXIT_USAGE)
    2318         PrintHelp();
    2319 
    2320     FreeAPICalls();
     1180        _tprintf(_T("No or wrong parameters given! Please consult the help (\"--help\" or \"/?\") for more information.\n"));
     1181
    23211182    return rc;
    23221183}
     1184
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