VBoxDrvInst.cpp revision 78a072e1b56619e3230735ae073668311232ec94
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
Abstract:
Command-line interface for installing / uninstalling device drivers
with a given Hardware-ID (and .INF-file).
--*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <setupapi.h>
#include <newdev.h>
#include <regstr.h>
#include <cfgmgr32.h>
#include <devguid.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
/*#define _DEBUG*/
struct IdEntry
{
};
/* @todo Split this program into several modules:
- Main
- Utility functions
- Dynamic API loading
- Installation / uninstallation routines
- ...
*/
/* Exit codes */
#define EXIT_OK (0)
#define EXIT_REBOOT (1)
#define EXIT_FAIL (2)
#define EXIT_USAGE (3)
/* Dynamic loaded libs */
/* Function pointers for dynamic loading of some API calls NT4 hasn't ... */
typedef BOOL (WINAPI *fnSetupDiCreateDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceName, LPGUID ClassGuid, PCTSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
typedef BOOL (WINAPI *fnSetupDiOpenDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceInstanceId, HWND hwndParent, DWORD OpenFlags, PSP_DEVINFO_DATA DeviceInfoData);
typedef BOOL (WINAPI *fnSetupDiEnumDeviceInfo) (HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData);
/***/
typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoListEx) (LPGUID ClassGuid, HWND hwndParent, PCTSTR MachineName, PVOID Reserved);
typedef BOOL (WINAPI *fnSetupDiDestroyDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
typedef BOOL (WINAPI *fnSetupDiGetDeviceInfoListDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData);
/***/
typedef BOOL (WINAPI *fnSetupDiSetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, CONST BYTE *PropertyBuffer, DWORD PropertyBufferSize);
typedef BOOL (WINAPI *fnSetupDiGetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer,
/***/
typedef BOOL (WINAPI *fnSetupDiCallClassInstaller) (DI_FUNCTION InstallFunction, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData);
typedef BOOL (WINAPI *fnSetupDiClassGuidsFromNameEx) (PCTSTR ClassName, LPGUID ClassGuidList, DWORD ClassGuidListSize, PDWORD RequiredSize, PCTSTR MachineName, PVOID Reserved);
typedef HDEVINFO (WINAPI *fnSetupDiGetClassDevsEx) (LPGUID ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags, HDEVINFO DeviceInfoSet, PCTSTR MachineName, PVOID Reserved);
typedef BOOL (WINAPI *fnSetupDiSetClassInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_CLASSINSTALL_HEADER ClassInstallParams, DWORD ClassInstallParamsSize);
typedef BOOL (WINAPI *fnSetupDiGetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
typedef HKEY (WINAPI *fnSetupDiOpenDevRegKey) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired);
typedef BOOL (WINAPI *fnSetupDiBuildDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
typedef BOOL (WINAPI *fnSetupDiEnumDriverInfo) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType, DWORD MemberIndex, PSP_DRVINFO_DATA DriverInfoData);
typedef BOOL (WINAPI *fnSetupDiGetDriverInfoDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData, PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
typedef BOOL (WINAPI *fnSetupDiSetSelectedDriver) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData);
typedef BOOL (WINAPI *fnSetupDiSetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
typedef CONFIGRET (WINAPI *fnCM_Get_Device_ID_Ex) (DEVINST dnDevInst, PTCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine);
typedef BOOL (WINAPI* fnSetupCopyOEMInf) (PCTSTR SourceInfFileName, PCTSTR OEMSourceMediaLocation, DWORD OEMSourceMediaType, DWORD CopyStyle, PTSTR DestinationInfFileName,
typedef BOOL (WINAPI* fnUpdateDriverForPlugAndPlayDevices) (HWND hwndParent, LPCTSTR HardwareId, LPCTSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
{ \
}
int LoadAPICalls ()
{
int rc = ERROR_SUCCESS;
#ifdef _DEBUG
#endif
/* Use unicode calls where available. */
{
if (NULL == g_hSetupAPI)
{
}
else
{
g_pfnSetupDiCreateDeviceInfoList = (fnSetupDiCreateDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoList");
g_pfnSetupDiCreateDeviceInfo = (fnSetupDiCreateDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoW");
g_pfnSetupDiSetDeviceRegistryProperty = (fnSetupDiSetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceRegistryPropertyW");
g_pfnSetupDiCallClassInstaller = (fnSetupDiCallClassInstaller)GetProcAddress(g_hSetupAPI, "SetupDiCallClassInstaller");
g_pfnSetupDiDestroyDeviceInfoList = (fnSetupDiDestroyDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDeviceInfoList");
g_pfnSetupDiClassGuidsFromNameEx = (fnSetupDiClassGuidsFromNameEx)GetProcAddress(g_hSetupAPI, "SetupDiClassGuidsFromNameExW");
g_pfnSetupDiGetDeviceRegistryProperty = (fnSetupDiGetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceRegistryPropertyW");
g_pfnSetupDiGetClassDevsEx = (fnSetupDiGetClassDevsEx)GetProcAddress(g_hSetupAPI, "SetupDiGetClassDevsExW");
g_pfnSetupDiCreateDeviceInfoListEx = (fnSetupDiCreateDeviceInfoListEx)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoListExW");
g_pfnSetupDiOpenDeviceInfo = (fnSetupDiOpenDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiOpenDeviceInfoW");
g_pfnSetupDiGetDeviceInfoListDetail = (fnSetupDiGetDeviceInfoListDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInfoListDetailW");
g_pfnSetupDiEnumDeviceInfo = (fnSetupDiEnumDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDeviceInfo");
g_pfnSetupDiSetClassInstallParams = (fnSetupDiSetClassInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetClassInstallParamsW");
g_pfnSetupDiGetDeviceInstallParams = (fnSetupDiGetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInstallParamsW");
g_pfnSetupDiOpenDevRegKey = (fnSetupDiOpenDevRegKey)GetProcAddress(g_hSetupAPI, "SetupDiOpenDevRegKey");
g_pfnSetupDiBuildDriverInfoList = (fnSetupDiBuildDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiBuildDriverInfoList");
g_pfnSetupDiEnumDriverInfo = (fnSetupDiEnumDriverInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDriverInfoW");
g_pfnSetupDiGetDriverInfoDetail = (fnSetupDiGetDriverInfoDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDriverInfoDetailW");
g_pfnSetupDiDestroyDriverInfoList = (fnSetupDiDestroyDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDriverInfoList");
g_pfnSetupDiSetSelectedDriver = (fnSetupDiSetSelectedDriver)GetProcAddress(g_hSetupAPI, "SetupDiSetSelectedDriverW");
g_pfnSetupDiSetDeviceInstallParams = (fnSetupDiSetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceInstallParamsW");
}
if (rc == ERROR_SUCCESS)
{
{
g_pfnUpdateDriverForPlugAndPlayDevices = (fnUpdateDriverForPlugAndPlayDevices)GetProcAddress(g_hNewDev, "UpdateDriverForPlugAndPlayDevicesW");
}
else
{
}
}
if (rc == ERROR_SUCCESS)
{
{
g_pfnCM_Get_Device_ID_Ex = (fnCM_Get_Device_ID_Ex)GetProcAddress(g_hCfgMgr, "CM_Get_Device_ID_ExW");
}
else
{
}
}
}
{
/* Nothing to do here yet. */
}
else /* Other platforms */
{
}
return rc;
}
void FreeAPICalls ()
{
#ifdef _DEBUG
#endif
if (NULL != g_hSetupAPI)
}
{
if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_dwLastError, 0, a_pszMsg, a_dwBufSize, NULL) == 0)
{
return false;
}
else
{
if (p != NULL)
*p = _T('\0');
}
return true;
}
/* @todo Add exception handling instead of crappy goto's! */
{
if (devInfoSet == INVALID_HANDLE_VALUE)
{
return EXIT_FAIL;
}
if (FALSE == g_pfnSetupDiCreateDeviceInfo(devInfoSet, a_pszHwID, &a_devClass, NULL, NULL, DICD_GENERATE_ID, &devInfoData))
{
dwErr = GetLastError();
switch (dwErr)
{
break;
case ERROR_CLASS_MISMATCH:
break;
break;
break;
default:
break;
}
goto InstallCleanup;
}
if (FALSE == g_pfnSetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID, (LPBYTE)a_pszHwID, (DWORD)((_tcsclen(a_pszHwID) + 2) * sizeof(_TCHAR))))
{
dwErr = GetLastError();
goto InstallCleanup;
}
{
dwErr = GetLastError();
goto InstallCleanup;
}
return iRet;
}
{
/* Retrieve GUID of device class */
/* Not used here: g_pfnSetupDiClassNameFromGuidEx( ... ) */
if (FALSE == g_pfnSetupDiClassGuidsFromNameEx(a_pszDevClass, devClassArr, 32, &dwReqSize, NULL, NULL))
{
return EXIT_FAIL;
}
else
{
/* Do not fail if dwReqSize is 0. For whatever reason Windows Server 2008 Core does not have the "Media"
device class installed. Maybe they stripped down too much? :-/ */
if (dwReqSize <= 0)
{
_tprintf(_T("WARNING: No device class with this name found! ReqSize: %ld, Error: %ld\n"), dwReqSize, GetLastError());
}
else
{
}
/* Not needed for now!
if (EXIT_FAIL == CreateDevice (a_pszHwID, devClassArr[0]))
return EXIT_FAIL;*/
}
{
dwErr = GetLastError();
return EXIT_FAIL;
}
/* Extract path from path+INF */
{
if (dwErr == ERROR_NO_SUCH_DEVINST)
{
if (FALSE == g_pfnSetupCopyOEMInf(szInf, szInfPath, SPOST_PATH, 0, szDestInf, sizeof(szDestInf), NULL, NULL))
{
dwErr = GetLastError();
return EXIT_FAIL;
}
return EXIT_OK;
}
switch (dwErr)
{
case ERROR_INVALID_FLAGS:
break;
case ERROR_NO_MORE_ITEMS:
_T(
"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"));
break;
case ERROR_FILE_NOT_FOUND:
break;
case ERROR_IN_WOW64:
_tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!"));
break;
case ERROR_NO_DRIVER_SELECTED:
break;
case ERROR_SECTION_NOT_FOUND:
break;
default:
/* Try error lookup with GetErrorMsg() */
break;
}
return EXIT_FAIL;
}
return EXIT_OK;
}
/*++
Routine Description:
Determine if this is instance id or hardware id and if there's any wildcards
instance ID is prefixed by '@'
wildcards are '*'
Arguments:
Id - ptr to string to check
Return Value:
IdEntry
--*/
{
{
}
{
/* prefix to treat rest of string literally */
}
else
{
/* see if any wild characters exist */
}
return Entry;
}
/*++
Routine Description:
Get an index array pointing to the MultiSz passed in
Arguments:
MultiSz - well formed multi-sz string
Return Value:
array of strings. last entry+1 of array contains NULL
returns NULL on failure
--*/
{
int elements;
{
}
if (!array)
{
return NULL;
}
array++;
if (elements)
{
{
}
}
return array;
}
/*++
Routine Description:
Deletes the string array allocated by GetDevMultiSz/GetRegMultiSz/GetMultiSzIndexArray
Arguments:
Array - pointer returned by GetMultiSzIndexArray
Return Value:
None
--*/
{
if (Array)
{
Array--;
if (Array[0])
{
delete[] Array[0];
}
delete[] Array;
}
}
/*++
Routine Description:
Get a multi-sz device property
and return as an array of strings
Arguments:
Devs - HDEVINFO containing DevInfo
DevInfo - Specific device
Prop - SPDRP_HARDWAREID or SPDRP_COMPATIBLEIDS
Return Value:
array of strings. last entry+1 of array contains NULL
returns NULL on failure
--*/
{
if (!buffer)
{
return NULL;
}
while (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, Prop, &dataType, (LPBYTE)buffer, size, &reqSize))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
goto failed;
}
if (dataType != REG_MULTI_SZ)
{
goto failed;
}
delete[] buffer;
if (!buffer)
{
goto failed;
}
}
if (array)
{
return array;
}
{
delete[] buffer;
}
return NULL;
}
/*++
Routine Description:
Compare a single item against wildcard
I'm sure there's better ways of implementing this
Other than a command-line management tools
it's a bad idea to use wildcards as it implies
eg, it might be tempting to enumerate root\* to
find all root devices, however there is a CfgMgr
API to query status and determine if a device is
root enumerated, which doesn't rely on implementation
details.
Arguments:
Item - item to find match for eg a\abcd\c
MatchEntry - eg *\*bc*\*
Return Value:
TRUE if any match, otherwise FALSE
--*/
{
/* Before attempting anything else,
try and compare everything up to first wild */
//
if (!MatchEntry.szWild)
{
}
{
return FALSE;
}
for (; wildMark[0];)
{
/* If we get here, we're either at or past a wildcard */
{
/* So skip wild chars */
continue;
}
/* Find next wild-card */
if (nextWild)
{
/* Substring */
}
else
{
/* Last portion of match */
{
return FALSE;
}
}
{
/* Scan for either lower or uppercase version of first character */
{
}
if (!scanItem[0])
{
/* Ran out of string */
return FALSE;
}
}
else
{
/* Scan for first character (no case) */
if (!scanItem)
{
/* Ran out of string */
return FALSE;
}
}
/* Try and match the sub-string at wildMark against scanItem */
{
/* Nope, try again */
continue;
}
/* Substring matched */
}
}
/*++
Routine Description:
Compares all strings in Array against Id
Use WildCardMatch to do real compare
Arguments:
Array - pointer returned by GetDevMultiSz
MatchEntry - string to compare against
Return Value:
TRUE if any match, otherwise FALSE
--*/
{
if (Array)
{
while (Array[0])
{
{
return TRUE;
}
Array++;
}
}
return FALSE;
}
/*++
Routine Description:
Generic enumerator for devices that will be passed the following arguments:
<id> [<id>...]
=<class> [<id>...]
where <id> can either be @instance-id, or hardware-id and may contain wildcards
<class> is a class name
Arguments:
BaseName - name of executable
Machine - name of machine to enumerate
Flags - extra enumeration flags (eg DIGCF_PRESENT)
Callback - function to call for each hit
Context - data to pass function for each hit
Return Value:
EXIT_xxxx
--*/
int EnumerateDevices (LPCTSTR BaseName, LPCTSTR Machine, DWORD Flags, int argc, LPTSTR argv[], fnCallback Callback, LPVOID Context)
{
int retcode;
int argIndex;
int skip = 0;
if (!argc)
{
return EXIT_USAGE;
}
if (!templ)
{
goto final;
}
/* Determine if a class is specified */
{
if (!g_pfnSetupDiClassGuidsFromNameEx(argv[skip] + 1, &cls, 1, &numClass, Machine, NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
goto final;
}
if (!numClass)
{
goto final;
}
skip++;
}
{
/* Catch convinient case of specifying a single argument '*' */
skip++;
}
{
/* At least one parameter, but no <id>'s */
}
/* Determine if any instance id's were specified */
/* Note, if =<class> was specified with no id's
we'll mark it as not doSearch
but will go ahead and add them all */
{
{
/* Anything other than simple bInstanceId's require a search */
}
}
{
/* Add all id's to list
If there's a class, filter on specified class */
devs = g_pfnSetupDiGetClassDevsEx(numClass ? &cls : NULL, NULL, NULL, (numClass ? 0 : DIGCF_ALLCLASSES) | Flags, NULL, Machine, NULL);
}
else
{
/* Blank list, we'll add instance id's by hand */
}
if (devs == INVALID_HANDLE_VALUE)
{
goto final;
}
{
/* Add explicit instances to list (even if enumerated all,
this gets around DIGCF_PRESENT)
do this even if wildcards appear to be detected since they
might actually be part of the instance ID of a non-present device */
{
}
}
{
goto final;
}
/* Now enumerate them */
if (all)
{
}
{
if (doSearch)
{
{
/* Determine instance ID */
if (g_pfnCM_Get_Device_ID_Ex(devInfo.DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle) != CR_SUCCESS)
{
}
{
/* Match on the instance ID */
}
else
{
/* Determine hardware ID's and search for matches */
{
}
}
}
}
else
{
}
if (match)
{
if (retcode)
{
goto final;
}
}
}
{
delete[] templ;
}
if (devs != INVALID_HANDLE_VALUE)
{
}
return failcode;
}
/*++
Routine Description:
Callback for use by Remove
Invokes DIF_REMOVE
uses g_pfnSetupDiCallClassInstaller so cannot be done for remote devices
Don't use CM_xxx API's, they bypass class/co-installers and this is bad.
Arguments:
Devs )_ uniquely identify the device
DevInfo )
Index - index of device
Context - GenericContext
Return Value:
EXIT_xxxx
--*/
{
/* Need hardware ID before trying to remove, as we wont have it after */
if ((!g_pfnSetupDiGetDeviceInfoListDetail(Devs, &devInfoListDetail)) || (g_pfnCM_Get_Device_ID_Ex(DevInfo->DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle)
!= CR_SUCCESS))
{
/* Skip this */
return EXIT_OK;
}
if (!g_pfnSetupDiSetClassInstallParams(Devs, DevInfo, &rmdParams.ClassInstallHeader, sizeof(rmdParams)) || !g_pfnSetupDiCallClassInstaller(DIF_REMOVE, Devs, DevInfo))
{
/* Failed to invoke DIF_REMOVE, TODO! */
return EXIT_FAIL;
}
/* See if device needs reboot */
if (g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &devParams) && (devParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)))
{
/* Reboot required */
}
else
{
/* Appears to have succeeded */
}
return EXIT_OK;
}
/*++
Routine Description:
Find the driver that is associated with the current device
We can do this either the quick way (available in WinXP)
or the long way that works in Win2k.
Arguments:
Devs )_ uniquely identify device
DevInfo )
Return Value:
TRUE if we managed to determine and select current driver
--*/
{
DWORD c;
long regerr;
{
printf("Could not retrieve install params!");
return FALSE;
}
#ifdef DI_FLAGSEX_INSTALLEDDRIVER
/* Set the flags that tell g_pfnSetupDiBuildDriverInfoList to just put the
currently installed driver node in the list, and that it should allow
excluded drivers. This flag introduced in WinXP. */
{
/* We were able to specify this flag, so proceed the easy way
We should get a list of no more than 1 driver */
{
return FALSE;
}
{
return FALSE;
}
/* We've selected the current driver */
return TRUE;
}
#endif
/* The following method works in Win2k, but it's slow and painful.
First, get driver key - if it doesn't exist, no driver */
);
if (hKey == INVALID_HANDLE_VALUE)
{
/* No such value exists, so there can't be an associated driver */
return FALSE;
}
/* Obtain path of INF - we'll do a search on this specific INF */
regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFPATH, NULL, &RegDataType, (PBYTE)deviceInstallParams.DriverPath, &RegDataLength);
{
/* No such value exists, so no associated driver */
return FALSE;
}
/* Obtain name of Provider to fill into DriverInfoData */
regerr = RegQueryValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, NULL, &RegDataType, (PBYTE)ProviderName, &RegDataLength);
{
/* No such value exists, so we don't have a valid associated driver */
return FALSE;
}
/* Obtain name of section - for final verification */
regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFSECTION, NULL, &RegDataType, (PBYTE)SectionName, &RegDataLength);
{
/* No such value exists, so we don't have a valid associated driver */
return FALSE;
}
/* Driver description (need not be same as device description) - for final verification */
regerr = RegQueryValueEx(hKey, REGSTR_VAL_DRVDESC, NULL, &RegDataType, (PBYTE)DrvDescription, &RegDataLength);
{
/* No such value exists, so we don't have a valid associated driver */
return FALSE;
}
/* Manufacturer (via SPDRP_MFG, don't access registry directly!) */
if (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, SPDRP_MFG, NULL, /* Datatype is guaranteed to always be REG_SZ */
NULL))
{
/* No such value exists, so we don't have a valid associated driver */
return FALSE;
}
/* Now search for drivers listed in the INF */
{
return FALSE;
}
{
return FALSE;
}
/* Find the entry in the INF that was used to install the driver for this device */
{
if ((_tcscmp(DriverInfoData->MfgName, MfgName) == 0) && (_tcscmp(DriverInfoData->ProviderName, ProviderName) == 0))
{
/* These two fields match, try more detailed info to ensure we have the exact driver entry used */
if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, DriverInfoData, &detail, sizeof(detail), NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
{
continue;
}
if ((_tcscmp(detail.SectionName, SectionName) == 0) && (_tcscmp(detail.DrvDescription, DrvDescription) == 0))
{
break;
}
}
}
if (!match)
{
}
return match;
}
/*++
Routine Description:
if Context provided, Simply count
otherwise dump files indented 2
Arguments:
Context - DWORD Count
Notification - SPFILENOTIFY_QUEUESCAN
Param1 - scan
Return Value:
none
--*/
UINT DumpDeviceDriversCallback (IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2)
{
if (count)
{
count[0]++;
}
else
{
}
return NO_ERROR;
}
/*++
Routine Description:
Dump information about what files were installed for driver package
<tab>Installed using OEM123.INF section [abc.NT]
<tab><tab>file...
Arguments:
Devs )_ uniquely identify device
DevInfo )
Return Value:
none
--*/
{
/* Do this by 'searching' for the current driver
mimmicing a copy-only install to our own file queue
and then parsing that file queue */
return EXIT_FAIL;
/* Get useful driver information */
if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, &driverInfoData, &driverInfoDetail, sizeof(SP_DRVINFO_DETAIL_DATA), NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
/* No information about driver or section */
goto final;
}
{
goto final;
}
/* Pretend to do the file-copy part of a driver install
to determine what files are used
the specified driver must be selected as the active driver */
goto final;
/* Create a file queue so we can look at this queue later */
{
goto final;
}
/* Modify flags to indicate we're providing our own queue */
goto final;
/* We want to add the files to the file queue, not install them! */
goto final;
/* Now fill queue with files that are to be installed this involves all class/co-installers */
goto final;
iterate the copy queue twice - 1st time to get # of files
2nd time to get files (WinXP has API to get # of files, but we want this to work
on Win2k too */
count = 0;
scanResult = 0;
/* Call once to count (NOT YET IMPLEMENTED!) */
//SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,&count,&scanResult);
//FormatToStream(stdout, count ? MSG_DUMP_DRIVER_FILES : MSG_DUMP_NO_DRIVER_FILES, count, driverInfoDetail.InfFileName, driverInfoDetail.SectionName);
/* Call again to dump the files (NOT YET IMPLEMENTED!) */
//SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,NULL,&scanResult);
scanResult = GetLastError();
else
{
if (index > 3)
{
scanResult = GetLastError();
}
}
{
}
{
}
return success;
}
{
return iRet;
return iRet;
}
{
/* Executed by the installer that already has proper privileges. */
swprintf(szCommandLine, sizeof(szCommandLine), TEXT( "%ws %d %ws" ), a_pszSection, a_iMode, a_pszInf);
#ifdef _DEBUG
#endif
return EXIT_OK;
}
{
int rc;
/* Note: HWOrder is not accessible in Windows 2000; it is updated automatically anyway. */
rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
if (rc != ERROR_SUCCESS)
{
return EXIT_FAIL;
}
{
return EXIT_FAIL;
}
#ifdef _DEBUG
#endif
/* Create entire new list. */
int iPos = 0;
{
/* Append new provider name (at beginning if a_iOrder=0). */
{
iPos++;
}
{
iPos++;
}
#ifdef _DEBUG
#endif
}
/* Append as last item if needed. */
/* Last char a delimiter? Cut off ... */
if (rc != ERROR_SUCCESS)
{
return EXIT_FAIL;
}
if (rc == ERROR_SUCCESS)
{
}
return rc;
}
int AddStringToMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToAdd, int a_iOrder)
{
int rc = 0;
_tprintf(_T("Adding MULTI_SZ string: %ws to %ws\\%ws (Order = %d)\n"), a_pszValueToAdd, a_pszSubKey, a_pszKeyValue, a_iOrder);
rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, a_pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
if (rc != ERROR_SUCCESS)
{
return EXIT_FAIL;
}
{
return EXIT_FAIL;
}
/* Look if the network provider is already in the list. */
int iPos = 0;
/* Replace delimiting "\0"'s with "," to make tokenizing work. */
for (int i=0; i<cbKeyValue/sizeof(TCHAR);i++)
{
/* Append new value (at beginning if a_iOrder=0). */
{
iPos++;
}
{
iPos++;
}
}
/* Append as last item if needed. */
{
}
if (rc != ERROR_SUCCESS)
{
return EXIT_FAIL;
}
if (rc == ERROR_SUCCESS)
{
}
return rc;
}
{
// @todo Make string sizes dynamically allocated!
int rc;
_tprintf(_T("Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), a_pszValueToRemove, a_pszSubKey, a_pszKeyValue);
rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp);
if (rc != ERROR_SUCCESS)
{
return EXIT_FAIL;
}
{
return EXIT_FAIL;
}
#ifdef _DEBUG
#endif
int iIndex = 0;
int iNewIndex = 0;
for (int i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
{
{
{
if (iNewIndex == 0)
}
iIndex = 0;
}
}
#ifdef _DEBUG
#endif
rc = RegSetValueExW(hkey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR));
if (rc != ERROR_SUCCESS)
{
return EXIT_FAIL;
}
if (rc == ERROR_SUCCESS)
{
}
return rc;
}
int a_iServiceType,
int a_iStartType,
{
int rc = ERROR_SUCCESS;
if (hSCManager == NULL)
{
return EXIT_FAIL;
}
/* Fixup end of multistring */
if (a_pszDependencies != NULL)
{
/* Replace comma separator on null separator */
{
if (',' == szDepend [i])
szDepend [i] = 0;
}
}
a_pszStartStopName, // name of service
a_pszDisplayName, // name to display
SERVICE_ALL_ACCESS, // desired access
a_iServiceType, // service type
a_iStartType, // start type
SERVICE_ERROR_NORMAL, // error control type
a_pszBinPath, // service's binary
a_pszLoadOrderGroup, // ordering group
{
switch (dwErr)
{
case ERROR_SERVICE_EXISTS:
{
a_pszStartStopName, // name of service
SERVICE_ALL_ACCESS); // desired access
{
dwErr = GetLastError();
}
else
{
a_iServiceType, // service type
a_iStartType, // start type
SERVICE_ERROR_NORMAL, // error control type
a_pszBinPath, // service's binary
a_pszLoadOrderGroup, // ordering group
a_pszDisplayName); // name to display
if (Result)
{
}
else
{
dwErr = GetLastError();
}
}
/* This entire branch do not return an error to avoid installations failures,
* if updating service parameters. Better to have a running system with old
* parameters and the failure information in the installation log.
*/
break;
}
case ERROR_INVALID_PARAMETER:
break;
default:
break;
}
goto cleanup;
}
else
{
}
if (hSCManager != NULL)
return rc;
}
{
int rc = ERROR_SUCCESS;
if (hSCManager == NULL)
{
}
else
{
{
}
}
{
{
{
switch (dwErr)
{
break;
default:
break;
}
}
else
{
}
}
else
{
}
}
if (hSCManager != NULL)
return rc;
}
const _TCHAR *pszValueName,
{
0, /* Reserved */
NULL, /* lpClass [in, optional] */
0, /* dwOptions [in] */
NULL, /* lpSecurityAttributes [in, optional] */
&hKey,
NULL); /* lpdwDisposition [out, optional] */
if (lRet != ERROR_SUCCESS)
{
}
else
{
if (lRet != ERROR_SUCCESS)
}
return lRet;
}
void PrintHelp (void)
{
_tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
_tprintf(_T("\tTo write registry values: VBoxDrvInst /registry write <root> <sub key> <key name> <key type> <value> [type] [size]\n\n"));
_tprintf(_T("\tVBoxDrvInst /i \"PCI\\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00\" VBoxVideo.inf Display\n"));
}
{
int rc;
rc = LoadAPICalls();
if ( rc == ERROR_SUCCESS
&& argc >= 2)
{
{
if (argc < 5)
{
rc = EXIT_USAGE;
}
else
{
{
}
if (rc == ERROR_SUCCESS)
{
}
}
}
{
if (argc < 3)
{
rc = EXIT_USAGE;
}
else
{
{
}
if (rc == ERROR_SUCCESS)
{
}
}
}
{
if (argc < 3)
{
rc = EXIT_USAGE;
}
else
{
{
}
if (rc == ERROR_SUCCESS)
{
}
}
}
{
if (argc < 3)
{
rc = EXIT_USAGE;
}
else
{
int iOrder = 0;
if (argc > 3)
}
}
{
if (argc < 6)
{
rc = EXIT_USAGE;
}
else
{
}
}
{
if (argc < 5)
{
rc = EXIT_USAGE;
}
else
{
}
}
{
if (argc < 7)
{
rc = EXIT_USAGE;
}
else
{
rc = CreateService(
argv[2],
argv[3],
argv[6],
}
}
{
if (argc < 3)
{
rc = EXIT_USAGE;
}
else
{
}
}
{
if (argc < 8)
{
rc = EXIT_USAGE;
}
else
{
/** @todo add a handleRegistry(argc, argv) method to keep things cleaner */
{
if (argc > 8)
{
{
}
}
{
}
if (argc > 9)
REG_BINARY, /** @todo needs to be expanded (argv[6]) */
pbVal, /* The value itself */
dwValSize); /* Size of the value */
}
/*else if (0 == _tcsicmp(argv[2], _T("read")))
{
}
else if (0 == _tcsicmp(argv[2], _T("del")))
{
}*/
else
rc = EXIT_USAGE;
}
}
}
if (rc == EXIT_USAGE)
PrintHelp();
FreeAPICalls();
return rc;
}