X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Flib%2Fsetupapi%2Fdevinst.c;h=b69ced2573c6675084cbbb86f68f896237228f77;hp=732adf34bb8def110fec1fd7f4cec1c68059c341;hb=8aa516fdf8f64e4d9374fc850e8834b8a580b139;hpb=8325af0b6a877585c5074a948eab202707d365bf diff --git a/reactos/lib/setupapi/devinst.c b/reactos/lib/setupapi/devinst.c index 732adf34bb8..b69ced2573c 100644 --- a/reactos/lib/setupapi/devinst.c +++ b/reactos/lib/setupapi/devinst.c @@ -2,7 +2,7 @@ * SetupAPI device installer * * Copyright 2000 Andreas Mohr for CodeWeavers - * 2005 Hervé Poussineau (hpoussin@reactos.com) + * 2005 Hervé Poussineau (hpoussin@reactos.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,23 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "config.h" -#include "wine/port.h" - -#include - -#include -#include "setupapi.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "cfgmgr32.h" -#include "initguid.h" -#define NTOS_MODE_USER -#include - +#define INITGUID #include "setupapi_private.h" - WINE_DEFAULT_DEBUG_CHANNEL(setupapi); /* Unicode constants */ @@ -43,30 +29,10 @@ static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0}; static const WCHAR Class[] = {'C','l','a','s','s',0}; static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0}; static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0}; -static const WCHAR NoDisplayClass[] = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0}; -static const WCHAR NoInstallClass[] = {'N','o','I','s','t','a','l','l','C','l','a','s','s',0}; -static const WCHAR NoUseClass[] = {'N','o','U','s','e','C','l','a','s','s',0}; -static const WCHAR NtExtension[] = {'.','N','T',0}; -static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0}; +static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0}; +static const WCHAR InterfaceInstall32[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0}; static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0}; static const WCHAR Version[] = {'V','e','r','s','i','o','n',0}; -static const WCHAR WinExtension[] = {'.','W','i','n',0}; - -/* Registry key and value names */ -static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'C','o','n','t','r','o','l','\\', - 'C','l','a','s','s',0}; - -static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'C','o','n','t','r','o','l','\\', - 'D','e','v','i','c','e','C','l','a','s','s','e','s',0}; - -static const WCHAR EnumKeyName[] = {'S','y','s','t','e','m','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'E','n','u','m',0}; - /* FIXME: header mess */ DEFINE_GUID(GUID_NULL, @@ -80,14 +46,23 @@ typedef BOOL (WINAPI* DEFAULT_CLASS_INSTALL_PROC) ( IN HDEVINFO DeviceInfoSet, IN OUT PSP_DEVINFO_DATA DeviceInfoData); -typedef DWORD +typedef DWORD (CALLBACK* COINSTALLER_PROC) ( IN DI_FUNCTION InstallFunction, IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, IN OUT PCOINSTALLER_CONTEXT_DATA Context); - -#define SETUP_DEV_INFO_SET_MAGIC 0xd00ff057 +typedef BOOL +(WINAPI* PROPERTY_PAGE_PROVIDER) ( + IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest, + IN LPFNADDPROPSHEETPAGE fAddFunc, + IN LPARAM lParam); +typedef BOOL +(*UPDATE_CLASS_PARAM_HANDLER) ( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, + IN DWORD ClassInstallParamsSize); struct CoInstallerElement { @@ -99,117 +74,56 @@ struct CoInstallerElement PVOID PrivateData; }; -struct DeviceInterface /* Element of DeviceInfoElement.InterfaceListHead */ -{ - LIST_ENTRY ListEntry; - - struct DeviceInfoElement* DeviceInfo; - GUID InterfaceClassGuid; - - - /* SPINT_ACTIVE : the interface is active/enabled - * SPINT_DEFAULT: the interface is the default interface for the device class FIXME??? - * SPINT_REMOVED: the interface is removed - */ - DWORD Flags; - - WCHAR SymbolicLink[0]; /* \\?\ACPI#PNP0501#4&2658d0a0&0#{GUID} */ -}; - -struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceInfoElement.DriverListHead */ -{ - LIST_ENTRY ListEntry; - - DWORD DriverRank; - SP_DRVINFO_DATA_V2_W Info; - GUID ClassGuid; - LPWSTR InfPath; - LPWSTR InfSection; - LPWSTR MatchingId; -}; - -struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */ -{ - LIST_ENTRY ListEntry; - - /* Information about devnode: - * - DeviceName: - * "Root\*PNP0501" for example. - * It doesn't contain the unique ID for the device - * (points into the Data field at the end of the structure) - * WARNING: no NULL char exist between DeviceName and UniqueId - * in Data field! - * - UniqueId - * "5&1be2108e&0" or "0000" - * If DICD_GENERATE_ID is specified in creation flags, - * this unique ID is autogenerated using 4 digits, base 10 - * (points into the Data field at the end of the structure) - * - DeviceDescription - * String which identifies the device. Can be NULL. If not NULL, - * points into the Data field at the end of the structure - * - ClassGuid - * Identifies the class of this device. FIXME: can it be GUID_NULL? - * - CreationFlags - * Is a combination of: - * - DICD_GENERATE_ID - * the unique ID needs to be generated - * - DICD_INHERIT_CLASSDRVS - * inherit driver of the device info set (== same pointer) - * - hwndParent - * Used when doing device-specific actions. Can be NULL - */ - PCWSTR DeviceName; - PCWSTR UniqueId; - PCWSTR DeviceDescription; - GUID ClassGuid; - DWORD CreationFlags; - HWND hwndParent; - - /* Flags is a combination of: - * - DI_DIDCOMPAT - * Set when the device driver list is created - * FlagsEx is a combination of: - */ - DWORD Flags; - DWORD FlagsEx; - - /* If CreationFlags contains DICD_INHERIT_CLASSDRVS, this list is invalid */ - /* If the driver is not searched/detected, this list is empty */ - LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */ - /* Points into DriverListHead list. The pointer is NULL if no driver is - * currently chosen. */ - struct DriverInfoElement *SelectedDriver; - - /* List of interfaces implemented by this device */ - LIST_ENTRY InterfaceListHead; /* List of struct DeviceInterface */ - - WCHAR Data[0]; -}; - -struct DeviceInfoSet /* HDEVINFO */ -{ - DWORD magic; /* SETUP_DEV_INFO_SET_MAGIC */ - GUID ClassGuid; /* If != GUID_NULL, only devices of this class can be in the device info set */ - HWND hwndParent; /* only used on non-device-specific actions, like as a select-device dialog using the global class driver list */ - HKEY HKLM; /* Local or distant HKEY_LOCAL_MACHINE registry key */ - - /* Flags is a combination of: - * - DI_DIDCLASS - * Set when the class driver list is created - * - DI_COMPAT_FROM_CLASS (FIXME: not supported) - * Forces SetupDiBuildDriverInfoList to build a class drivers list - * FlagsEx is a combination of: - */ - DWORD Flags; - DWORD FlagsEx; - - /* If the driver is not searched/detected, this list is empty */ - LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */ - /* Points into DriverListHead list. The pointer is NULL if no driver is - * currently chosen. */ - struct DriverInfoElement *SelectedDriver; - - LIST_ENTRY ListHead; /* List of struct DeviceInfoElement */ +static BOOL +PropertyChangeHandler( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, + IN DWORD ClassInstallParamsSize); + +static UPDATE_CLASS_PARAM_HANDLER UpdateClassInstallParamHandlers[] = { + NULL, /* DIF_SELECTDEVICE */ + NULL, /* DIF_INSTALLDEVICE */ + NULL, /* DIF_ASSIGNRESOURCES */ + NULL, /* DIF_PROPERTIES */ + NULL, /* DIF_REMOVE */ + NULL, /* DIF_FIRSTTIMESETUP */ + NULL, /* DIF_FOUNDDEVICE */ + NULL, /* DIF_SELECTCLASSDRIVERS */ + NULL, /* DIF_VALIDATECLASSDRIVERS */ + NULL, /* DIF_INSTALLCLASSDRIVERS */ + NULL, /* DIF_CALCDISKSPACE */ + NULL, /* DIF_DESTROYPRIVATEDATA */ + NULL, /* DIF_VALIDATEDRIVER */ + NULL, /* DIF_MOVEDEVICE */ + NULL, /* DIF_DETECT */ + NULL, /* DIF_INSTALLWIZARD */ + NULL, /* DIF_DESTROYWIZARDDATA */ + PropertyChangeHandler, /* DIF_PROPERTYCHANGE */ + NULL, /* DIF_ENABLECLASS */ + NULL, /* DIF_DETECTVERIFY */ + NULL, /* DIF_INSTALLDEVICEFILES */ + NULL, /* DIF_UNREMOVE */ + NULL, /* DIF_SELECTBESTCOMPATDRV */ + NULL, /* DIF_ALLOW_INSTALL */ + NULL, /* DIF_REGISTERDEVICE */ + NULL, /* DIF_NEWDEVICEWIZARD_PRESELECT */ + NULL, /* DIF_NEWDEVICEWIZARD_SELECT */ + NULL, /* DIF_NEWDEVICEWIZARD_PREANALYZE */ + NULL, /* DIF_NEWDEVICEWIZARD_POSTANALYZE */ + NULL, /* DIF_NEWDEVICEWIZARD_FINISHINSTALL */ + NULL, /* DIF_UNUSED1 */ + NULL, /* DIF_INSTALLINTERFACES */ + NULL, /* DIF_DETECTCANCEL */ + NULL, /* DIF_REGISTER_COINSTALLERS */ + NULL, /* DIF_ADDPROPERTYPAGE_ADVANCED */ + NULL, /* DIF_ADDPROPERTYPAGE_BASIC */ + NULL, /* DIF_RESERVED1 */ + NULL, /* DIF_TROUBLESHOOTER */ + NULL, /* DIF_POWERMESSAGEWAKE */ + NULL, /* DIF_ADDREMOTEPROPERTYPAGE_ADVANCED */ + NULL, /* DIF_UPDATEDRIVER_UI */ + NULL /* DIF_RESERVED2 */ }; /*********************************************************************** @@ -278,13 +192,14 @@ BOOL WINAPI SetupDiBuildClassInfoListExW( LONG lError; DWORD dwGuidListIndex = 0; - TRACE("\n"); + TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList, + ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved); if (RequiredSize != NULL) *RequiredSize = 0; hClassesKey = SetupDiOpenClassRegKeyExW(NULL, - KEY_ALL_ACCESS, + KEY_ENUMERATE_SUB_KEYS, DIOCR_INSTALLER, MachineName, Reserved); @@ -307,12 +222,12 @@ BOOL WINAPI SetupDiBuildClassInfoListExW( TRACE("RegEnumKeyExW() returns %ld\n", lError); if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA) { - TRACE("Key name: %p\n", szKeyName); + TRACE("Key name: %s\n", debugstr_w(szKeyName)); if (RegOpenKeyExW(hClassesKey, szKeyName, 0, - KEY_ALL_ACCESS, + KEY_QUERY_VALUE, &hClassKey)) { RegCloseKey(hClassesKey); @@ -320,7 +235,7 @@ BOOL WINAPI SetupDiBuildClassInfoListExW( } if (!RegQueryValueExW(hClassKey, - NoUseClass, + REGSTR_VAL_NOUSECLASS, NULL, NULL, NULL, @@ -333,7 +248,7 @@ BOOL WINAPI SetupDiBuildClassInfoListExW( if ((Flags & DIBCI_NOINSTALLCLASS) && (!RegQueryValueExW(hClassKey, - NoInstallClass, + REGSTR_VAL_NOINSTALLCLASS, NULL, NULL, NULL, @@ -346,7 +261,7 @@ BOOL WINAPI SetupDiBuildClassInfoListExW( if ((Flags & DIBCI_NODISPLAYCLASS) && (!RegQueryValueExW(hClassKey, - NoDisplayClass, + REGSTR_VAL_NODISPLAYCLASS, NULL, NULL, NULL, @@ -359,14 +274,14 @@ BOOL WINAPI SetupDiBuildClassInfoListExW( RegCloseKey(hClassKey); - TRACE("Guid: %p\n", szKeyName); + TRACE("Guid: %s\n", debugstr_w(szKeyName)); if (dwGuidListIndex < ClassGuidListSize) { if (szKeyName[0] == L'{' && szKeyName[37] == L'}') { szKeyName[37] = 0; } - TRACE("Guid: %p\n", &szKeyName[1]); + TRACE("Guid: %s\n", debugstr_w(&szKeyName[1])); UuidFromStringW(&szKeyName[1], &ClassGuidList[dwGuidListIndex]); @@ -484,6 +399,9 @@ BOOL WINAPI SetupDiClassGuidsFromNameExW( LONG lError; DWORD dwGuidListIndex = 0; + TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList, + ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved); + if (RequiredSize != NULL) *RequiredSize = 0; @@ -511,7 +429,7 @@ BOOL WINAPI SetupDiClassGuidsFromNameExW( TRACE("RegEnumKeyExW() returns %ld\n", lError); if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA) { - TRACE("Key name: %p\n", szKeyName); + TRACE("Key name: %s\n", debugstr_w(szKeyName)); if (RegOpenKeyExW(hClassesKey, szKeyName, @@ -531,20 +449,20 @@ BOOL WINAPI SetupDiClassGuidsFromNameExW( (LPBYTE)szClassName, &dwLength)) { - TRACE("Class name: %p\n", szClassName); + TRACE("Class name: %s\n", debugstr_w(szClassName)); if (strcmpiW(szClassName, ClassName) == 0) { TRACE("Found matching class name\n"); - TRACE("Guid: %p\n", szKeyName); + TRACE("Guid: %s\n", debugstr_w(szKeyName)); if (dwGuidListIndex < ClassGuidListSize) { if (szKeyName[0] == L'{' && szKeyName[37] == L'}') { szKeyName[37] = 0; } - TRACE("Guid: %p\n", &szKeyName[1]); + TRACE("Guid: %s\n", debugstr_w(&szKeyName[1])); UuidFromStringW(&szKeyName[1], &ClassGuidList[dwGuidListIndex]); @@ -649,6 +567,9 @@ BOOL WINAPI SetupDiClassNameFromGuidExW( DWORD dwLength; LONG rc; + TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName, + ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved); + hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INSTALLER, @@ -719,7 +640,8 @@ SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid, LPWSTR MachineNameW = NULL; HDEVINFO hDevInfo; - TRACE("%p %p %s %p\n", ClassGuid, hwndParent, MachineName, Reserved); + TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent, + debugstr_a(MachineName), Reserved); if (MachineName) { @@ -737,6 +659,22 @@ SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid, return hDevInfo; } +static DWORD +GetErrorCodeFromCrCode(const IN CONFIGRET cr) +{ + switch (cr) + { + case CR_INVALID_MACHINENAME: return ERROR_INVALID_COMPUTERNAME; + case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY; + case CR_SUCCESS: return ERROR_SUCCESS; + default: + /* FIXME */ + return ERROR_GEN_FAILURE; + } + + /* Does not happen */ +} + /*********************************************************************** * SetupDiCreateDeviceInfoListExW (SETUPAPI.@) */ @@ -747,42 +685,91 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid, PVOID Reserved) { struct DeviceInfoSet *list; + LPWSTR UNCServerName = NULL; + DWORD size; DWORD rc; + //CONFIGRET cr; + HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;; - TRACE("%p %p %S %p\n", ClassGuid, hwndParent, MachineName, Reserved); + TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent, + debugstr_w(MachineName), Reserved); - list = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoSet)); + size = FIELD_OFFSET(struct DeviceInfoSet, szData); + if (MachineName) + size += (wcslen(MachineName) + 3) * sizeof(WCHAR); + list = HeapAlloc(GetProcessHeap(), 0, size); if (!list) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return (HDEVINFO)INVALID_HANDLE_VALUE; + goto cleanup; } + memset(list, 0, sizeof(struct DeviceInfoSet)); list->magic = SETUP_DEV_INFO_SET_MAGIC; memcpy( &list->ClassGuid, ClassGuid ? ClassGuid : &GUID_NULL, sizeof(list->ClassGuid)); - list->hwndParent = hwndParent; + list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); + list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS; + list->InstallParams.hwndParent = hwndParent; if (MachineName) { rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM); if (rc != ERROR_SUCCESS) { SetLastError(rc); - HeapFree(GetProcessHeap(), 0, list); - return (HDEVINFO)INVALID_HANDLE_VALUE; + goto cleanup; + } + UNCServerName = HeapAlloc(GetProcessHeap(), 0, (strlenW(MachineName) + 3) * sizeof(WCHAR)); + if (!UNCServerName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; } + + strcpyW(UNCServerName + 2, MachineName); + list->szData[0] = list->szData[1] = '\\'; + strcpyW(list->szData + 2, MachineName); + list->MachineName = list->szData; } else { + DWORD Size = MAX_PATH; list->HKLM = HKEY_LOCAL_MACHINE; + UNCServerName = HeapAlloc(GetProcessHeap(), 0, (MAX_PATH + 2) * sizeof(WCHAR)); + if (!UNCServerName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + if (!GetComputerNameW(UNCServerName + 2, &Size)) + goto cleanup; + list->MachineName = NULL; + } +#if 0 + UNCServerName[0] = UNCServerName[1] = '\\'; + cr = CM_Connect_MachineW(UNCServerName, &list->hMachine); + if (cr != CR_SUCCESS) + { + SetLastError(GetErrorCodeFromCrCode(cr)); + goto cleanup; } - list->Flags = 0; /* FIXME */ - list->FlagsEx = 0; /* FIXME */ +#endif InitializeListHead(&list->DriverListHead); InitializeListHead(&list->ListHead); - return (HDEVINFO)list; + + ret = (HDEVINFO)list; + +cleanup: + if (ret == INVALID_HANDLE_VALUE) + { + if (list && list->HKLM != 0 && list->HKLM != HKEY_LOCAL_MACHINE) + RegCloseKey(list->HKLM); + HeapFree(GetProcessHeap(), 0, list); + } + HeapFree(GetProcessHeap(), 0, UNCServerName); + return ret; } /*********************************************************************** @@ -801,7 +788,7 @@ BOOL WINAPI SetupDiEnumDeviceInfo( else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE) { struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet; - + if (list->magic != SETUP_DEV_INFO_SET_MAGIC) SetLastError(ERROR_INVALID_HANDLE); else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) @@ -819,12 +806,7 @@ BOOL WINAPI SetupDiEnumDeviceInfo( memcpy(&DeviceInfoData->ClassGuid, &DevInfo->ClassGuid, sizeof(GUID)); - DeviceInfoData->DevInst = 0; /* FIXME */ - /* Note: this appears to be dangerous, passing a private - * pointer a heap-allocated datum to the caller. However, the - * expected lifetime of the device data is the same as the - * HDEVINFO; once that is closed, the data are no longer valid. - */ + DeviceInfoData->DevInst = DevInfo->dnDevInst; DeviceInfoData->Reserved = (ULONG_PTR)DevInfo; ret = TRUE; } @@ -838,16 +820,53 @@ BOOL WINAPI SetupDiEnumDeviceInfo( /*********************************************************************** * SetupDiGetActualSectionToInstallA (SETUPAPI.@) */ -BOOL WINAPI SetupDiGetActualSectionToInstallA( - HINF InfHandle, - PCSTR InfSectionName, - PSTR InfSectionWithExt, - DWORD InfSectionWithExtSize, - PDWORD RequiredSize, - PSTR *Extension) +BOOL WINAPI +SetupDiGetActualSectionToInstallA( + IN HINF InfHandle, + IN PCSTR InfSectionName, + OUT PSTR InfSectionWithExt OPTIONAL, + IN DWORD InfSectionWithExtSize, + OUT PDWORD RequiredSize OPTIONAL, + OUT PSTR *Extension OPTIONAL) +{ + return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName, + NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize, + Extension, NULL); +} + +/*********************************************************************** + * SetupDiGetActualSectionToInstallW (SETUPAPI.@) + */ +BOOL WINAPI +SetupDiGetActualSectionToInstallW( + IN HINF InfHandle, + IN PCWSTR InfSectionName, + OUT PWSTR InfSectionWithExt OPTIONAL, + IN DWORD InfSectionWithExtSize, + OUT PDWORD RequiredSize OPTIONAL, + OUT PWSTR *Extension OPTIONAL) +{ + return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName, + NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize, + Extension, NULL); +} + +/*********************************************************************** + * SetupDiGetActualSectionToInstallExA (SETUPAPI.@) + */ +BOOL WINAPI +SetupDiGetActualSectionToInstallExA( + IN HINF InfHandle, + IN PCSTR InfSectionName, + IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL, + OUT PSTR InfSectionWithExt OPTIONAL, + IN DWORD InfSectionWithExtSize, + OUT PDWORD RequiredSize OPTIONAL, + OUT PSTR* Extension OPTIONAL, + IN PVOID Reserved) { LPWSTR InfSectionNameW = NULL; - PWSTR InfSectionWithExtW = NULL; + LPWSTR InfSectionWithExtW = NULL; PWSTR ExtensionW; BOOL bResult = FALSE; @@ -856,18 +875,23 @@ BOOL WINAPI SetupDiGetActualSectionToInstallA( if (InfSectionName) { InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP); - if (InfSectionNameW == NULL) goto end; + if (InfSectionNameW == NULL) + goto cleanup; } if (InfSectionWithExt) { - InfSectionWithExtW = HeapAlloc(GetProcessHeap(), 0, InfSectionWithExtSize * sizeof(WCHAR)); - if (InfSectionWithExtW == NULL) goto end; + InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR)); + if (InfSectionWithExtW == NULL) + goto cleanup; } - bResult = SetupDiGetActualSectionToInstallW(InfHandle, InfSectionNameW, - InfSectionWithExt ? InfSectionNameW : NULL, - InfSectionWithExtSize, RequiredSize, - Extension ? &ExtensionW : NULL); + bResult = SetupDiGetActualSectionToInstallExW( + InfHandle, InfSectionNameW, AlternatePlatformInfo, + InfSectionWithExt ? InfSectionWithExtW : NULL, + InfSectionWithExtSize, + RequiredSize, + Extension ? &ExtensionW : NULL, + Reserved); if (bResult && InfSectionWithExt) { @@ -882,90 +906,188 @@ BOOL WINAPI SetupDiGetActualSectionToInstallA( *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW]; } -end: - if (InfSectionNameW) MyFree(InfSectionNameW); - if (InfSectionWithExtW) HeapFree(GetProcessHeap(), 0, InfSectionWithExtW); +cleanup: + MyFree(InfSectionNameW); + MyFree(InfSectionWithExtW); return bResult; } /*********************************************************************** - * SetupDiGetActualSectionToInstallW (SETUPAPI.@) + * SetupDiGetActualSectionToInstallExW (SETUPAPI.@) */ -BOOL WINAPI SetupDiGetActualSectionToInstallW( - HINF InfHandle, - PCWSTR InfSectionName, - PWSTR InfSectionWithExt, - DWORD InfSectionWithExtSize, - PDWORD RequiredSize, - PWSTR *Extension) +BOOL WINAPI +SetupDiGetActualSectionToInstallExW( + IN HINF InfHandle, + IN PCWSTR InfSectionName, + IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL, + OUT PWSTR InfSectionWithExt OPTIONAL, + IN DWORD InfSectionWithExtSize, + OUT PDWORD RequiredSize OPTIONAL, + OUT PWSTR* Extension OPTIONAL, + IN PVOID Reserved) { - WCHAR szBuffer[MAX_PATH]; - DWORD dwLength; - DWORD dwFullLength; - LONG lLineCount = -1; - - lstrcpyW(szBuffer, InfSectionName); - dwLength = lstrlenW(szBuffer); + BOOL ret = FALSE; - if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - /* Test section name with '.NTx86' extension */ - lstrcpyW(&szBuffer[dwLength], NtPlatformExtension); - lLineCount = SetupGetLineCountW(InfHandle, szBuffer); + TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName), + AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize, + RequiredSize, Extension, Reserved); - if (lLineCount == -1) - { - /* Test section name with '.NT' extension */ - lstrcpyW(&szBuffer[dwLength], NtExtension); - lLineCount = SetupGetLineCountW(InfHandle, szBuffer); - } - } + if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE) + SetLastError(ERROR_INVALID_HANDLE); + else if (!InfSectionName) + SetLastError(ERROR_INVALID_PARAMETER); + else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (Reserved != NULL) + SetLastError(ERROR_INVALID_PARAMETER); else { - /* Test section name with '.Win' extension */ - lstrcpyW(&szBuffer[dwLength], WinExtension); - lLineCount = SetupGetLineCountW(InfHandle, szBuffer); - } + static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, }; + PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform; + LPCWSTR pExtensionPlatform, pExtensionArchitecture; + WCHAR SectionName[LINE_LEN + 1]; + LONG lLineCount = -1; + DWORD dwFullLength; + + /* Fill platform info if needed */ + if (AlternatePlatformInfo) + pPlatformInfo = AlternatePlatformInfo; + else if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO)) + { + /* That's the first time we go here. We need to fill in the structure */ + OSVERSIONINFO VersionInfo; + SYSTEM_INFO SystemInfo; + VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + ret = GetVersionEx(&VersionInfo); + if (!ret) + goto done; + GetSystemInfo(&SystemInfo); + CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO); + CurrentPlatform.Platform = VersionInfo.dwPlatformId; + CurrentPlatform.MajorVersion = VersionInfo.dwMajorVersion; + CurrentPlatform.MinorVersion = VersionInfo.dwMinorVersion; + CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture; + CurrentPlatform.Reserved = 0; + } - if (lLineCount == -1) - { - /* Test section name without extension */ - szBuffer[dwLength] = 0; - lLineCount = SetupGetLineCountW(InfHandle, szBuffer); - } +static const WCHAR ExtensionPlatformNone[] = {'.',0}; +static const WCHAR ExtensionPlatformNT[] = {'.','N','T',0}; +static const WCHAR ExtensionPlatformWindows[] = {'.','W','i','n',0}; - if (lLineCount == -1) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } +static const WCHAR ExtensionArchitectureNone[] = {0}; +static const WCHAR ExtensionArchitectureamd64[] = {'a','m','d','6','4',0}; +static const WCHAR ExtensionArchitectureppc[] = {'p','p','c',0}; +static const WCHAR ExtensionArchitecturex86[] = {'x','8','6',0}; + + /* Set various extensions values */ + switch (pPlatformInfo->Platform) + { + case VER_PLATFORM_WIN32_WINDOWS: + pExtensionPlatform = ExtensionPlatformWindows; + break; + case VER_PLATFORM_WIN32_NT: + pExtensionPlatform = ExtensionPlatformNT; + break; + default: + pExtensionPlatform = ExtensionPlatformNone; + break; + } + switch (pPlatformInfo->ProcessorArchitecture) + { + case PROCESSOR_ARCHITECTURE_AMD64: + pExtensionArchitecture = ExtensionArchitectureamd64; + break; + case PROCESSOR_ARCHITECTURE_INTEL: + pExtensionArchitecture = ExtensionArchitecturex86; + break; + case PROCESSOR_ARCHITECTURE_PPC: + pExtensionArchitecture = ExtensionArchitectureppc; + break; + default: + ERR("Unknown processor architecture 0x%x\n", pPlatformInfo->ProcessorArchitecture); + case PROCESSOR_ARCHITECTURE_UNKNOWN: + pExtensionArchitecture = ExtensionArchitectureNone; + break; + } - dwFullLength = lstrlenW(szBuffer); + SectionName[LINE_LEN] = UNICODE_NULL; + + /* Test with platform.architecture.major.minor extension */ + snprintfW(SectionName, LINE_LEN, L"%s%s%s.%lu.%lu", InfSectionName, + pExtensionPlatform, pExtensionArchitecture, pPlatformInfo->MajorVersion, pPlatformInfo->MinorVersion); + lLineCount = SetupGetLineCountW(InfHandle, SectionName); + if (lLineCount != -1) goto sectionfound; + + /* Test with platform.major.minor extension */ + snprintfW(SectionName, LINE_LEN, L"%s%s.%lu.%lu", InfSectionName, + pExtensionPlatform, pPlatformInfo->MajorVersion, pPlatformInfo->MinorVersion); + lLineCount = SetupGetLineCountW(InfHandle, SectionName); + if (lLineCount != -1) goto sectionfound; + + /* Test with platform.architecture.major extension */ + snprintfW(SectionName, LINE_LEN, L"%s%s%s.%lu", InfSectionName, + pExtensionPlatform, pExtensionArchitecture, pPlatformInfo->MajorVersion); + lLineCount = SetupGetLineCountW(InfHandle, SectionName); + if (lLineCount != -1) goto sectionfound; + + /* Test with platform.major extension */ + snprintfW(SectionName, LINE_LEN, L"%s%s.%lu", InfSectionName, + pExtensionPlatform, pPlatformInfo->MajorVersion); + lLineCount = SetupGetLineCountW(InfHandle, SectionName); + if (lLineCount != -1) goto sectionfound; + + /* Test with platform.architecture extension */ + snprintfW(SectionName, LINE_LEN, L"%s%s%s", InfSectionName, + pExtensionPlatform, pExtensionArchitecture); + lLineCount = SetupGetLineCountW(InfHandle, SectionName); + if (lLineCount != -1) goto sectionfound; + + /* Test with platform extension */ + snprintfW(SectionName, LINE_LEN, L"%s%s", InfSectionName, + pExtensionPlatform); + lLineCount = SetupGetLineCountW(InfHandle, SectionName); + if (lLineCount != -1) goto sectionfound; + + /* Test without extension */ + snprintfW(SectionName, LINE_LEN, L"%s", InfSectionName); + lLineCount = SetupGetLineCountW(InfHandle, SectionName); + if (lLineCount != -1) goto sectionfound; + + /* No appropriate section found */ + SetLastError(ERROR_INVALID_PARAMETER); + goto done; - if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0) - { - if (InfSectionWithExtSize < (dwFullLength + 1)) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; - } +sectionfound: + dwFullLength = lstrlenW(SectionName); + if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0) + { + if (InfSectionWithExtSize < (dwFullLength + 1)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + goto done; + } - lstrcpyW(InfSectionWithExt, szBuffer); - if (Extension != NULL) - { - *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength]; - } - } + lstrcpyW(InfSectionWithExt, SectionName); + if (Extension != NULL) + { + DWORD dwLength = lstrlenW(SectionName); + *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength]; + } + } - if (RequiredSize != NULL) - { - *RequiredSize = dwFullLength + 1; + if (RequiredSize != NULL) + *RequiredSize = dwFullLength + 1; + + ret = TRUE; } - return TRUE; +done: + TRACE("Returning %d\n", ret); + return ret; } + /*********************************************************************** * SetupDiGetClassDescriptionA (SETUPAPI.@) */ @@ -1065,8 +1187,11 @@ BOOL WINAPI SetupDiGetClassDescriptionExW( HKEY hKey; DWORD dwLength; + TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription, + ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved); + hKey = SetupDiOpenClassRegKeyExW(ClassGuid, - KEY_ALL_ACCESS, + KEY_QUERY_VALUE, DIOCR_INSTALLER, MachineName, Reserved); @@ -1184,30 +1309,40 @@ end: static BOOL CreateDeviceInfoElement( + IN struct DeviceInfoSet *list, IN LPCWSTR InstancePath, IN LPCGUID pClassGuid, OUT struct DeviceInfoElement **pDeviceInfo) { + DWORD size; + CONFIGRET cr; struct DeviceInfoElement *deviceInfo; *pDeviceInfo = NULL; - deviceInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoElement) + (wcslen(InstancePath) + 1) * sizeof(WCHAR)); + size = FIELD_OFFSET(struct DeviceInfoElement, Data) + (wcslen(InstancePath) + 1) * sizeof(WCHAR); + deviceInfo = HeapAlloc(GetProcessHeap(), 0, size); if (!deviceInfo) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } + memset(deviceInfo, 0, size); + + cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine); + if (cr != CR_SUCCESS) + { + SetLastError(GetErrorCodeFromCrCode(cr)); + return FALSE; + } + + deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); wcscpy(deviceInfo->Data, InstancePath); deviceInfo->DeviceName = deviceInfo->Data; deviceInfo->UniqueId = wcsrchr(deviceInfo->Data, '\\'); deviceInfo->DeviceDescription = NULL; memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID)); deviceInfo->CreationFlags = 0; - deviceInfo->hwndParent = NULL; - deviceInfo->Flags = 0; /* FIXME */ - deviceInfo->FlagsEx = 0; /* FIXME */ - deviceInfo->SelectedDriver = NULL; InitializeListHead(&deviceInfo->DriverListHead); InitializeListHead(&deviceInfo->InterfaceListHead); @@ -1226,7 +1361,8 @@ CreateDeviceInterface( *pDeviceInterface = NULL; - deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymbolicLink) + 1) * sizeof(WCHAR)); + deviceInterface = HeapAlloc(GetProcessHeap(), 0, + FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (wcslen(SymbolicLink) + 1) * sizeof(WCHAR)); if (!deviceInterface) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); @@ -1255,7 +1391,7 @@ static LONG SETUP_CreateDevListFromEnumerator( DWORD i = 0, j; DWORD dwLength, dwRegType; DWORD rc; - + /* Enumerate device IDs (subkeys of hEnumeratorKey) */ while (TRUE) { @@ -1313,6 +1449,8 @@ static LONG SETUP_CreateDevListFromEnumerator( if (pClassGuid) /* Skip this bad entry as we can't verify it */ continue; + /* Set a default GUID for this device */ + memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID)); } else if (rc != ERROR_SUCCESS) { @@ -1324,13 +1462,14 @@ static LONG SETUP_CreateDevListFromEnumerator( RegCloseKey(hDeviceIdKey); return ERROR_GEN_FAILURE; } - - KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */ - if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK) + else { - RegCloseKey(hDeviceIdKey); - return GetLastError(); + KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */ + if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK) + /* Bad GUID, skip the entry */ + continue; } + if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid)) { /* Skip this entry as it is not the right device class */ @@ -1338,7 +1477,7 @@ static LONG SETUP_CreateDevListFromEnumerator( } /* Add the entry to the list */ - if (!CreateDeviceInfoElement(InstancePath, &KeyGuid, &deviceInfo)) + if (!CreateDeviceInfoElement(list, InstancePath, &KeyGuid, &deviceInfo)) { RegCloseKey(hDeviceIdKey); return GetLastError(); @@ -1364,7 +1503,7 @@ static LONG SETUP_CreateDevList( DWORD dwLength; DWORD rc; - if (IsEqualIID(class, &GUID_NULL)) + if (class && IsEqualIID(class, &GUID_NULL)) class = NULL; /* Open Enum key */ @@ -1378,7 +1517,7 @@ static LONG SETUP_CreateDevList( HKLM = HKEY_LOCAL_MACHINE; rc = RegOpenKeyExW(HKLM, - EnumKeyName, + REGSTR_PATH_SYSTEMENUM, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumKey); @@ -1387,7 +1526,7 @@ static LONG SETUP_CreateDevList( return rc; /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator. - * Else, enumerate all enumerators all call SETUP_CreateDevListFromEnumerator + * Else, enumerate all enumerators and call SETUP_CreateDevListFromEnumerator * for each one. */ if (Enumerator) @@ -1497,7 +1636,7 @@ static LONG SETUP_CreateSerialDeviceList( struct DeviceInterface *interfaceInfo; TRACE("Adding %s to list\n", debugstr_w(ptr)); /* Step 1. Create a device info element */ - if (!CreateDeviceInfoElement(ptr, &GUID_SERENUM_BUS_ENUMERATOR, &deviceInfo)) + if (!CreateDeviceInfoElement(list, ptr, &GUID_SERENUM_BUS_ENUMERATOR, &deviceInfo)) { if (devices != buf) HeapFree(GetProcessHeap(), 0, devices); @@ -1615,10 +1754,10 @@ static LONG SETUP_CreateInterfaceList( /* Find class GUID associated to the device instance */ rc = RegOpenKeyExW( - HKEY_LOCAL_MACHINE, - EnumKeyName, + list->HKLM, + REGSTR_PATH_SYSTEMENUM, 0, /* Options */ - KEY_ENUMERATE_SUB_KEYS, + 0, &hEnumKey); if (rc != ERROR_SUCCESS) { @@ -1669,7 +1808,7 @@ static LONG SETUP_CreateInterfaceList( RegCloseKey(hDeviceInstanceKey); continue; } - + /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */ j = 0; while (TRUE) @@ -1721,7 +1860,7 @@ static LONG SETUP_CreateInterfaceList( /* We have found a device */ /* Step 1. Create a device info element */ - if (!CreateDeviceInfoElement(InstancePath, &ClassGuid, &deviceInfo)) + if (!CreateDeviceInfoElement(list, InstancePath, &ClassGuid, &deviceInfo)) { RegCloseKey(hReferenceKey); RegCloseKey(hDeviceInstanceKey); @@ -1879,69 +2018,367 @@ HDEVINFO WINAPI SetupDiGetClassDevsExW( } /*********************************************************************** - * SetupDiEnumDeviceInterfaces (SETUPAPI.@) + * SetupDiGetClassImageIndex (SETUPAPI.@) */ -BOOL WINAPI SetupDiEnumDeviceInterfaces( - HDEVINFO DeviceInfoSet, - PSP_DEVINFO_DATA DeviceInfoData, - CONST GUID * InterfaceClassGuid, - DWORD MemberIndex, - PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) + +static BOOL GetIconIndex( + IN HKEY hClassKey, + OUT PINT ImageIndex) { + LPWSTR Buffer = NULL; + DWORD dwRegType, dwLength; + LONG rc; BOOL ret = FALSE; - TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData, - debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData); + /* Read icon registry key */ + rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } else if (dwRegType != REG_SZ) + { + SetLastError(ERROR_INVALID_INDEX); + goto cleanup; + } + Buffer = MyMalloc(dwLength + sizeof(WCHAR)); + if (!Buffer) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + /* make sure the returned buffer is NULL-terminated */ + Buffer[dwLength / sizeof(WCHAR)] = 0; - if (!DeviceInterfaceData) + /* Transform icon value to a INT */ + *ImageIndex = atoiW(Buffer); + ret = TRUE; + +cleanup: + MyFree(Buffer); + return ret; +} + +BOOL WINAPI SetupDiGetClassImageIndex( + IN PSP_CLASSIMAGELIST_DATA ClassImageListData, + IN CONST GUID *ClassGuid, + OUT PINT ImageIndex) +{ + struct ClassImageList *list; + BOOL ret = FALSE; + + TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex); + + if (!ClassImageListData || !ClassGuid || !ImageIndex) SetLastError(ERROR_INVALID_PARAMETER); - else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA)) + else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) SetLastError(ERROR_INVALID_USER_BUFFER); - else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE) + else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (!ImageIndex) + SetLastError(ERROR_INVALID_PARAMETER); + else { - struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet; + HKEY hKey = INVALID_HANDLE_VALUE; + INT iconIndex; - if (list->magic == SETUP_DEV_INFO_SET_MAGIC) + /* Read Icon registry entry into Buffer */ + hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INTERFACE, list->MachineName, NULL); + if (hKey == INVALID_HANDLE_VALUE) + goto cleanup; + if (!GetIconIndex(hKey, &iconIndex)) + goto cleanup; + + if (iconIndex >= 0) { - PLIST_ENTRY ItemList = list->ListHead.Flink; - BOOL Found = FALSE; - while (ItemList != &list->ListHead && !Found) - { - PLIST_ENTRY InterfaceListEntry; - struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList; - if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo) - { - /* We are not searching for this element */ - ItemList = ItemList->Flink; - continue; - } - InterfaceListEntry = DevInfo->InterfaceListHead.Flink; - while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found) - { - struct DeviceInterface *DevItf = (struct DeviceInterface *)InterfaceListEntry; - if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid)) - { - InterfaceListEntry = InterfaceListEntry->Flink; - continue; - } - if (MemberIndex-- == 0) - { - /* return this item */ - memcpy(&DeviceInterfaceData->InterfaceClassGuid, - &DevItf->InterfaceClassGuid, - sizeof(GUID)); - DeviceInterfaceData->Flags = 0; /* FIXME */ - /* Note: this appears to be dangerous, passing a private - * pointer a heap-allocated datum to the caller. However, the - * expected lifetime of the device data is the same as the - * HDEVINFO; once that is closed, the data are no longer valid. - */ - DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf; - Found = TRUE; - } - InterfaceListEntry = InterfaceListEntry->Flink; - } - ItemList = ItemList->Flink; + SetLastError(ERROR_INVALID_INDEX); + goto cleanup; + } + + *ImageIndex = -iconIndex; + ret = TRUE; + +cleanup: + if (hKey != INVALID_HANDLE_VALUE) + RegCloseKey(hKey); + } + + TRACE("Returning %d\n", ret); + return ret; +} + +/*********************************************************************** + * SetupDiGetClassImageList(SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassImageList( + OUT PSP_CLASSIMAGELIST_DATA ClassImageListData) +{ + return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL); +} + +/*********************************************************************** + * SetupDiGetClassImageListExA(SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassImageListExA( + OUT PSP_CLASSIMAGELIST_DATA ClassImageListData, + IN PCSTR MachineName OPTIONAL, + IN PVOID Reserved) +{ + PWSTR MachineNameW = NULL; + BOOL ret; + + if (MachineName) + { + MachineNameW = MultiByteToUnicode(MachineName, CP_ACP); + if (MachineNameW == NULL) + return FALSE; + } + + ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved); + + if (MachineNameW) + MyFree(MachineNameW); + + return ret; +} + +/*********************************************************************** + * SetupDiGetClassImageListExW(SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassImageListExW( + OUT PSP_CLASSIMAGELIST_DATA ClassImageListData, + IN PCWSTR MachineName OPTIONAL, + IN PVOID Reserved) +{ + BOOL ret = FALSE; + + TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved); + + if (!ClassImageListData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (Reserved) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + struct ClassImageList *list = NULL; + DWORD size; + + size = FIELD_OFFSET(struct ClassImageList, szData); + if (MachineName) + size += (wcslen(MachineName) + 3) * sizeof(WCHAR); + list = HeapAlloc(GetProcessHeap(), 0, size); + if (!list) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC; + if (MachineName) + { + list->szData[0] = list->szData[1] = '\\'; + strcpyW(list->szData + 2, MachineName); + list->MachineName = list->szData; + } + else + { + list->MachineName = NULL; + } + + ClassImageListData->Reserved = (DWORD)list; /* FIXME: 64 bit portability issue */ + ret = TRUE; + +cleanup: + if (!ret) + MyFree(list); + } + + TRACE("Returning %d\n", ret); + return ret; +} + +/*********************************************************************** + * SetupDiLoadClassIcon(SETUPAPI.@) + */ +BOOL WINAPI SetupDiLoadClassIcon( + IN CONST GUID *ClassGuid, + OUT HICON *LargeIcon OPTIONAL, + OUT PINT MiniIconIndex OPTIONAL) +{ + BOOL ret = FALSE; + + if (!ClassGuid) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + LPWSTR Buffer = NULL; + LPCWSTR DllName; + INT iconIndex; + HKEY hKey = INVALID_HANDLE_VALUE; + + hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE); + if (hKey == INVALID_HANDLE_VALUE) + goto cleanup; + + if (!GetIconIndex(hKey, &iconIndex)) + goto cleanup; + + if (iconIndex > 0) + { + /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */ + PWCHAR Comma; + LONG rc; + DWORD dwRegType, dwLength; + rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength); + if (rc == ERROR_SUCCESS && dwRegType == REG_SZ) + { + Buffer = MyMalloc(dwLength + sizeof(WCHAR)); + if (Buffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + /* make sure the returned buffer is NULL-terminated */ + Buffer[dwLength / sizeof(WCHAR)] = 0; + } + else if + (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength)) + && dwRegType == REG_SZ) + { + Buffer = MyMalloc(dwLength + sizeof(WCHAR)); + if (Buffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + /* make sure the returned buffer is NULL-terminated */ + Buffer[dwLength / sizeof(WCHAR)] = 0; + } + else + { + /* Unable to find where to load the icon */ + SetLastError(ERROR_FILE_NOT_FOUND); + goto cleanup; + } + Comma = strchrW(Buffer, ','); + if (!Comma) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + *Comma = '\0'; + DllName = Buffer; + } + else + { + /* Look up icon in setupapi.dll */ + DllName = L"setupapi.dll"; + iconIndex = -iconIndex; + } + + TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(DllName)); + if (LargeIcon) + { + if (1 != ExtractIconEx(DllName, iconIndex, LargeIcon, NULL, 1)) + { + SetLastError(ERROR_INVALID_INDEX); + goto cleanup; + } + } + if (MiniIconIndex) + *MiniIconIndex = iconIndex; + ret = TRUE; + +cleanup: + if (hKey != INVALID_HANDLE_VALUE) + RegCloseKey(hKey); + MyFree(Buffer); + } + + TRACE("Returning %d\n", ret); + return ret; +} + +/*********************************************************************** + * SetupDiEnumDeviceInterfaces (SETUPAPI.@) + */ +BOOL WINAPI SetupDiEnumDeviceInterfaces( + HDEVINFO DeviceInfoSet, + PSP_DEVINFO_DATA DeviceInfoData, + CONST GUID * InterfaceClassGuid, + DWORD MemberIndex, + PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) +{ + BOOL ret = FALSE; + + TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData, + debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData); + + if (!DeviceInterfaceData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE) + { + struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet; + + if (list->magic == SETUP_DEV_INFO_SET_MAGIC) + { + PLIST_ENTRY ItemList = list->ListHead.Flink; + BOOL Found = FALSE; + while (ItemList != &list->ListHead && !Found) + { + PLIST_ENTRY InterfaceListEntry; + struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList; + if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo) + { + /* We are not searching for this element */ + ItemList = ItemList->Flink; + continue; + } + InterfaceListEntry = DevInfo->InterfaceListHead.Flink; + while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found) + { + struct DeviceInterface *DevItf = (struct DeviceInterface *)InterfaceListEntry; + if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid)) + { + InterfaceListEntry = InterfaceListEntry->Flink; + continue; + } + if (MemberIndex-- == 0) + { + /* return this item */ + memcpy(&DeviceInterfaceData->InterfaceClassGuid, + &DevItf->InterfaceClassGuid, + sizeof(GUID)); + DeviceInterfaceData->Flags = 0; /* FIXME */ + DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf; + Found = TRUE; + } + InterfaceListEntry = InterfaceListEntry->Flink; + } + ItemList = ItemList->Flink; } if (!Found) SetLastError(ERROR_NO_MORE_ITEMS); @@ -1956,6 +2393,76 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces( return ret; } +static VOID ReferenceInfFile(struct InfFileDetails* infFile) +{ + InterlockedIncrement(&infFile->References); +} + +static VOID DereferenceInfFile(struct InfFileDetails* infFile) +{ + if (InterlockedDecrement(&infFile->References) == 0) + { + SetupCloseInfFile(infFile->hInf); + HeapFree(GetProcessHeap(), 0, infFile); + } +} + +static BOOL DestroyDriverInfoElement(struct DriverInfoElement* driverInfo) +{ + DereferenceInfFile(driverInfo->InfFileDetails); + HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId); + HeapFree(GetProcessHeap(), 0, driverInfo); + return TRUE; +} + +static BOOL DestroyClassInstallParams(struct ClassInstallParams* installParams) +{ + HeapFree(GetProcessHeap(), 0, installParams->PropChange); + return TRUE; +} + +static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo) +{ + PLIST_ENTRY ListEntry; + struct DriverInfoElement *driverInfo; + + while (!IsListEmpty(&deviceInfo->DriverListHead)) + { + ListEntry = RemoveHeadList(&deviceInfo->DriverListHead); + driverInfo = (struct DriverInfoElement *)ListEntry; + if (!DestroyDriverInfoElement(driverInfo)) + return FALSE; + } + while (!IsListEmpty(&deviceInfo->InterfaceListHead)) + { + ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead); + HeapFree(GetProcessHeap(), 0, ListEntry); + } + DestroyClassInstallParams(&deviceInfo->ClassInstallParams); + HeapFree(GetProcessHeap(), 0, deviceInfo); + return TRUE; +} + +static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list) +{ + PLIST_ENTRY ListEntry; + struct DeviceInfoElement *deviceInfo; + + while (!IsListEmpty(&list->ListHead)) + { + ListEntry = RemoveHeadList(&list->ListHead); + deviceInfo = (struct DeviceInfoElement *)ListEntry; + if (!DestroyDeviceInfoElement(deviceInfo)) + return FALSE; + } + if (list->HKLM != HKEY_LOCAL_MACHINE) + RegCloseKey(list->HKLM); + CM_Disconnect_Machine(list->hMachine); + DestroyClassInstallParams(&list->ClassInstallParams); + HeapFree(GetProcessHeap(), 0, list); + return TRUE; +} + /*********************************************************************** * SetupDiDestroyDeviceInfoList (SETUPAPI.@) */ @@ -1969,25 +2476,7 @@ BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo) struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo; if (list->magic == SETUP_DEV_INFO_SET_MAGIC) - { - PLIST_ENTRY ListEntry, InterfaceEntry; - struct DeviceInfoElement *deviceInfo; - while (!IsListEmpty(&list->ListHead)) - { - ListEntry = RemoveHeadList(&list->ListHead); - deviceInfo = (struct DeviceInfoElement *)ListEntry; - while (!IsListEmpty(&deviceInfo->InterfaceListHead)) - { - InterfaceEntry = RemoveHeadList(&deviceInfo->InterfaceListHead); - HeapFree(GetProcessHeap(), 0, InterfaceEntry); - } - HeapFree(GetProcessHeap(), 0, ListEntry); - } - if (list->HKLM != HKEY_LOCAL_MACHINE) - RegCloseKey(list->HKLM); - HeapFree(GetProcessHeap(), 0, list); - ret = TRUE; - } + ret = DestroyDeviceInfoSet(list); else SetLastError(ERROR_INVALID_HANDLE); } @@ -2013,7 +2502,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailA( DWORD sizeW = 0, sizeA; BOOL ret = FALSE; - TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet, + TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet, DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); @@ -2081,7 +2570,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW( { BOOL ret = FALSE; - TRACE("(%p, %p, %p, %ld, %p, %p): stub\n", DeviceInfoSet, + TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet, DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData); @@ -2123,12 +2612,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW( memcpy(&DeviceInfoData->ClassGuid, &deviceInterface->DeviceInfo->ClassGuid, sizeof(GUID)); - DeviceInfoData->DevInst = 0; /* FIXME */ - /* Note: this appears to be dangerous, passing a private - * pointer a heap-allocated datum to the caller. However, the - * expected lifetime of the device data is the same as the - * HDEVINFO; once that is closed, the data are no longer valid. - */ + DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst; DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo; } ret = TRUE; @@ -2174,7 +2658,7 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA( PropertyBufferSizeW, &RequiredSizeW); - if (bResult || GetLastError() == ERROR_MORE_DATA) + if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER) { bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ); @@ -2269,45 +2753,48 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW( case SPDRP_SECURITY: case SPDRP_SERVICE: case SPDRP_UI_NUMBER: + case SPDRP_UI_NUMBER_DESC_FORMAT: case SPDRP_UPPERFILTERS: { LPCWSTR RegistryPropertyName; DWORD BufferSize; - + switch (Property) { case SPDRP_CAPABILITIES: - RegistryPropertyName = L"Capabilities"; break; + RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break; case SPDRP_CLASS: - RegistryPropertyName = L"Class"; break; + RegistryPropertyName = REGSTR_VAL_CLASS; break; case SPDRP_CLASSGUID: - RegistryPropertyName = L"ClassGUID"; break; + RegistryPropertyName = REGSTR_VAL_CLASSGUID; break; case SPDRP_COMPATIBLEIDS: - RegistryPropertyName = L"CompatibleIDs"; break; + RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break; case SPDRP_CONFIGFLAGS: - RegistryPropertyName = L"ConfigFlags"; break; + RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break; case SPDRP_DEVICEDESC: - RegistryPropertyName = L"DeviceDesc"; break; + RegistryPropertyName = REGSTR_VAL_DEVDESC; break; case SPDRP_DRIVER: - RegistryPropertyName = L"Driver"; break; + RegistryPropertyName = REGSTR_VAL_DRIVER; break; case SPDRP_FRIENDLYNAME: - RegistryPropertyName = L"FriendlyName"; break; + RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break; case SPDRP_HARDWAREID: - RegistryPropertyName = L"HardwareID"; break; + RegistryPropertyName = REGSTR_VAL_HARDWAREID; break; case SPDRP_LOCATION_INFORMATION: - RegistryPropertyName = L"LocationInformation"; break; + RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break; case SPDRP_LOWERFILTERS: - RegistryPropertyName = L"LowerFilters"; break; + RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break; case SPDRP_MFG: - RegistryPropertyName = L"Mfg"; break; + RegistryPropertyName = REGSTR_VAL_MFG; break; case SPDRP_SECURITY: RegistryPropertyName = L"Security"; break; case SPDRP_SERVICE: - RegistryPropertyName = L"Service"; break; + RegistryPropertyName = REGSTR_VAL_SERVICE; break; case SPDRP_UI_NUMBER: - RegistryPropertyName = L"UINumber"; break; + RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break; + case SPDRP_UI_NUMBER_DESC_FORMAT: + RegistryPropertyName = L"UINumberDescFormat"; break; case SPDRP_UPPERFILTERS: - RegistryPropertyName = L"UpperFilters"; break; + RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break; default: /* Should not happen */ RegistryPropertyName = NULL; break; @@ -2316,9 +2803,9 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW( /* Open registry key name */ rc = RegOpenKeyExW( list->HKLM, - EnumKeyName, + REGSTR_PATH_SYSTEMENUM, 0, /* Options */ - KEY_ENUMERATE_SUB_KEYS, + 0, &hEnumKey); if (rc != ERROR_SUCCESS) { @@ -2348,10 +2835,19 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW( &BufferSize); if (RequiredSize) *RequiredSize = BufferSize; - if (rc == ERROR_SUCCESS) - ret = TRUE; - else - SetLastError(rc); + switch(rc) { + case ERROR_SUCCESS: + if (PropertyBuffer != NULL || BufferSize == 0) + ret = TRUE; + else + SetLastError(ERROR_INSUFFICIENT_BUFFER); + break; + case ERROR_MORE_DATA: + SetLastError(ERROR_INSUFFICIENT_BUFFER); + break; + default: + SetLastError(rc); + } RegCloseKey(hKey); break; } @@ -2383,7 +2879,6 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW( case SPDRP_EXCLUSIVE: case SPDRP_CHARACTERISTICS: case SPDRP_ADDRESS: - case SPDRP_UI_NUMBER_DESC_FORMAT: case SPDRP_DEVICE_POWER_DATA:*/ #if (WINVER >= 0x501) /*case SPDRP_REMOVAL_POLICY: @@ -2394,7 +2889,7 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW( default: { - FIXME("Property 0x%lx not implemented\n", Property); + ERR("Property 0x%lx not implemented\n", Property); SetLastError(ERROR_NOT_SUPPORTED); } } @@ -2404,32 +2899,216 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW( return ret; } - /*********************************************************************** - * SetupDiInstallClassA (SETUPAPI.@) + * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@) */ -BOOL WINAPI SetupDiInstallClassA( - HWND hwndParent, - PCSTR InfFileName, - DWORD Flags, - HSPFILEQ FileQueue) +BOOL WINAPI SetupDiSetDeviceRegistryPropertyA( + IN HDEVINFO DeviceInfoSet, + IN OUT PSP_DEVINFO_DATA DeviceInfoData, + IN DWORD Property, + IN CONST BYTE *PropertyBuffer, + IN DWORD PropertyBufferSize) +{ + FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, + Property, PropertyBuffer, PropertyBufferSize); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/*********************************************************************** + * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiSetDeviceRegistryPropertyW( + IN HDEVINFO DeviceInfoSet, + IN OUT PSP_DEVINFO_DATA DeviceInfoData, + IN DWORD Property, + IN const BYTE *PropertyBuffer, + IN DWORD PropertyBufferSize) +{ + struct DeviceInfoSet *list; + BOOL ret = FALSE; + + TRACE("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, + Property, PropertyBuffer, PropertyBufferSize); + + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_HANDLE); + else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (!DeviceInfoData) + SetLastError(ERROR_INVALID_HANDLE); + else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + switch (Property) + { + case SPDRP_COMPATIBLEIDS: + case SPDRP_CONFIGFLAGS: + case SPDRP_FRIENDLYNAME: + case SPDRP_HARDWAREID: + case SPDRP_LOCATION_INFORMATION: + case SPDRP_LOWERFILTERS: + case SPDRP_SECURITY: + case SPDRP_SERVICE: + case SPDRP_UI_NUMBER_DESC_FORMAT: + case SPDRP_UPPERFILTERS: + { + LPCWSTR RegistryPropertyName; + DWORD RegistryDataType; + HKEY hKey; + LONG rc; + + switch (Property) + { + case SPDRP_COMPATIBLEIDS: + RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; + RegistryDataType = REG_MULTI_SZ; + break; + case SPDRP_CONFIGFLAGS: + RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; + RegistryDataType = REG_DWORD; + break; + case SPDRP_FRIENDLYNAME: + RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; + RegistryDataType = REG_SZ; + break; + case SPDRP_HARDWAREID: + RegistryPropertyName = REGSTR_VAL_HARDWAREID; + RegistryDataType = REG_MULTI_SZ; + break; + case SPDRP_LOCATION_INFORMATION: + RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; + RegistryDataType = REG_SZ; + break; + case SPDRP_LOWERFILTERS: + RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; + RegistryDataType = REG_MULTI_SZ; + break; + case SPDRP_SECURITY: + RegistryPropertyName = L"Security"; + RegistryDataType = REG_BINARY; + break; + case SPDRP_SERVICE: + RegistryPropertyName = REGSTR_VAL_SERVICE; + RegistryDataType = REG_SZ; + break; + case SPDRP_UI_NUMBER_DESC_FORMAT: + RegistryPropertyName = L"UINumberDescFormat"; + RegistryDataType = REG_SZ; + break; + case SPDRP_UPPERFILTERS: + RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; + RegistryDataType = REG_MULTI_SZ; + break; + default: + /* Should not happen */ + RegistryPropertyName = NULL; + RegistryDataType = REG_BINARY; + break; + } + /* Open device registry key */ + hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE); + if (hKey != INVALID_HANDLE_VALUE) + { + /* Write new data */ + rc = RegSetValueExW( + hKey, + RegistryPropertyName, + 0, /* Reserved */ + RegistryDataType, + PropertyBuffer, + PropertyBufferSize); + if (rc == ERROR_SUCCESS) + ret = TRUE; + else + SetLastError(rc); + RegCloseKey(hKey); + } + break; + } + + /*case SPDRP_CHARACTERISTICS: + case SPDRP_DEVTYPE: + case SPDRP_EXCLUSIVE:*/ +#if (WINVER >= 0x501) + //case SPDRP_REMOVAL_POLICY_OVERRIDE: +#endif + //case SPDRP_SECURITY_SDS: + + default: + { + ERR("Property 0x%lx not implemented\n", Property); + SetLastError(ERROR_NOT_SUPPORTED); + } + } + } + + TRACE("Returning %d\n", ret); + return ret; +} + + +/*********************************************************************** + * SetupDiInstallClassA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiInstallClassA( + IN HWND hwndParent OPTIONAL, + IN PCSTR InfFileName, + IN DWORD Flags, + IN HSPFILEQ FileQueue OPTIONAL) +{ + return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL); +} + + +/*********************************************************************** + * SetupDiInstallClassW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiInstallClassW( + IN HWND hwndParent OPTIONAL, + IN PCWSTR InfFileName, + IN DWORD Flags, + IN HSPFILEQ FileQueue OPTIONAL) +{ + return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL); +} + + +/*********************************************************************** + * SetupDiInstallClassExA (SETUPAPI.@) + */ +BOOL WINAPI SetupDiInstallClassExA( + IN HWND hwndParent OPTIONAL, + IN PCSTR InfFileName OPTIONAL, + IN DWORD Flags, + IN HSPFILEQ FileQueue OPTIONAL, + IN const GUID* InterfaceClassGuid OPTIONAL, + IN PVOID Reserved1, + IN PVOID Reserved2) { - UNICODE_STRING FileNameW; + PWSTR InfFileNameW = NULL; BOOL Result; - if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName)) + if (InfFileName) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; + InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP); + if (InfFileNameW == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } } - Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue); + Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags, + FileQueue, InterfaceClassGuid, Reserved1, Reserved2); - RtlFreeUnicodeString(&FileNameW); + MyFree(InfFileNameW); return Result; } + static HKEY CreateClassKey(HINF hInf) { WCHAR FullBuffer[MAX_PATH]; @@ -2449,7 +3128,7 @@ static HKEY CreateClassKey(HINF hInf) return INVALID_HANDLE_VALUE; } - lstrcpyW(FullBuffer, ControlClass); + lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT); lstrcatW(FullBuffer, Buffer); @@ -2470,7 +3149,7 @@ static HKEY CreateClassKey(HINF hInf) 0, NULL, REG_OPTION_NON_VOLATILE, - KEY_ALL_ACCESS, + KEY_SET_VALUE, NULL, &hClassKey, NULL)) @@ -2494,100 +3173,241 @@ static HKEY CreateClassKey(HINF hInf) return hClassKey; } -/*********************************************************************** - * SetupDiInstallClassW (SETUPAPI.@) - */ -BOOL WINAPI SetupDiInstallClassW( - HWND hwndParent, - PCWSTR InfFileName, - DWORD Flags, - HSPFILEQ FileQueue) -{ - WCHAR SectionName[MAX_PATH]; - DWORD SectionNameLength = 0; - HINF hInf; - BOOL bFileQueueCreated = FALSE; - HKEY hClassKey; - - FIXME("not fully implemented\n"); - if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } +static BOOL +InstallServicesSection( + IN HINF hInf, + IN PCWSTR SectionName, + IN HDEVINFO DeviceInfoSet OPTIONAL, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + OUT PCWSTR* pAssociatedService OPTIONAL, + OUT PBOOL pRebootRequired OPTIONAL) +{ + INFCONTEXT ContextService; + DWORD RequiredSize; + INT Flags; + BOOL ret = FALSE; - /* Open the .inf file */ - hInf = SetupOpenInfFileW(InfFileName, - NULL, - INF_STYLE_WIN4, - NULL); - if (hInf == INVALID_HANDLE_VALUE) + ret = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService); + while (ret) { + LPWSTR ServiceName = NULL; + LPWSTR ServiceSection = NULL; - return FALSE; - } + ret = SetupGetStringFieldW( + &ContextService, + 1, /* Field index */ + NULL, 0, + &RequiredSize); + if (!ret) + goto nextservice; + if (RequiredSize > 0) + { + /* We got the needed size for the buffer */ + ServiceName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); + if (!ServiceName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto nextservice; + } + ret = SetupGetStringFieldW( + &ContextService, + 1, /* Field index */ + ServiceName, RequiredSize, + &RequiredSize); + if (!ret) + goto nextservice; + } + ret = SetupGetIntField( + &ContextService, + 2, /* Field index */ + &Flags); + if (!ret) + { + /* The field may be empty. Ignore the error */ + Flags = 0; + } + ret = SetupGetStringFieldW( + &ContextService, + 3, /* Field index */ + NULL, 0, + &RequiredSize); + if (!ret) + { + if (GetLastError() == ERROR_INVALID_PARAMETER) + { + /* This first is probably missing. It is not + * required, so ignore the error */ + RequiredSize = 0; + ret = TRUE; + } + else + goto nextservice; + } + if (RequiredSize > 0) + { + /* We got the needed size for the buffer */ + ServiceSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); + if (!ServiceSection) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto nextservice; + } + ret = SetupGetStringFieldW( + &ContextService, + 3, /* Field index */ + ServiceSection, RequiredSize, + &RequiredSize); + if (!ret) + goto nextservice; - /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */ - hClassKey = CreateClassKey(hInf); - if (hClassKey == INVALID_HANDLE_VALUE) - { - SetupCloseInfFile(hInf); - return FALSE; + SetLastError(ERROR_SUCCESS); + ret = SetupInstallServicesFromInfSectionExW( + hInf, + ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL); + } + if (ret && (Flags & SPSVCINST_ASSOCSERVICE)) + { + if (pAssociatedService) + { + *pAssociatedService = ServiceName; + ServiceName = NULL; + } + if (pRebootRequired && GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) + *pRebootRequired = TRUE; + } +nextservice: + HeapFree(GetProcessHeap(), 0, ServiceName); + HeapFree(GetProcessHeap(), 0, ServiceSection); + if (!ret) + goto done; + ret = SetupFindNextLine(&ContextService, &ContextService); } + ret = TRUE; +done: + return ret; +} - /* Try to append a layout file */ -#if 0 - SetupOpenAppendInfFileW(NULL, hInf, NULL); -#endif +/*********************************************************************** + * SetupDiInstallClassExW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiInstallClassExW( + IN HWND hwndParent OPTIONAL, + IN PCWSTR InfFileName OPTIONAL, + IN DWORD Flags, + IN HSPFILEQ FileQueue OPTIONAL, + IN const GUID* InterfaceClassGuid OPTIONAL, + IN PVOID Reserved1, + IN PVOID Reserved2) +{ + BOOL ret = FALSE; - /* Retrieve the actual section name */ - SetupDiGetActualSectionToInstallW(hInf, - ClassInstall32, - SectionName, - MAX_PATH, - &SectionNameLength, - NULL); + TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags, + FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2); -#if 0 - if (!(Flags & DI_NOVCP)) + if (!InfFileName && !InterfaceClassGuid) + SetLastError(ERROR_INVALID_PARAMETER); + else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL)) { - FileQueue = SetupOpenFileQueue(); - if (FileQueue == INVALID_HANDLE_VALUE) - { - SetupCloseInfFile(hInf); - RegCloseKey(hClassKey); - return FALSE; - } + TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL)); + SetLastError(ERROR_INVALID_FLAGS); + } + else if ((Flags & DI_NOVCP) && FileQueue == NULL) + SetLastError(ERROR_INVALID_PARAMETER); + else if (Reserved1 != NULL) + SetLastError(ERROR_INVALID_PARAMETER); + else if (Reserved2 != NULL) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + WCHAR SectionName[MAX_PATH]; + HINF hInf = INVALID_HANDLE_VALUE; + HKEY hClassKey = INVALID_HANDLE_VALUE; + PVOID callback_context = NULL; + + if (InterfaceClassGuid) + { + /* SetupDiCreateDeviceInterface??? */ + FIXME("Installing an interface is not implemented\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + } + else + { + if (Flags & DI_NOVCP) + FIXME("FileQueue argument ignored\n"); + if (Flags & (DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL)) + FIXME("Flags 0x%lx ignored\n", Flags & (DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL)); + + /* Open the .inf file */ + hInf = SetupOpenInfFileW( + InfFileName, + NULL, + INF_STYLE_WIN4, + NULL); + if (hInf == INVALID_HANDLE_VALUE) + goto cleanup; - bFileQueueCreated = TRUE; + /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */ + hClassKey = CreateClassKey(hInf); + if (hClassKey == INVALID_HANDLE_VALUE) + goto cleanup; - } -#endif + /* Try to append a layout file */ + ret = SetupOpenAppendInfFileW(NULL, hInf, NULL); + if (!ret) + goto cleanup; - SetupInstallFromInfSectionW(NULL, - hInf, - SectionName, - SPINST_REGISTRY, - hClassKey, - NULL, - 0, - NULL, - NULL, - INVALID_HANDLE_VALUE, - NULL); + /* Retrieve the actual section name */ + ret = SetupDiGetActualSectionToInstallW( + hInf, + ClassInstall32, + SectionName, + MAX_PATH - wcslen(DotServices), + NULL, + NULL); + if (!ret) + goto cleanup; - /* FIXME: More code! */ + callback_context = SetupInitDefaultQueueCallback(hwndParent); + if (!callback_context) + goto cleanup; - if (bFileQueueCreated) - SetupCloseFileQueue(FileQueue); + ret = SetupInstallFromInfSectionW( + hwndParent, + hInf, + SectionName, + SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG, + hClassKey, + NULL, /* SourceRootPath */ + 0, /* CopyFlags */ + SetupDefaultQueueCallbackW, + callback_context, + NULL, + NULL); + if (!ret) + goto cleanup; - SetupCloseInfFile(hInf); + /* Install .Services section */ + lstrcatW(SectionName, DotServices); + ret = InstallServicesSection(hInf, SectionName, NULL, NULL, NULL, NULL); + if (!ret) + goto cleanup; - RegCloseKey(hClassKey); - return TRUE; + ret = TRUE; + } + +cleanup: + if (hInf != INVALID_HANDLE_VALUE) + SetupCloseInfFile(hInf); + if (hClassKey != INVALID_HANDLE_VALUE) + RegCloseKey(hClassKey); + SetupTermDefaultQueueCallback(callback_context); + } + + TRACE("Returning %d\n", ret); + return ret; } @@ -2607,10 +3427,10 @@ HKEY WINAPI SetupDiOpenClassRegKey( * SetupDiOpenClassRegKeyExA (SETUPAPI.@) */ HKEY WINAPI SetupDiOpenClassRegKeyExA( - const GUID* ClassGuid, + const GUID* ClassGuid OPTIONAL, REGSAM samDesired, DWORD Flags, - PCSTR MachineName, + PCSTR MachineName OPTIONAL, PVOID Reserved) { PWSTR MachineNameW = NULL; @@ -2639,10 +3459,10 @@ HKEY WINAPI SetupDiOpenClassRegKeyExA( * SetupDiOpenClassRegKeyExW (SETUPAPI.@) */ HKEY WINAPI SetupDiOpenClassRegKeyExW( - const GUID* ClassGuid, + const GUID* ClassGuid OPTIONAL, REGSAM samDesired, DWORD Flags, - PCWSTR MachineName, + PCWSTR MachineName OPTIONAL, PVOID Reserved) { LPWSTR lpGuidString; @@ -2654,18 +3474,21 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW( DWORD rc; LPCWSTR lpKeyName; + TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired, + Flags, debugstr_w(MachineName), Reserved); + if (Flags == DIOCR_INSTALLER) { - lpKeyName = ControlClass; + lpKeyName = REGSTR_PATH_CLASS_NT; } else if (Flags == DIOCR_INTERFACE) { - lpKeyName = DeviceClasses; + lpKeyName = REGSTR_PATH_DEVICE_CLASSES; } else { ERR("Invalid Flags parameter!\n"); - SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_FLAGS); return INVALID_HANDLE_VALUE; } @@ -2684,7 +3507,7 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW( rc = RegOpenKeyExW(HKLM, lpKeyName, 0, - KEY_ALL_ACCESS, + ClassGuid ? 0 : samDesired, &hClassesKey); if (MachineName != NULL) RegCloseKey(HKLM); if (rc != ERROR_SUCCESS) @@ -2720,7 +3543,7 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW( rc = RegOpenKeyExW(hClassesKey, lpFullGuidString, 0, - KEY_ALL_ACCESS, + samDesired, &hClassKey); if (rc != ERROR_SUCCESS) { @@ -2790,11 +3613,142 @@ BOOL WINAPI SetupDiSetClassInstallParamsA( return FALSE; } -static DWORD -GetFunctionPointer( - IN PWSTR InstallerName, - OUT HMODULE* ModulePointer, - OUT PVOID* FunctionPointer) +/*********************************************************************** + * SetupDiSetClassInstallParamsW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiSetClassInstallParamsW( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, + IN DWORD ClassInstallParamsSize) +{ + struct DeviceInfoSet *list; + BOOL ret = FALSE; + + TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData, + ClassInstallParams, ClassInstallParamsSize); + + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) + SetLastError(ERROR_INVALID_HANDLE); + else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER)) + SetLastError(ERROR_INVALID_PARAMETER); + else if (!ClassInstallParams && ClassInstallParamsSize != 0) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + SP_DEVINSTALL_PARAMS_W InstallParams; + BOOL Result; + + InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + if (!Result) + goto done; + + if (ClassInstallParams) + { + /* Check parameters in ClassInstallParams */ + if (ClassInstallParams->InstallFunction < DIF_SELECTDEVICE + || ClassInstallParams->InstallFunction - DIF_SELECTDEVICE >= sizeof(UpdateClassInstallParamHandlers)/sizeof(UpdateClassInstallParamHandlers[0])) + { + SetLastError(ERROR_INVALID_USER_BUFFER); + goto done; + } + else if (UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE] == NULL) + { + FIXME("InstallFunction %u is valid, but has no associated update handler\n", ClassInstallParams->InstallFunction); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + goto done; + } + ret = UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE](DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize); + if (!ret) + goto done; + InstallParams.Flags |= DI_CLASSINSTALLPARAMS; + } + else + { + InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS; + } + + ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + } + +done: + TRACE("Returning %d\n", ret); + return ret; +} + +static BOOL PropertyChangeHandler( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, + IN DWORD ClassInstallParamsSize) +{ + PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams; + BOOL ret = FALSE; + + if (!DeviceInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS)) + SetLastError(ERROR_INVALID_PARAMETER); + else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE + && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE + && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP) + SetLastError(ERROR_INVALID_FLAGS); + else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL + && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC) + SetLastError(ERROR_INVALID_FLAGS); + else if (PropChangeParams + && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP) + && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams; + if (!DeviceInfoData) + { + struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet; + CurrentPropChangeParams = &list->ClassInstallParams.PropChange; + } + else + { + struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; + CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChange; + } + if (*CurrentPropChangeParams) + { + MyFree(*CurrentPropChangeParams); + *CurrentPropChangeParams = NULL; + } + if (PropChangeParams) + { + *CurrentPropChangeParams = MyMalloc(sizeof(SP_PROPCHANGE_PARAMS)); + if (!*CurrentPropChangeParams) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto done; + } + memcpy(*CurrentPropChangeParams, PropChangeParams, sizeof(SP_PROPCHANGE_PARAMS)); + } + ret = TRUE; + } + +done: + return ret; +} + +static DWORD +GetFunctionPointer( + IN PWSTR InstallerName, + OUT HMODULE* ModulePointer, + OUT PVOID* FunctionPointer) { HMODULE hModule = NULL; LPSTR FunctionNameA = NULL; @@ -2811,14 +3765,6 @@ GetFunctionPointer( goto cleanup; } - /* W->A conversion for function name */ - FunctionNameA = UnicodeToMultiByte(Comma + 1, CP_ACP); - if (!FunctionNameA) - { - rc = GetLastError(); - goto cleanup; - } - /* Load library */ *Comma = '\0'; hModule = LoadLibraryW(InstallerName); @@ -2829,6 +3775,18 @@ GetFunctionPointer( goto cleanup; } + /* Skip comma spaces */ + while (*Comma == ',' || isspaceW(*Comma)) + Comma++; + + /* W->A conversion for function name */ + FunctionNameA = UnicodeToMultiByte(Comma, CP_ACP); + if (!FunctionNameA) + { + rc = GetLastError(); + goto cleanup; + } + /* Search function */ *FunctionPointer = GetProcAddress(hModule, FunctionNameA); if (!*FunctionPointer) @@ -2870,7 +3828,7 @@ BOOL WINAPI SetupDiCallClassInstaller( { BOOL ret = FALSE; - TRACE("%ld %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData); + TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData); if (!DeviceInfoSet) SetLastError(ERROR_INVALID_PARAMETER); @@ -2884,6 +3842,7 @@ BOOL WINAPI SetupDiCallClassInstaller( SetLastError(ERROR_INVALID_USER_BUFFER); else { + SP_DEVINSTALL_PARAMS_W InstallParams; #define CLASS_COINSTALLER 0x1 #define DEVICE_COINSTALLER 0x2 #define CLASS_INSTALLER 0x4 @@ -2919,6 +3878,10 @@ BOOL WINAPI SetupDiCallClassInstaller( case DIF_NEWDEVICEWIZARD_PREANALYZE: CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER; break; + case DIF_PROPERTYCHANGE: + CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER; + DefaultHandler = SetupDiChangeState; + break; case DIF_REGISTER_COINSTALLERS: CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER; DefaultHandler = SetupDiRegisterCoDeviceInstallers; @@ -2928,10 +3891,15 @@ BOOL WINAPI SetupDiCallClassInstaller( DefaultHandler = SetupDiSelectBestCompatDrv; break; default: - FIXME("Install function %ld not implemented\n", InstallFunction); - SetLastError(ERROR_INVALID_PARAMETER); + ERR("Install function %u not supported\n", InstallFunction); + SetLastError(ERROR_NOT_SUPPORTED); } + InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); + if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams)) + /* Don't process this call, as a parameter is invalid */ + CanHandle = 0; + if (CanHandle != 0) { LIST_ENTRY ClassCoInstallersListHead; @@ -2949,13 +3917,45 @@ BOOL WINAPI SetupDiCallClassInstaller( if (CanHandle & DEVICE_COINSTALLER) { - FIXME("Doesn't use Device co-installers at the moment\n"); + hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + if (hKey != INVALID_HANDLE_VALUE) + { + rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength); + if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ) + { + LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength); + if (KeyBuffer != NULL) + { + rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength); + if (rc == ERROR_SUCCESS) + { + LPWSTR ptr; + for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1) + { + /* Add coinstaller to DeviceCoInstallersListHead list */ + struct CoInstallerElement *coinstaller; + TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr)); + coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement)); + if (!coinstaller) + continue; + memset(coinstaller, 0, sizeof(struct CoInstallerElement)); + if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS) + InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry); + else + HeapFree(GetProcessHeap(), 0, coinstaller); + } + } + HeapFree(GetProcessHeap(), 0, KeyBuffer); + } + } + RegCloseKey(hKey); + } } if (CanHandle & CLASS_COINSTALLER) { rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Control\\CoDeviceInstallers", + REGSTR_PATH_CODEVICEINSTALLERS, 0, /* Options */ KEY_QUERY_VALUE, &hKey); @@ -2965,7 +3965,7 @@ BOOL WINAPI SetupDiCallClassInstaller( if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK) { rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength); - if (rc == ERROR_SUCCESS && dwRegType == REG_SZ) + if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ) { LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength); if (KeyBuffer != NULL) @@ -2973,11 +3973,20 @@ BOOL WINAPI SetupDiCallClassInstaller( rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength); if (rc == ERROR_SUCCESS) { - LPCWSTR ptr; + LPWSTR ptr; for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1) { /* Add coinstaller to ClassCoInstallersListHead list */ - FIXME("Class coinstaller is '%S'. UNIMPLEMENTED!\n", ptr); + struct CoInstallerElement *coinstaller; + TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr)); + coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement)); + if (!coinstaller) + continue; + memset(coinstaller, 0, sizeof(struct CoInstallerElement)); + if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS) + InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry); + else + HeapFree(GetProcessHeap(), 0, coinstaller); } } HeapFree(GetProcessHeap(), 0, KeyBuffer); @@ -2988,22 +3997,27 @@ BOOL WINAPI SetupDiCallClassInstaller( RegCloseKey(hKey); } } - if (CanHandle & CLASS_INSTALLER) + if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED)) { hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE); if (hKey != INVALID_HANDLE_VALUE) { - rc = RegQueryValueExW(hKey, L"Installer32", NULL, &dwRegType, NULL, &dwLength); + rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength); if (rc == ERROR_SUCCESS && dwRegType == REG_SZ) { LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength); if (KeyBuffer != NULL) { - rc = RegQueryValueExW(hKey, L"Installer32", NULL, NULL, (LPBYTE)KeyBuffer, &dwLength); + rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength); if (rc == ERROR_SUCCESS) { /* Get ClassInstaller function pointer */ - rc = GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller); + TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer)); + if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS) + { + InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED; + SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + } } HeapFree(GetProcessHeap(), 0, KeyBuffer); } @@ -3056,7 +4070,7 @@ BOOL WINAPI SetupDiCallClassInstaller( /* Call default handler */ if (rc == ERROR_DI_DO_DEFAULT) { - if (DefaultHandler /*FIXME && DI_NODI_DEFAULTACTION not set */) + if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION)) { if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData)) rc = NO_ERROR; @@ -3118,6 +4132,45 @@ BOOL WINAPI SetupDiCallClassInstaller( return ret; } +/*********************************************************************** + * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceInfoListDetailW( + IN HDEVINFO DeviceInfoSet, + OUT PSP_DEVINFO_LIST_DETAIL_DATA_W DeviceInfoListDetailData) +{ + struct DeviceInfoSet *list; + BOOL ret = FALSE; + + TRACE("%p %p\n", DeviceInfoSet, DeviceInfoListDetailData); + + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_HANDLE); + else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (!DeviceInfoListDetailData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoListDetailData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + memcpy( + &DeviceInfoListDetailData->ClassGuid, + &list->ClassGuid, + sizeof(GUID)); + DeviceInfoListDetailData->RemoteMachineHandle = list->hMachine; + if (list->MachineName) + strcpyW(DeviceInfoListDetailData->RemoteMachineName, list->MachineName + 2); + else + DeviceInfoListDetailData->RemoteMachineName[0] = 0; + + ret = TRUE; + } + + TRACE("Returning %d\n", ret); + return ret; +} + /*********************************************************************** * SetupDiGetDeviceInstallParamsA (SETUPAPI.@) */ @@ -3168,103 +4221,594 @@ BOOL WINAPI SetupDiGetDeviceInstallParamsW( IN PSP_DEVINFO_DATA DeviceInfoData, OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams) { - FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams); - return FALSE; + struct DeviceInfoSet *list; + BOOL ret = FALSE; + + TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams); + + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_HANDLE); + else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (!DeviceInstallParams) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + PSP_DEVINSTALL_PARAMS_W Source; + + if (DeviceInfoData) + Source = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams; + else + Source = &list->InstallParams; + memcpy(DeviceInstallParams, Source, Source->cbSize); + ret = TRUE; + } + + TRACE("Returning %d\n", ret); + return ret; } /*********************************************************************** - * SetupDiCreateDevRegKey (SETUPAPI.@) + * SetupDiSetDeviceInstallParamsW (SETUPAPI.@) */ -HKEY WINAPI SetupDiCreateDevRegKeyW( - IN HDEVINFO DeviceInfoSet, - IN PSP_DEVINFO_DATA DeviceInfoData, - IN DWORD Scope, - IN DWORD HwProfile, - IN DWORD KeyType, - IN HINF InfHandle OPTIONAL, - IN PCWSTR InfSectionName OPTIONAL) +BOOL WINAPI SetupDiSetDeviceInstallParamsW( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams) { struct DeviceInfoSet *list; - HKEY ret = INVALID_HANDLE_VALUE; + BOOL ret = FALSE; - TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData, - Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName)); + TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams); if (!DeviceInfoSet) SetLastError(ERROR_INVALID_HANDLE); else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) SetLastError(ERROR_INVALID_HANDLE); - else if (!DeviceInfoData) - SetLastError(ERROR_INVALID_PARAMETER); - else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) SetLastError(ERROR_INVALID_USER_BUFFER); - else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC) - SetLastError(ERROR_INVALID_PARAMETER); - else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV) - SetLastError(ERROR_INVALID_PARAMETER); - else if (InfHandle && !InfSectionName) - SetLastError(ERROR_INVALID_PARAMETER); - else if (!InfHandle && InfSectionName) + else if (!DeviceInstallParams) SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W)) + SetLastError(ERROR_INVALID_USER_BUFFER); else { - LPWSTR lpGuidString = NULL; - LPWSTR DriverKey = NULL; /* {GUID}\Index */ - LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */ - DWORD Index; /* Index used in the DriverKey name */ - DWORD rc; - HKEY hClassKey = INVALID_HANDLE_VALUE; - HKEY hDeviceKey = INVALID_HANDLE_VALUE; - HKEY hKey = INVALID_HANDLE_VALUE; + PSP_DEVINSTALL_PARAMS_W Destination; - if (Scope == DICS_FLAG_CONFIGSPECIFIC) - { - FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n"); - goto cleanup; - } + /* FIXME: Validate parameters */ - if (KeyType == DIREG_DEV) + if (DeviceInfoData) + Destination = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams; + else + Destination = &list->InstallParams; + memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize); + ret = TRUE; + } + + TRACE("Returning %d\n", ret); + return ret; +} + +/*********************************************************************** + * SetupDiGetDeviceInstanceIdA(SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceInstanceIdA( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + OUT PSTR DeviceInstanceId OPTIONAL, + IN DWORD DeviceInstanceIdSize, + OUT PDWORD RequiredSize OPTIONAL) +{ + PWSTR DeviceInstanceIdW = NULL; + BOOL ret = FALSE; + + TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData, + DeviceInstanceId, DeviceInstanceIdSize, RequiredSize); + + if (!DeviceInstanceId && DeviceInstanceIdSize > 0) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + if (DeviceInstanceIdSize != 0) { - FIXME("DIREG_DEV case unimplemented\n"); + DeviceInstanceIdW = MyMalloc(DeviceInstanceIdSize * sizeof(WCHAR)); + if (DeviceInstanceIdW == NULL) + return FALSE; } - else /* KeyType == DIREG_DRV */ + + ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, + DeviceInstanceIdW, DeviceInstanceIdSize, + RequiredSize); + + if (ret && DeviceInstanceIdW != NULL) { - if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK) - goto cleanup; - /* The driver key is in HKLM\System\CurrentControlSet\Control\Class\{GUID}\Index */ - DriverKey = HeapAlloc(GetProcessHeap(), 0, (wcslen(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING)); - if (!DriverKey) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - wcscpy(DriverKey, L"{"); - wcscat(DriverKey, lpGuidString); - wcscat(DriverKey, L"}\\"); - pDeviceInstance = &DriverKey[wcslen(DriverKey)]; - rc = RegOpenKeyExW(list->HKLM, - ControlClass, - 0, - KEY_CREATE_SUB_KEY, - &hClassKey); - if (rc != ERROR_SUCCESS) + if (WideCharToMultiByte(CP_ACP, 0, DeviceInstanceIdW, -1, + DeviceInstanceId, DeviceInstanceIdSize, NULL, NULL) == 0) { - SetLastError(rc); - goto cleanup; + DeviceInstanceId[0] = '\0'; + ret = FALSE; } + } + } - /* Try all values for Index between 0 and 9999 */ - Index = 0; - while (Index <= 9999) - { - DWORD Disposition; - wsprintf(pDeviceInstance, L"%04lu", Index); - rc = RegCreateKeyEx(hClassKey, + TRACE("Returning %d\n", ret); + return ret; +} + +/*********************************************************************** + * SetupDiGetDeviceInstanceIdW(SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetDeviceInstanceIdW( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + OUT PWSTR DeviceInstanceId OPTIONAL, + IN DWORD DeviceInstanceIdSize, + OUT PDWORD RequiredSize OPTIONAL) +{ + BOOL ret = FALSE; + + TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData, + DeviceInstanceId, DeviceInstanceIdSize, RequiredSize); + + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_HANDLE); + else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (!DeviceInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (!DeviceInstanceId && DeviceInstanceIdSize > 0) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInstanceId && DeviceInstanceIdSize == 0) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; + DWORD required; + + required = (wcslen(DevInfo->DeviceName) + 1) * sizeof(WCHAR); + if (RequiredSize) + *RequiredSize = required; + + if (required <= DeviceInstanceIdSize) + { + wcscpy(DeviceInstanceId, DevInfo->DeviceName); + ret = TRUE; + } + else + SetLastError(ERROR_INSUFFICIENT_BUFFER); + } + + TRACE("Returning %d\n", ret); + return ret; +} + +/*********************************************************************** + * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassDevPropertySheetsA( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + IN LPPROPSHEETHEADERA PropertySheetHeader, + IN DWORD PropertySheetHeaderPageListSize, + OUT PDWORD RequiredSize OPTIONAL, + IN DWORD PropertySheetType) +{ + PROPSHEETHEADERW psh; + BOOL ret = FALSE; + + TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, + PropertySheetHeader, PropertySheetHeaderPageListSize, + RequiredSize, PropertySheetType); + + psh.dwFlags = PropertySheetHeader->dwFlags; + psh.phpage = PropertySheetHeader->phpage; + psh.nPages = PropertySheetHeader->nPages; + + ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL, + PropertySheetHeaderPageListSize, RequiredSize, + PropertySheetType); + if (ret) + { + PropertySheetHeader->nPages = psh.nPages; + } + + TRACE("Returning %d\n", ret); + return ret; +} + +struct ClassDevPropertySheetsData +{ + HPROPSHEETPAGE *PropertySheetPages; + DWORD MaximumNumberOfPages; + DWORD NumberOfPages; +}; + +static BOOL WINAPI GetClassDevPropertySheetsCallback( + IN HPROPSHEETPAGE hPropSheetPage, + IN OUT LPARAM lParam) +{ + struct ClassDevPropertySheetsData *PropPageData; + + PropPageData = (struct ClassDevPropertySheetsData *)lParam; + + if (PropPageData->NumberOfPages < PropPageData->MaximumNumberOfPages) + { + *PropPageData->PropertySheetPages = hPropSheetPage; + PropPageData->PropertySheetPages++; + } + + PropPageData->NumberOfPages++; + return TRUE; +} + +/*********************************************************************** + * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@) + */ +BOOL WINAPI SetupDiGetClassDevPropertySheetsW( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + IN OUT LPPROPSHEETHEADERW PropertySheetHeader, + IN DWORD PropertySheetHeaderPageListSize, + OUT PDWORD RequiredSize OPTIONAL, + IN DWORD PropertySheetType) +{ + struct DeviceInfoSet *list; + BOOL ret = FALSE; + + TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, + PropertySheetHeader, PropertySheetHeaderPageListSize, + RequiredSize, PropertySheetType); + + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_HANDLE); + else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (!PropertySheetHeader) + SetLastError(ERROR_INVALID_PARAMETER); + else if (PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE) + SetLastError(ERROR_INVALID_FLAGS); + else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (!DeviceInfoData && IsEqualIID(&list->ClassGuid, &GUID_NULL)) + SetLastError(ERROR_INVALID_PARAMETER); + else if (!PropertySheetHeader) + SetLastError(ERROR_INVALID_PARAMETER); + else if (PropertySheetType != DIGCDP_FLAG_ADVANCED + && PropertySheetType != DIGCDP_FLAG_BASIC + && PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED + && PropertySheetType != DIGCDP_FLAG_REMOTE_BASIC) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + HKEY hKey = INVALID_HANDLE_VALUE; + SP_PROPSHEETPAGE_REQUEST Request; + LPWSTR PropPageProvider = NULL; + HMODULE hModule = NULL; + PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL; + struct ClassDevPropertySheetsData PropPageData; + DWORD dwLength, dwRegType; + DWORD rc; + + if (DeviceInfoData) + hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + else + { + hKey = SetupDiOpenClassRegKeyExW(&list->ClassGuid, KEY_QUERY_VALUE, + DIOCR_INSTALLER, list->MachineName + 2, NULL); + } + if (hKey == INVALID_HANDLE_VALUE) + goto cleanup; + + rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength); + if (rc == ERROR_FILE_NOT_FOUND) + { + /* No registry key. As it is optional, don't say it's a bad error */ + if (RequiredSize) + *RequiredSize = 0; + ret = TRUE; + goto cleanup; + } + else if (rc != ERROR_SUCCESS && dwRegType != REG_SZ) + { + SetLastError(rc); + goto cleanup; + } + + PropPageProvider = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR)); + if (!PropPageProvider) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + PropPageProvider[dwLength / sizeof(WCHAR)] = 0; + + rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider); + if (rc != ERROR_SUCCESS) + { + SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER); + goto cleanup; + } + + Request.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST); + Request.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES; + Request.DeviceInfoSet = DeviceInfoSet; + Request.DeviceInfoData = DeviceInfoData; + PropPageData.PropertySheetPages = &PropertySheetHeader->phpage[PropertySheetHeader->nPages]; + PropPageData.MaximumNumberOfPages = PropertySheetHeaderPageListSize - PropertySheetHeader->nPages; + PropPageData.NumberOfPages = 0; + ret = pPropPageProvider(&Request, GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData); + if (!ret) + goto cleanup; + + if (RequiredSize) + *RequiredSize = PropPageData.NumberOfPages + PropertySheetHeader->nPages; + if (PropPageData.NumberOfPages <= PropPageData.MaximumNumberOfPages) + { + PropertySheetHeader->nPages += PropPageData.NumberOfPages; + ret = TRUE; + } + else + { + PropertySheetHeader->nPages += PropPageData.MaximumNumberOfPages; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + } + +cleanup: + if (hKey != INVALID_HANDLE_VALUE) + RegCloseKey(hKey); + HeapFree(GetProcessHeap(), 0, PropPageProvider); + FreeFunctionPointer(hModule, pPropPageProvider); + } + + TRACE("Returning %d\n", ret); + return ret; +} + +/*********************************************************************** + * SetupDiCreateDevRegKeyA (SETUPAPI.@) + */ +HKEY WINAPI SetupDiCreateDevRegKeyA( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN DWORD Scope, + IN DWORD HwProfile, + IN DWORD KeyType, + IN HINF InfHandle OPTIONAL, + IN PCSTR InfSectionName OPTIONAL) +{ + PCWSTR InfSectionNameW = NULL; + HKEY ret = INVALID_HANDLE_VALUE; + + if (InfSectionName) + { + InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP); + if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE; + } + + ret = SetupDiCreateDevRegKeyW(DeviceInfoSet, + DeviceInfoData, + Scope, + HwProfile, + KeyType, + InfHandle, + InfSectionNameW); + + if (InfSectionNameW != NULL) + MyFree((PVOID)InfSectionNameW); + + return ret; +} + +static HKEY +OpenHardwareProfileKey( + IN HKEY HKLM, + IN DWORD HwProfile, + IN DWORD samDesired) +{ + HKEY hHWProfilesKey = INVALID_HANDLE_VALUE; + HKEY hHWProfileKey = INVALID_HANDLE_VALUE; + HKEY ret = INVALID_HANDLE_VALUE; + LONG rc; + + rc = RegOpenKeyExW(HKLM, + REGSTR_PATH_HWPROFILES, + 0, + 0, + &hHWProfilesKey); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + if (HwProfile == 0) + { + rc = RegOpenKeyExW( + hHWProfilesKey, + REGSTR_KEY_CURRENT, + 0, + KEY_CREATE_SUB_KEY, + &hHWProfileKey); + } + else + { + WCHAR subKey[5]; + snprintfW(subKey, 4, L"%04lu", HwProfile); + subKey[4] = '\0'; + rc = RegOpenKeyExW( + hHWProfilesKey, + subKey, + 0, + KEY_CREATE_SUB_KEY, + &hHWProfileKey); + } + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + ret = hHWProfileKey; + +cleanup: + if (hHWProfilesKey != INVALID_HANDLE_VALUE) + RegCloseKey(hHWProfilesKey); + if (hHWProfileKey != INVALID_HANDLE_VALUE && hHWProfileKey != ret) + RegCloseKey(hHWProfileKey); + return ret; +} + +/*********************************************************************** + * SetupDiCreateDevRegKeyW (SETUPAPI.@) + */ +HKEY WINAPI SetupDiCreateDevRegKeyW( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN DWORD Scope, + IN DWORD HwProfile, + IN DWORD KeyType, + IN HINF InfHandle OPTIONAL, + IN PCWSTR InfSectionName OPTIONAL) +{ + struct DeviceInfoSet *list; + HKEY ret = INVALID_HANDLE_VALUE; + + TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData, + Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName)); + + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_HANDLE); + else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (!DeviceInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC) + SetLastError(ERROR_INVALID_PARAMETER); + else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV) + SetLastError(ERROR_INVALID_PARAMETER); + else if (InfHandle && !InfSectionName) + SetLastError(ERROR_INVALID_PARAMETER); + else if (!InfHandle && InfSectionName) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + LPWSTR lpGuidString = NULL; + LPWSTR DriverKey = NULL; /* {GUID}\Index */ + LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */ + DWORD Index; /* Index used in the DriverKey name */ + DWORD rc; + HKEY hHWProfileKey = INVALID_HANDLE_VALUE; + HKEY hEnumKey = INVALID_HANDLE_VALUE; + HKEY hClassKey = INVALID_HANDLE_VALUE; + HKEY hDeviceKey = INVALID_HANDLE_VALUE; + HKEY hKey = INVALID_HANDLE_VALUE; + HKEY RootKey; + + if (Scope == DICS_FLAG_GLOBAL) + RootKey = list->HKLM; + else /* Scope == DICS_FLAG_CONFIGSPECIFIC */ + { + hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, KEY_CREATE_SUB_KEY); + if (hHWProfileKey == INVALID_HANDLE_VALUE) + goto cleanup; + RootKey = hHWProfileKey; + } + + if (KeyType == DIREG_DEV) + { + struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; + + rc = RegCreateKeyExW( + RootKey, + REGSTR_PATH_SYSTEMENUM, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_CREATE_SUB_KEY, + NULL, + &hEnumKey, + NULL); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + rc = RegCreateKeyExW( + hEnumKey, + deviceInfo->DeviceName, + 0, + NULL, + REG_OPTION_NON_VOLATILE, +#if _WIN32_WINNT >= 0x502 + KEY_READ | KEY_WRITE, +#else + KEY_ALL_ACCESS, +#endif + NULL, + &hKey, + NULL); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + } + else /* KeyType == DIREG_DRV */ + { + if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK) + goto cleanup; + /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */ + DriverKey = HeapAlloc(GetProcessHeap(), 0, (wcslen(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING)); + if (!DriverKey) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + wcscpy(DriverKey, L"{"); + wcscat(DriverKey, lpGuidString); + wcscat(DriverKey, L"}\\"); + pDeviceInstance = &DriverKey[wcslen(DriverKey)]; + rc = RegOpenKeyExW(RootKey, + REGSTR_PATH_CLASS_NT, + 0, + KEY_CREATE_SUB_KEY, + &hClassKey); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + + /* Try all values for Index between 0 and 9999 */ + Index = 0; + while (Index <= 9999) + { + DWORD Disposition; + wsprintf(pDeviceInstance, L"%04lu", Index); + rc = RegCreateKeyEx(hClassKey, DriverKey, 0, NULL, REG_OPTION_NON_VOLATILE, +#if _WIN32_WINNT >= 0x502 KEY_READ | KEY_WRITE, +#else + KEY_ALL_ACCESS, +#endif NULL, &hKey, &Disposition); @@ -3290,7 +4834,7 @@ HKEY WINAPI SetupDiCreateDevRegKeyW( hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_SET_VALUE); if (hDeviceKey == INVALID_HANDLE_VALUE) goto cleanup; - rc = RegSetValueEx(hDeviceKey, L"Driver", 0, REG_SZ, (const BYTE *)DriverKey, (wcslen(DriverKey) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (wcslen(DriverKey) + 1) * sizeof(WCHAR)); if (rc != ERROR_SUCCESS) { SetLastError(rc); @@ -3310,6 +4854,10 @@ cleanup: if (lpGuidString) RpcStringFreeW(&lpGuidString); HeapFree(GetProcessHeap(), 0, DriverKey); + if (hHWProfileKey != INVALID_HANDLE_VALUE) + RegCloseKey(hHWProfileKey); + if (hEnumKey != INVALID_HANDLE_VALUE) + RegCloseKey(hEnumKey); if (hClassKey != INVALID_HANDLE_VALUE) RegCloseKey(hClassKey); if (hDeviceKey != INVALID_HANDLE_VALUE) @@ -3353,104 +4901,112 @@ HKEY WINAPI SetupDiOpenDevRegKey( SetLastError(ERROR_INVALID_PARAMETER); else { - HKEY hKey = INVALID_HANDLE_VALUE; - HKEY hRootKey = INVALID_HANDLE_VALUE; struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; LPWSTR DriverKey = NULL; DWORD dwLength = 0; DWORD dwRegType; DWORD rc; + HKEY hHWProfileKey = INVALID_HANDLE_VALUE; + HKEY hEnumKey = INVALID_HANDLE_VALUE; + HKEY hKey = INVALID_HANDLE_VALUE; + HKEY RootKey; - if (Scope == DICS_FLAG_CONFIGSPECIFIC) + if (Scope == DICS_FLAG_GLOBAL) + RootKey = list->HKLM; + else /* Scope == DICS_FLAG_CONFIGSPECIFIC */ { - FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n"); + hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, 0); + if (hHWProfileKey == INVALID_HANDLE_VALUE) + goto cleanup; + RootKey = hHWProfileKey; } - else /* Scope == DICS_FLAG_GLOBAL */ + + rc = RegOpenKeyExW( + RootKey, + REGSTR_PATH_SYSTEMENUM, + 0, /* Options */ + 0, + &hEnumKey); + if (rc != ERROR_SUCCESS) { - rc = RegOpenKeyExW( - list->HKLM, - EnumKeyName, - 0, /* Options */ - KEY_ENUMERATE_SUB_KEYS, - &hRootKey); - if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - goto cleanup; - } - rc = RegOpenKeyExW( - hRootKey, - deviceInfo->DeviceName, - 0, /* Options */ - KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE, - &hKey); - RegCloseKey(hRootKey); - hRootKey = INVALID_HANDLE_VALUE; - if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - goto cleanup; - } - if (KeyType == DIREG_DEV) - { - /* We're done. Just return the hKey handle */ - ret = hKey; - goto cleanup; - } - /* Read the 'Driver' key */ - rc = RegQueryValueExW(hKey, L"Driver", NULL, &dwRegType, NULL, &dwLength); - if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - goto cleanup; - } - if (dwRegType != REG_SZ) - { - SetLastError(ERROR_GEN_FAILURE); - goto cleanup; - } - DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength); - if (!DriverKey) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - rc = RegQueryValueExW(hKey, L"Driver", NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength); - if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - goto cleanup; - } - RegCloseKey(hKey); - hKey = INVALID_HANDLE_VALUE; - /* Need to open the driver key */ - rc = RegOpenKeyExW( - list->HKLM, - ControlClass, - 0, /* Options */ - KEY_ENUMERATE_SUB_KEYS, - &hRootKey); - if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - goto cleanup; - } - rc = RegOpenKeyExW( - hRootKey, - DriverKey, - 0, /* Options */ - samDesired, - &hKey); - if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - goto cleanup; - } + SetLastError(rc); + goto cleanup; + } + rc = RegOpenKeyExW( + hEnumKey, + deviceInfo->DeviceName, + 0, /* Options */ + KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE, + &hKey); + RegCloseKey(hEnumKey); + hEnumKey = INVALID_HANDLE_VALUE; + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + if (KeyType == DIREG_DEV) + { + /* We're done. Just return the hKey handle */ ret = hKey; + goto cleanup; + } + /* Read the 'Driver' key */ + rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + else if (dwRegType != REG_SZ) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength); + if (!DriverKey) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; } + rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + RegCloseKey(hKey); + hKey = INVALID_HANDLE_VALUE; + /* Need to open the driver key */ + rc = RegOpenKeyExW( + RootKey, + REGSTR_PATH_CLASS_NT, + 0, /* Options */ + 0, + &hEnumKey); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + rc = RegOpenKeyExW( + hEnumKey, + DriverKey, + 0, /* Options */ + samDesired, + &hKey); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + ret = hKey; + cleanup: - if (hRootKey != INVALID_HANDLE_VALUE) - RegCloseKey(hRootKey); + if (hHWProfileKey != INVALID_HANDLE_VALUE) + RegCloseKey(hHWProfileKey); + if (hEnumKey != INVALID_HANDLE_VALUE) + RegCloseKey(hEnumKey); if (hKey != INVALID_HANDLE_VALUE && hKey != ret) RegCloseKey(hKey); } @@ -3533,7 +5089,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW( else if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS)) { TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS)); - SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_FLAGS); } else { @@ -3542,7 +5098,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW( if (CreationFlags & DICD_GENERATE_ID) { /* Generate a new unique ID for this device */ - SetLastError(ERROR_GEN_FAILURE); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); FIXME("not implemented\n"); } else @@ -3569,8 +5125,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW( { struct DeviceInfoElement *deviceInfo; - /* FIXME: ClassGuid can be NULL */ - if (CreateDeviceInfoElement(DeviceName, ClassGuid, &deviceInfo)) + if (CreateDeviceInfoElement(list, DeviceName, ClassGuid, &deviceInfo)) { InsertTailList(&list->ListHead, &deviceInfo->ListEntry); @@ -3585,7 +5140,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW( else { memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID)); - DeviceInfoData->DevInst = 0; /* FIXME */ + DeviceInfoData->DevInst = deviceInfo->dnDevInst; DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo; ret = TRUE; } @@ -3608,6 +5163,7 @@ AddDriverToList( IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */ IN LPGUID ClassGuid, IN INFCONTEXT ContextDevice, + IN struct InfFileDetails *InfFileDetails, IN LPCWSTR InfFile, IN LPCWSTR ProviderName, IN LPCWSTR ManufacturerName, @@ -3617,10 +5173,10 @@ AddDriverToList( IN DWORD Rank) { struct DriverInfoElement *driverInfo = NULL; + HANDLE hFile = INVALID_HANDLE_VALUE; DWORD RequiredSize = 128; /* Initial buffer size */ BOOL Result = FALSE; PLIST_ENTRY PreviousEntry; - LPWSTR DeviceDescription = NULL; LPWSTR InfInstallSection = NULL; BOOL ret = FALSE; @@ -3632,34 +5188,38 @@ AddDriverToList( } memset(driverInfo, 0, sizeof(struct DriverInfoElement)); - /* Fill InfSection field */ - SetLastError(ERROR_INSUFFICIENT_BUFFER); - while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - HeapFree(GetProcessHeap(), 0, driverInfo->InfSection); - driverInfo->InfSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); - if (!driverInfo->InfSection) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - Result = SetupGetStringFieldW( - &ContextDevice, - 1, - driverInfo->InfSection, RequiredSize, - &RequiredSize); - } + driverInfo->Details.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); + driverInfo->Details.Reserved = (ULONG_PTR)driverInfo; + + /* Copy InfFileName field */ + wcsncpy(driverInfo->Details.InfFileName, InfFile, MAX_PATH - 1); + driverInfo->Details.InfFileName[MAX_PATH - 1] = '\0'; + + /* Fill InfDate field */ + /* FIXME: hFile = CreateFile(driverInfo->Details.InfFileName, + GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + goto cleanup; + Result = GetFileTime(hFile, NULL, NULL, &driverInfo->Details.InfDate); + if (!Result) + goto cleanup;*/ + + /* Fill SectionName field */ + Result = SetupGetStringFieldW( + &ContextDevice, + 1, + driverInfo->Details.SectionName, LINE_LEN, + NULL); if (!Result) goto cleanup; - /* Copy InfFile information */ - driverInfo->InfPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(InfFile) + 1) * sizeof(WCHAR)); - if (!driverInfo->InfPath) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - RtlCopyMemory(driverInfo->InfPath, InfFile, (wcslen(InfFile) + 1) * sizeof(WCHAR)); + /* Fill DrvDescription field */ + Result = SetupGetStringFieldW( + &ContextDevice, + 0, /* Field index */ + driverInfo->Details.DrvDescription, LINE_LEN, + NULL); /* Copy MatchingId information */ driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (wcslen(MatchingId) + 1) * sizeof(WCHAR)); @@ -3670,25 +5230,6 @@ AddDriverToList( } RtlCopyMemory(driverInfo->MatchingId, MatchingId, (wcslen(MatchingId) + 1) * sizeof(WCHAR)); - /* Get device description */ - Result = FALSE; - RequiredSize = 128; /* Initial buffer size */ - SetLastError(ERROR_INSUFFICIENT_BUFFER); - while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - HeapFree(GetProcessHeap(), 0, DeviceDescription); - DeviceDescription = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); - if (!DeviceDescription) - goto cleanup; - Result = SetupGetStringFieldW( - &ContextDevice, - 0, /* Field index */ - DeviceDescription, RequiredSize, - &RequiredSize); - } - if (!Result) - goto cleanup; - /* Get inf install section */ Result = FALSE; RequiredSize = 128; /* Initial buffer size */ @@ -3709,13 +5250,14 @@ AddDriverToList( goto cleanup; TRACE("Adding driver '%S' [%S/%S] (Rank 0x%lx)\n", - DeviceDescription, InfFile, InfInstallSection, Rank); + driverInfo->Details.DrvDescription, InfFile, InfInstallSection, Rank); driverInfo->DriverRank = Rank; + memcpy(&driverInfo->DriverDate, &DriverDate, sizeof(FILETIME)); memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID)); driverInfo->Info.DriverType = DriverType; driverInfo->Info.Reserved = (ULONG_PTR)driverInfo; - wcsncpy(driverInfo->Info.Description, DeviceDescription, LINE_LEN - 1); + wcsncpy(driverInfo->Info.Description, driverInfo->Details.DrvDescription, LINE_LEN - 1); driverInfo->Info.Description[LINE_LEN - 1] = '\0'; wcsncpy(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1); driverInfo->Info.MfgName[LINE_LEN - 1] = '\0'; @@ -3728,17 +5270,23 @@ AddDriverToList( driverInfo->Info.ProviderName[0] = '\0'; driverInfo->Info.DriverDate = DriverDate; driverInfo->Info.DriverVersion = DriverVersion; + ReferenceInfFile(InfFileDetails); + driverInfo->InfFileDetails = InfFileDetails; /* Insert current driver in driver list, according to its rank */ PreviousEntry = DriverListHead->Flink; while (PreviousEntry != DriverListHead) { - if (((struct DriverInfoElement *)PreviousEntry)->DriverRank >= Rank) + struct DriverInfoElement *CurrentDriver; + CurrentDriver = CONTAINING_RECORD(PreviousEntry, struct DriverInfoElement, ListEntry); + if (CurrentDriver->DriverRank > Rank || + (CurrentDriver->DriverRank == Rank && CurrentDriver->DriverDate.QuadPart > driverInfo->DriverDate.QuadPart)) { /* Insert before the current item */ InsertHeadList(PreviousEntry, &driverInfo->ListEntry); break; } + PreviousEntry = PreviousEntry->Flink; } if (PreviousEntry == DriverListHead) { @@ -3752,14 +5300,11 @@ cleanup: if (!ret) { if (driverInfo) - { - HeapFree(GetProcessHeap(), 0, driverInfo->InfPath); - HeapFree(GetProcessHeap(), 0, driverInfo->InfSection); HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId); - } HeapFree(GetProcessHeap(), 0, driverInfo); } - HeapFree(GetProcessHeap(), 0, DeviceDescription); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); HeapFree(GetProcessHeap(), 0, InfInstallSection); return ret; @@ -3871,7 +5416,36 @@ GetVersionInformationFromInfFile( } /* Get driver version. Invalid version = 0.0.0.0 */ *DriverVersion = 0; - /* FIXME: use pVersion to fill DriverVersion variable */ + if (pVersion) + { + WORD Major, Minor = 0, Revision = 0, Build = 0; + LPWSTR pMinor = NULL, pRevision = NULL, pBuild = NULL; + LARGE_INTEGER fullVersion; + + pMinor = strchrW(pVersion, '.'); + if (pMinor) + { + *pMinor = 0; + pRevision = strchrW(++pMinor, '.'); + Minor = atoiW(pMinor); + } + if (pRevision) + { + *pRevision = 0; + pBuild = strchrW(++pRevision, '.'); + Revision = atoiW(pRevision); + } + if (pBuild) + { + *pBuild = 0; + pBuild++; + Build = atoiW(pBuild); + } + Major = atoiW(pVersion); + fullVersion.u.HighPart = Major << 16 | Minor; + fullVersion.u.LowPart = Revision << 16 | Build; + memcpy(DriverVersion, &fullVersion, sizeof(LARGE_INTEGER)); + } ret = TRUE; @@ -3880,7 +5454,6 @@ cleanup: HeapFree(GetProcessHeap(), 0, ProviderName); HeapFree(GetProcessHeap(), 0, DriverVer); - TRACE("Returning %d\n", ret); return ret; } @@ -3894,13 +5467,15 @@ SetupDiBuildDriverInfoList( IN DWORD DriverType) { struct DeviceInfoSet *list; + SP_DEVINSTALL_PARAMS_W InstallParams; PVOID Buffer = NULL; - HINF hInf = INVALID_HANDLE_VALUE; + struct InfFileDetails *currentInfFileDetails = NULL; LPWSTR ProviderName = NULL; LPWSTR ManufacturerName = NULL; - LPWSTR ManufacturerSection = NULL; + WCHAR ManufacturerSection[LINE_LEN + 1]; LPWSTR HardwareIDs = NULL; LPWSTR CompatibleIDs = NULL; + LPWSTR FullInfFileName = NULL; FILETIME DriverDate; DWORDLONG DriverVersion = 0; DWORD RequiredSize; @@ -3924,7 +5499,12 @@ SetupDiBuildDriverInfoList( SetLastError(ERROR_INVALID_USER_BUFFER); else { - BOOL Result = FALSE; + BOOL Result; + + InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + if (!Result) + goto done; if (DriverType == SPDIT_COMPATDRIVER) { @@ -4001,34 +5581,84 @@ SetupDiBuildDriverInfoList( break; } Result = SetupGetInfFileListW( - NULL, /* Directory path */ + *InstallParams.DriverPath ? InstallParams.DriverPath : NULL, INF_STYLE_WIN4, Buffer, RequiredSize, &RequiredSize); } + if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND) + { + /* No .inf file in specified directory. So, we should + * success as we created an empty driver info list. + */ + ret = TRUE; + goto done; + } if (Result) { LPCWSTR filename; + LPWSTR pFullFilename; + + if (*InstallParams.DriverPath) + { + DWORD len; + len = GetFullPathNameW(InstallParams.DriverPath, 0, NULL, NULL); + if (len == 0) + goto done; + FullInfFileName = HeapAlloc(GetProcessHeap(), 0, len + MAX_PATH); + if (!FullInfFileName) + goto done; + len = GetFullPathNameW(InstallParams.DriverPath, len, FullInfFileName, NULL); + if (len == 0) + goto done; + if (*FullInfFileName && FullInfFileName[wcslen(FullInfFileName) - 1] != '\\') + wcscat(FullInfFileName, L"\\"); + pFullFilename = &FullInfFileName[wcslen(FullInfFileName)]; + } + else + { + FullInfFileName = HeapAlloc(GetProcessHeap(), 0, MAX_PATH); + if (!FullInfFileName) + goto done; + pFullFilename = &FullInfFileName[0]; + } for (filename = (LPCWSTR)Buffer; *filename; filename += wcslen(filename) + 1) { INFCONTEXT ContextManufacturer, ContextDevice; GUID ClassGuid; - TRACE("Opening file %S\n", filename); - hInf = SetupOpenInfFileW(filename, NULL, INF_STYLE_WIN4, NULL); - if (hInf == INVALID_HANDLE_VALUE) + wcscpy(pFullFilename, filename); + TRACE("Opening file %S\n", FullInfFileName); + + currentInfFileDetails = HeapAlloc( + GetProcessHeap(), + 0, + FIELD_OFFSET(struct InfFileDetails, FullInfFileName) + wcslen(FullInfFileName) * sizeof(WCHAR) + UNICODE_NULL); + if (!currentInfFileDetails) + continue; + memset(currentInfFileDetails, 0, sizeof(struct InfFileDetails)); + wcscpy(currentInfFileDetails->FullInfFileName, FullInfFileName); + + currentInfFileDetails->hInf = SetupOpenInfFileW(FullInfFileName, NULL, INF_STYLE_WIN4, NULL); + ReferenceInfFile(currentInfFileDetails); + if (currentInfFileDetails->hInf == INVALID_HANDLE_VALUE) + { + HeapFree(GetProcessHeap(), 0, currentInfFileDetails); + currentInfFileDetails = NULL; continue; + } if (!GetVersionInformationFromInfFile( - hInf, + currentInfFileDetails->hInf, &ClassGuid, &ProviderName, &DriverDate, &DriverVersion)) { - SetupCloseInfFile(hInf); - hInf = INVALID_HANDLE_VALUE; + SetupCloseInfFile(currentInfFileDetails->hInf); + HeapFree(GetProcessHeap(), 0, currentInfFileDetails->hInf); + currentInfFileDetails = NULL; continue; } @@ -4042,7 +5672,7 @@ SetupDiBuildDriverInfoList( } /* Get the manufacturers list */ - Result = SetupFindFirstLineW(hInf, L"Manufacturer", NULL, &ContextManufacturer); + Result = SetupFindFirstLineW(currentInfFileDetails->hInf, L"Manufacturer", NULL, &ContextManufacturer); while (Result) { Result = SetupGetStringFieldW( @@ -4065,29 +5695,24 @@ SetupDiBuildDriverInfoList( ManufacturerName, RequiredSize, &RequiredSize); } + /* Get manufacturer section name */ Result = SetupGetStringFieldW( &ContextManufacturer, 1, /* Field index */ - NULL, 0, + ManufacturerSection, LINE_LEN, &RequiredSize); if (Result) { - /* We got the needed size for the buffer */ - ManufacturerSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); - if (!ManufacturerSection) + ManufacturerSection[RequiredSize] = 0; /* Final NULL char */ + /* Add (possible) extension to manufacturer section name */ + Result = SetupDiGetActualSectionToInstallW( + currentInfFileDetails->hInf, ManufacturerSection, ManufacturerSection, LINE_LEN, NULL, NULL); + if (Result) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto done; + TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection); + Result = SetupFindFirstLineW(currentInfFileDetails->hInf, ManufacturerSection, NULL, &ContextDevice); } - Result = SetupGetStringFieldW( - &ContextManufacturer, - 1, /* Field index */ - ManufacturerSection, RequiredSize, - &RequiredSize); } - - TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection); - Result = SetupFindFirstLineW(hInf, ManufacturerSection, NULL, &ContextDevice); while (Result) { if (DriverType == SPDIT_CLASSDRIVER) @@ -4098,6 +5723,7 @@ SetupDiBuildDriverInfoList( DriverType, &ClassGuid, ContextDevice, + currentInfFileDetails, filename, ProviderName, ManufacturerName, @@ -4146,13 +5772,14 @@ SetupDiBuildDriverInfoList( DriverAlreadyAdded = FALSE; for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++) { - if (wcscmp(DeviceId, currentId) == 0) + if (wcsicmp(DeviceId, currentId) == 0) { AddDriverToList( &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead, DriverType, &ClassGuid, ContextDevice, + currentInfFileDetails, filename, ProviderName, ManufacturerName, @@ -4166,13 +5793,14 @@ SetupDiBuildDriverInfoList( { for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++) { - if (wcscmp(DeviceId, currentId) == 0) + if (wcsicmp(DeviceId, currentId) == 0) { AddDriverToList( &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead, DriverType, &ClassGuid, ContextDevice, + currentInfFileDetails, filename, ProviderName, ManufacturerName, @@ -4190,8 +5818,7 @@ SetupDiBuildDriverInfoList( } HeapFree(GetProcessHeap(), 0, ManufacturerName); - HeapFree(GetProcessHeap(), 0, ManufacturerSection); - ManufacturerName = ManufacturerSection = NULL; + ManufacturerName = NULL; Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer); } @@ -4200,8 +5827,8 @@ next: HeapFree(GetProcessHeap(), 0, ProviderName); ProviderName = NULL; - SetupCloseInfFile(hInf); - hInf = INVALID_HANDLE_VALUE; + DereferenceInfFile(currentInfFileDetails); + currentInfFileDetails = NULL; } ret = TRUE; } @@ -4212,20 +5839,24 @@ done: { if (DeviceInfoData) { - struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; - deviceInfo->Flags |= DI_DIDCOMPAT; + InstallParams.Flags |= DI_DIDCOMPAT; + InstallParams.FlagsEx |= DI_FLAGSEX_DIDCOMPATINFO; } else - list->Flags |= DI_DIDCLASS; + { + InstallParams.Flags |= DI_DIDCLASS; + InstallParams.FlagsEx |= DI_FLAGSEX_DIDINFOLIST; + } + ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); } HeapFree(GetProcessHeap(), 0, ProviderName); HeapFree(GetProcessHeap(), 0, ManufacturerName); - HeapFree(GetProcessHeap(), 0, ManufacturerSection); HeapFree(GetProcessHeap(), 0, HardwareIDs); HeapFree(GetProcessHeap(), 0, CompatibleIDs); - if (hInf != INVALID_HANDLE_VALUE) - SetupCloseInfFile(hInf); + HeapFree(GetProcessHeap(), 0, FullInfFileName); + if (currentInfFileDetails) + DereferenceInfFile(currentInfFileDetails); HeapFree(GetProcessHeap(), 0, Buffer); TRACE("Returning %d\n", ret); @@ -4243,7 +5874,7 @@ SetupDiDeleteDeviceInfo( TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData); FIXME("not implemented\n"); - SetLastError(ERROR_GEN_FAILURE); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } @@ -4257,11 +5888,78 @@ SetupDiDestroyDriverInfoList( IN PSP_DEVINFO_DATA DeviceInfoData, IN DWORD DriverType) { + struct DeviceInfoSet *list; + BOOL ret = FALSE; + TRACE("%p %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, DriverType); - FIXME("not implemented\n"); - SetLastError(ERROR_GEN_FAILURE); - return FALSE; + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_HANDLE); + else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + PLIST_ENTRY ListEntry; + struct DriverInfoElement *driverInfo; + SP_DEVINSTALL_PARAMS_W InstallParams; + + InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); + if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams)) + goto done; + + if (!DeviceInfoData) + /* Fall back to destroying class driver list */ + DriverType = SPDIT_CLASSDRIVER; + + if (DriverType == SPDIT_CLASSDRIVER) + { + while (!IsListEmpty(&list->DriverListHead)) + { + ListEntry = RemoveHeadList(&list->DriverListHead); + driverInfo = (struct DriverInfoElement *)ListEntry; + DestroyDriverInfoElement(driverInfo); + } + InstallParams.Reserved = 0; + InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS); + InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST; + ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParams); + } + else + { + SP_DEVINSTALL_PARAMS_W InstallParamsSet; + struct DeviceInfoElement *deviceInfo; + + InstallParamsSet.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); + if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet)) + goto done; + deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; + while (!IsListEmpty(&deviceInfo->DriverListHead)) + { + ListEntry = RemoveHeadList(&deviceInfo->DriverListHead); + driverInfo = (struct DriverInfoElement *)ListEntry; + if ((PVOID)InstallParamsSet.Reserved == driverInfo) + { + InstallParamsSet.Reserved = 0; + SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet); + } + DestroyDriverInfoElement(driverInfo); + } + InstallParams.Reserved = 0; + InstallParams.Flags &= ~DI_DIDCOMPAT; + InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO; + ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + } + } + +done: + TRACE("Returning %d\n", ret); + return ret; } @@ -4324,7 +6022,7 @@ SetupDiOpenDeviceInfoW( else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS)) { TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS)); - SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_FLAGS); } else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) SetLastError(ERROR_INVALID_USER_BUFFER); @@ -4355,9 +6053,9 @@ SetupDiOpenDeviceInfoW( /* Open supposed registry key */ rc = RegOpenKeyExW( list->HKLM, - EnumKeyName, + REGSTR_PATH_SYSTEMENUM, 0, /* Options */ - KEY_ENUMERATE_SUB_KEYS, + 0, &hEnumKey); if (rc != ERROR_SUCCESS) { @@ -4373,12 +6071,16 @@ SetupDiOpenDeviceInfoW( RegCloseKey(hEnumKey); if (rc != ERROR_SUCCESS) { + if (rc == ERROR_FILE_NOT_FOUND) + rc = ERROR_NO_SUCH_DEVINST; SetLastError(rc); return FALSE; } - /* FIXME: GUID_NULL is not allowed */ - if (!CreateDeviceInfoElement(DeviceInstanceId, &GUID_NULL /* FIXME */, &deviceInfo)) + /* FIXME: try to get ClassGUID from registry, instead of + * sending GUID_NULL to CreateDeviceInfoElement + */ + if (!CreateDeviceInfoElement(list, DeviceInstanceId, &GUID_NULL, &deviceInfo)) { RegCloseKey(hKey); return FALSE; @@ -4392,7 +6094,7 @@ SetupDiOpenDeviceInfoW( if (ret && deviceInfo && DeviceInfoData) { memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID)); - DeviceInfoData->DevInst = 0; /* FIXME */ + DeviceInfoData->DevInst = deviceInfo->dnDevInst; DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo; } } @@ -4453,78 +6155,338 @@ SetupDiEnumDriverInfoA( } if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A)) { - /* Copy more fields */ - DriverInfoData->DriverDate = driverInfoData2W.DriverDate; - DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion; + /* Copy more fields */ + DriverInfoData->DriverDate = driverInfoData2W.DriverDate; + DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion; + } + } + } + + TRACE("Returning %d\n", ret); + return ret; +} + + +/*********************************************************************** + * SetupDiEnumDriverInfoW (SETUPAPI.@) + */ +BOOL WINAPI +SetupDiEnumDriverInfoW( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + IN DWORD DriverType, + IN DWORD MemberIndex, + OUT PSP_DRVINFO_DATA_W DriverInfoData) +{ + PLIST_ENTRY ListHead; + BOOL ret = FALSE; + + TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData, + DriverType, MemberIndex, DriverInfoData); + + if (!DeviceInfoSet || !DriverInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) + SetLastError(ERROR_INVALID_HANDLE); + else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; + PLIST_ENTRY ItemList; + if (DriverType == SPDIT_CLASSDRIVER || + devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS) + { + ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead; + } + else + { + ListHead = &devInfo->DriverListHead; + } + + ItemList = ListHead->Flink; + while (ItemList != ListHead && MemberIndex-- > 0) + ItemList = ItemList->Flink; + if (ItemList == ListHead) + SetLastError(ERROR_NO_MORE_ITEMS); + else + { + struct DriverInfoElement *DrvInfo = (struct DriverInfoElement *)ItemList; + + memcpy( + &DriverInfoData->DriverType, + &DrvInfo->Info.DriverType, + DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType)); + ret = TRUE; + } + } + + TRACE("Returning %d\n", ret); + return ret; +} + + +/*********************************************************************** + * SetupDiGetSelectedDriverA (SETUPAPI.@) + */ +BOOL WINAPI +SetupDiGetSelectedDriverA( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + OUT PSP_DRVINFO_DATA_A DriverInfoData) +{ + SP_DRVINFO_DATA_V2_W driverInfoData2W; + BOOL ret = FALSE; + + if (DriverInfoData == NULL) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W); + + ret = SetupDiGetSelectedDriverW(DeviceInfoSet, + DeviceInfoData, + &driverInfoData2W); + + if (ret) + { + /* Do W->A conversion */ + DriverInfoData->DriverType = driverInfoData2W.DriverType; + DriverInfoData->Reserved = driverInfoData2W.Reserved; + if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1, + DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0) + { + DriverInfoData->Description[0] = '\0'; + ret = FALSE; + } + if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1, + DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0) + { + DriverInfoData->MfgName[0] = '\0'; + ret = FALSE; + } + if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1, + DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0) + { + DriverInfoData->ProviderName[0] = '\0'; + ret = FALSE; + } + if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A)) + { + /* Copy more fields */ + DriverInfoData->DriverDate = driverInfoData2W.DriverDate; + DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion; + } + } + } + + return ret; +} + + +/*********************************************************************** + * SetupDiGetSelectedDriverW (SETUPAPI.@) + */ +BOOL WINAPI +SetupDiGetSelectedDriverW( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + OUT PSP_DRVINFO_DATA_W DriverInfoData) +{ + BOOL ret = FALSE; + + TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData); + + if (!DeviceInfoSet || !DriverInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) + SetLastError(ERROR_INVALID_HANDLE); + else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + SP_DEVINSTALL_PARAMS InstallParams; + + InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); + if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams)) + { + struct DriverInfoElement *driverInfo; + driverInfo = (struct DriverInfoElement *)InstallParams.Reserved; + if (driverInfo == NULL) + SetLastError(ERROR_NO_DRIVER_SELECTED); + else + { + memcpy( + &DriverInfoData->DriverType, + &driverInfo->Info.DriverType, + DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType)); + ret = TRUE; + } + } + } + + TRACE("Returning %d\n", ret); + return ret; +} + + +/*********************************************************************** + * SetupDiSetSelectedDriverA (SETUPAPI.@) + */ +BOOL WINAPI +SetupDiSetSelectedDriverA( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + IN OUT PSP_DRVINFO_DATA_A DriverInfoData OPTIONAL) +{ + SP_DRVINFO_DATA_V1_W DriverInfoDataW; + PSP_DRVINFO_DATA_W pDriverInfoDataW = NULL; + BOOL ret = FALSE; + + if (DriverInfoData != NULL) + { + if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A) && + DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A)); + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W); + DriverInfoDataW.Reserved = DriverInfoData->Reserved; + + if (DriverInfoDataW.Reserved == 0) + { + DriverInfoDataW.DriverType = DriverInfoData->DriverType; + + /* convert the strings to unicode */ + if (!MultiByteToWideChar(CP_ACP, + 0, + DriverInfoData->Description, + LINE_LEN, + DriverInfoDataW.Description, + LINE_LEN) || + !MultiByteToWideChar(CP_ACP, + 0, + DriverInfoData->ProviderName, + LINE_LEN, + DriverInfoDataW.ProviderName, + LINE_LEN)) + { + return FALSE; } } + + pDriverInfoDataW = (PSP_DRVINFO_DATA_W)&DriverInfoDataW; + } + + ret = SetupDiSetSelectedDriverW(DeviceInfoSet, + DeviceInfoData, + pDriverInfoDataW); + + if (ret && pDriverInfoDataW != NULL) + { + DriverInfoData->Reserved = DriverInfoDataW.Reserved; } - TRACE("Returning %d\n", ret); return ret; } /*********************************************************************** - * SetupDiEnumDriverInfoW (SETUPAPI.@) + * SetupDiSetSelectedDriverW (SETUPAPI.@) */ BOOL WINAPI -SetupDiEnumDriverInfoW( +SetupDiSetSelectedDriverW( IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, - IN DWORD DriverType, - IN DWORD MemberIndex, - OUT PSP_DRVINFO_DATA_W DriverInfoData) + IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL) { - PLIST_ENTRY ListHead; BOOL ret = FALSE; - TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData, - DriverType, MemberIndex, DriverInfoData); + TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData); - if (!DeviceInfoSet || !DriverInfoData) + if (!DeviceInfoSet) SetLastError(ERROR_INVALID_PARAMETER); else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) SetLastError(ERROR_INVALID_HANDLE); else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) SetLastError(ERROR_INVALID_HANDLE); - else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER) - SetLastError(ERROR_INVALID_PARAMETER); - else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData) - SetLastError(ERROR_INVALID_PARAMETER); - else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData) - SetLastError(ERROR_INVALID_PARAMETER); - else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W)) + else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W)) SetLastError(ERROR_INVALID_USER_BUFFER); else { - struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; - PLIST_ENTRY ItemList; - if (DriverType == SPDIT_CLASSDRIVER || - devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS) + struct DriverInfoElement **pDriverInfo; + PLIST_ENTRY ListHead, ItemList; + + if (DeviceInfoData) { - ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead; + pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams.Reserved; + ListHead = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead; } else { - ListHead = &devInfo->DriverListHead; + pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved; + ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead; } - ItemList = ListHead->Flink; - while (ItemList != ListHead && MemberIndex-- > 0) - ItemList = ItemList->Flink; - if (ItemList == ListHead) - SetLastError(ERROR_NO_MORE_ITEMS); - else + if (!DriverInfoData) { - struct DriverInfoElement *DrvInfo = (struct DriverInfoElement *)ItemList; - - memcpy( - &DriverInfoData->DriverType, - &DrvInfo->Info.DriverType, - DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType)); + *pDriverInfo = NULL; ret = TRUE; } + else + { + /* Search selected driver in list */ + ItemList = ListHead->Flink; + while (ItemList != ListHead) + { + if (DriverInfoData->Reserved != 0) + { + if (DriverInfoData->Reserved == (ULONG_PTR)ItemList) + break; + } + else + { + /* The caller wants to compare only DriverType, Description and ProviderName fields */ + struct DriverInfoElement *driverInfo = (struct DriverInfoElement *)ItemList; + if (driverInfo->Info.DriverType == DriverInfoData->DriverType + && wcscmp(driverInfo->Info.Description, DriverInfoData->Description) == 0 + && wcscmp(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0) + { + break; + } + } + } + if (ItemList == ListHead) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + *pDriverInfo = (struct DriverInfoElement *)ItemList; + DriverInfoData->Reserved = (ULONG_PTR)ItemList; + ret = TRUE; + TRACE("Choosing driver whose rank is 0x%lx\n", + ((struct DriverInfoElement *)ItemList)->DriverRank); + if (DeviceInfoData) + memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID)); + } + } } TRACE("Returning %d\n", ret); @@ -4532,65 +6494,223 @@ SetupDiEnumDriverInfoW( } /*********************************************************************** - * SetupDiGetSelectedDriverW (SETUPAPI.@) + * SetupDiGetDriverInfoDetailA (SETUPAPI.@) */ BOOL WINAPI -SetupDiGetSelectedDriverW( +SetupDiGetDriverInfoDetailA( IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, - OUT PSP_DRVINFO_DATA_W DriverInfoData) + IN PSP_DRVINFO_DATA_A DriverInfoData, + OUT PSP_DRVINFO_DETAIL_DATA_A DriverInfoDetailData OPTIONAL, + IN DWORD DriverInfoDetailDataSize, + OUT PDWORD RequiredSize OPTIONAL) { + SP_DRVINFO_DATA_V2_W DriverInfoDataW; + PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailDataW = NULL; + DWORD BufSize = 0; + DWORD HardwareIDLen = 0; BOOL ret = FALSE; - TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData); - - if (!DeviceInfoSet || !DriverInfoData) + /* do some sanity checks, the unicode version might do more thorough checks */ + if (DriverInfoData == NULL || + (DriverInfoDetailData == NULL && DriverInfoDetailDataSize != 0) || + (DriverInfoDetailData != NULL && + (DriverInfoDetailDataSize < FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) + sizeof(CHAR) || + DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_A)))) + { SetLastError(ERROR_INVALID_PARAMETER); - else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) - SetLastError(ERROR_INVALID_HANDLE); - else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) - SetLastError(ERROR_INVALID_HANDLE); - else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) - SetLastError(ERROR_INVALID_USER_BUFFER); - else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W)) - SetLastError(ERROR_INVALID_USER_BUFFER); + goto Cleanup; + } + + /* make sure we support both versions of the SP_DRVINFO_DATA structure */ + if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1_A)) + { + DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W); + } + else if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A)) + { + DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V2_W); + } else { - struct DriverInfoElement *driverInfo; - - if (DeviceInfoData) - driverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver; - else - driverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver; + SetLastError(ERROR_INVALID_PARAMETER); + goto Cleanup; + } + DriverInfoDataW.DriverType = DriverInfoData->DriverType; + DriverInfoDataW.Reserved = DriverInfoData->Reserved; + + /* convert the strings to unicode */ + if (MultiByteToWideChar(CP_ACP, + 0, + DriverInfoData->Description, + LINE_LEN, + DriverInfoDataW.Description, + LINE_LEN) && + MultiByteToWideChar(CP_ACP, + 0, + DriverInfoData->MfgName, + LINE_LEN, + DriverInfoDataW.MfgName, + LINE_LEN) && + MultiByteToWideChar(CP_ACP, + 0, + DriverInfoData->ProviderName, + LINE_LEN, + DriverInfoDataW.ProviderName, + LINE_LEN)) + { + if (DriverInfoDataW.cbSize == sizeof(SP_DRVINFO_DATA_V2_W)) + { + DriverInfoDataW.DriverDate = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverDate; + DriverInfoDataW.DriverVersion = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverVersion; + } - if (driverInfo == NULL) - SetLastError(ERROR_NO_DRIVER_SELECTED); - else + if (DriverInfoDetailData != NULL) { - memcpy( - &DriverInfoData->DriverType, - &driverInfo->Info.DriverType, - DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType)); - ret = TRUE; + /* calculate the unicode buffer size from the ansi buffer size */ + HardwareIDLen = DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID); + BufSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID) + + (HardwareIDLen * sizeof(WCHAR)); + + DriverInfoDetailDataW = MyMalloc(BufSize); + if (DriverInfoDetailDataW == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto Cleanup; + } + + /* initialize the buffer */ + ZeroMemory(DriverInfoDetailDataW, + BufSize); + DriverInfoDetailDataW->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W); + } + + /* call the unicode version */ + ret = SetupDiGetDriverInfoDetailW(DeviceInfoSet, + DeviceInfoData, + &DriverInfoDataW, + DriverInfoDetailDataW, + BufSize, + RequiredSize); + + if (ret) + { + if (DriverInfoDetailDataW != NULL) + { + /* convert the SP_DRVINFO_DETAIL_DATA_W structure to ansi */ + DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A); + DriverInfoDetailData->InfDate = DriverInfoDetailDataW->InfDate; + DriverInfoDetailData->Reserved = DriverInfoDetailDataW->Reserved; + if (WideCharToMultiByte(CP_ACP, + 0, + DriverInfoDetailDataW->SectionName, + LINE_LEN, + DriverInfoDetailData->SectionName, + LINE_LEN, + NULL, + NULL) && + WideCharToMultiByte(CP_ACP, + 0, + DriverInfoDetailDataW->InfFileName, + MAX_PATH, + DriverInfoDetailData->InfFileName, + MAX_PATH, + NULL, + NULL) && + WideCharToMultiByte(CP_ACP, + 0, + DriverInfoDetailDataW->DrvDescription, + LINE_LEN, + DriverInfoDetailData->DrvDescription, + LINE_LEN, + NULL, + NULL) && + WideCharToMultiByte(CP_ACP, + 0, + DriverInfoDetailDataW->HardwareID, + HardwareIDLen, + DriverInfoDetailData->HardwareID, + HardwareIDLen, + NULL, + NULL)) + { + DWORD len, cnt = 0; + DWORD hwidlen = HardwareIDLen; + CHAR *s = DriverInfoDetailData->HardwareID; + + /* count the strings in the list */ + while (*s != '\0') + { + len = lstrlenA(s) + 1; + if (hwidlen > len) + { + cnt++; + s += len; + hwidlen -= len; + } + else + { + /* looks like the string list wasn't terminated... */ + SetLastError(ERROR_INVALID_USER_BUFFER); + ret = FALSE; + break; + } + } + + /* make sure CompatIDsOffset points to the second string in the + list, if present */ + if (cnt > 1) + { + DriverInfoDetailData->CompatIDsOffset = lstrlenA(DriverInfoDetailData->HardwareID) + 1; + DriverInfoDetailData->CompatIDsLength = (DWORD)(s - DriverInfoDetailData->HardwareID) - + DriverInfoDetailData->CompatIDsOffset + 1; + } + else + { + DriverInfoDetailData->CompatIDsOffset = 0; + DriverInfoDetailData->CompatIDsLength = 0; + } + } + else + { + ret = FALSE; + } + } + + if (RequiredSize != NULL) + { + *RequiredSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) + + (((*RequiredSize) - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR)); + } } } - TRACE("Returning %d\n", ret); +Cleanup: + if (DriverInfoDetailDataW != NULL) + { + MyFree(DriverInfoDetailDataW); + } + return ret; } /*********************************************************************** - * SetupDiSetSelectedDriverW (SETUPAPI.@) + * SetupDiGetDriverInfoDetailW (SETUPAPI.@) */ BOOL WINAPI -SetupDiSetSelectedDriverW( +SetupDiGetDriverInfoDetailW( IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, - IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL) + IN PSP_DRVINFO_DATA_W DriverInfoData, + OUT PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData OPTIONAL, + IN DWORD DriverInfoDetailDataSize, + OUT PDWORD RequiredSize OPTIONAL) { BOOL ret = FALSE; - TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData); + TRACE("%p %p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData, + DriverInfoData, DriverInfoDetailData, + DriverInfoDetailDataSize, RequiredSize); if (!DeviceInfoSet) SetLastError(ERROR_INVALID_PARAMETER); @@ -4600,67 +6720,223 @@ SetupDiSetSelectedDriverW( SetLastError(ERROR_INVALID_HANDLE); else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) SetLastError(ERROR_INVALID_USER_BUFFER); - else if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W)) + else if (!DriverInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (!DriverInfoDetailData && DriverInfoDetailDataSize != 0) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DriverInfoDetailData && DriverInfoDetailDataSize < sizeof(SP_DRVINFO_DETAIL_DATA_W)) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DriverInfoDetailData && DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_W)) SetLastError(ERROR_INVALID_USER_BUFFER); + else if (DriverInfoData->Reserved == 0) + SetLastError(ERROR_NO_DRIVER_SELECTED); + else + { + struct DriverInfoElement *driverInfoElement; + driverInfoElement = (struct DriverInfoElement *)DriverInfoData->Reserved; + + memcpy( + DriverInfoDetailData, + &driverInfoElement->Details, + driverInfoElement->Details.cbSize); + /* FIXME: copy HardwareIDs/CompatibleIDs if buffer is big enough + * Don't forget to set CompatIDsOffset and CompatIDsLength fields. + */ + ret = TRUE; + } + + TRACE("Returning %d\n", ret); + return ret; +} + +/* Return the current hardware profile id, or -1 if error */ +static DWORD +GetCurrentHwProfile( + IN HDEVINFO DeviceInfoSet) +{ + HKEY hKey = INVALID_HANDLE_VALUE; + DWORD dwRegType, dwLength; + DWORD hwProfile; + LONG rc; + DWORD ret = (DWORD)-1; + + rc = RegOpenKeyExW( + ((struct DeviceInfoSet *)DeviceInfoSet)->HKLM, + REGSTR_PATH_IDCONFIGDB, + 0, /* Options */ + KEY_QUERY_VALUE, + &hKey); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + + dwLength = sizeof(DWORD); + rc = RegQueryValueExW( + hKey, + REGSTR_VAL_CURRENTCONFIG, + NULL, + &dwRegType, + (LPBYTE)&hwProfile, &dwLength); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + ret = hwProfile; + +cleanup: + if (hKey != INVALID_HANDLE_VALUE) + RegCloseKey(hKey); + + return hwProfile; +} + +static BOOL +ResetDevice( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData) +{ + PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData; + struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; + NTSTATUS Status; + + if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE) + { + /* At the moment, I only know how to start local devices */ + SetLastError(ERROR_INVALID_COMPUTERNAME); + return FALSE; + } + + RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, deviceInfo->DeviceName); + Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA)); + SetLastError(RtlNtStatusToDosError(Status)); + return NT_SUCCESS(Status); +} + +static BOOL StopDevice( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData) +{ + FIXME("Stub %p %p\n", DeviceInfoSet, DeviceInfoData); + return TRUE; +} + +/*********************************************************************** + * SetupDiChangeState (SETUPAPI.@) + */ +BOOL WINAPI +SetupDiChangeState( + IN HDEVINFO DeviceInfoSet, + IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL) +{ + PSP_PROPCHANGE_PARAMS PropChange; + HKEY hKey = INVALID_HANDLE_VALUE; + LPCWSTR RegistryValueName; + DWORD dwConfigFlags, dwLength, dwRegType; + LONG rc; + BOOL ret = FALSE; + + TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData); + + if (!DeviceInfoData) + PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChange; + else + PropChange = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->ClassInstallParams.PropChange; + if (!PropChange) + { + SetLastError(ERROR_INVALID_PARAMETER); + goto cleanup; + } + + if (PropChange->Scope == DICS_FLAG_GLOBAL) + RegistryValueName = REGSTR_VAL_CONFIGFLAGS; else - { - struct DriverInfoElement **pDriverInfo; - PLIST_ENTRY ListHead, ItemList; + RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS; - if (DeviceInfoData) - { - pDriverInfo = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver; - ListHead = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead; - } - else + switch (PropChange->StateChange) + { + case DICS_ENABLE: + case DICS_DISABLE: { - pDriverInfo = &((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver; - ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead; - } + /* Enable/disable device in registry */ + hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE); + if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND) + hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL); + if (hKey == INVALID_HANDLE_VALUE) + break; + dwLength = sizeof(DWORD); + rc = RegQueryValueExW( + hKey, + RegistryValueName, + NULL, + &dwRegType, + (LPBYTE)&dwConfigFlags, &dwLength); + if (rc == ERROR_FILE_NOT_FOUND) + dwConfigFlags = 0; + else if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + if (PropChange->StateChange == DICS_ENABLE) + dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED); + else + dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED); + rc = RegSetValueEx( + hKey, + RegistryValueName, + 0, + REG_DWORD, + (LPBYTE)&dwConfigFlags, sizeof(DWORD)); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } - if (!DriverInfoData) - { - *pDriverInfo = NULL; - ret = TRUE; - } - else - { - /* Search selected driver in list */ - ItemList = ListHead->Flink; - while (ItemList != ListHead) + /* Enable/disable device if needed */ + if (PropChange->Scope == DICS_FLAG_GLOBAL + || PropChange->HwProfile == 0 + || PropChange->HwProfile == GetCurrentHwProfile(DeviceInfoSet)) { - if (DriverInfoData->Reserved != 0) - { - if (DriverInfoData->Reserved == (ULONG_PTR)ItemList) - break; - } + if (PropChange->StateChange == DICS_ENABLE) + ret = ResetDevice(DeviceInfoSet, DeviceInfoData); else - { - /* The caller wants to compare only DriverType, Description and ProviderName fields */ - struct DriverInfoElement *driverInfo = (struct DriverInfoElement *)ItemList; - if (driverInfo->Info.DriverType == DriverInfoData->DriverType - && wcscmp(driverInfo->Info.Description, DriverInfoData->Description) == 0 - && wcscmp(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0) - { - break; - } - } + ret = StopDevice(DeviceInfoSet, DeviceInfoData); } - if (ItemList == ListHead) - SetLastError(ERROR_INVALID_PARAMETER); else - { - *pDriverInfo = (struct DriverInfoElement *)ItemList; - DriverInfoData->Reserved = (ULONG_PTR)ItemList; ret = TRUE; - TRACE("Choosing driver whose rank is 0x%lx\n", - ((struct DriverInfoElement *)ItemList)->DriverRank); - if (DeviceInfoData) - memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID)); - } + break; + } + case DICS_PROPCHANGE: + { + ret = ResetDevice(DeviceInfoSet, DeviceInfoData); + break; + } + default: + { + FIXME("Unknown StateChange 0x%lx\n", PropChange->StateChange); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); } } +cleanup: + if (hKey != INVALID_HANDLE_VALUE) + RegCloseKey(hKey); + TRACE("Returning %d\n", ret); return ret; } @@ -4721,48 +6997,50 @@ SetupDiInstallDriverFiles( SetLastError(ERROR_INVALID_HANDLE); else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) SetLastError(ERROR_INVALID_USER_BUFFER); - else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver == NULL) - SetLastError(ERROR_INVALID_PARAMETER); - else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver == NULL) - SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams.Reserved == 0) + SetLastError(ERROR_NO_DRIVER_SELECTED); + else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved == 0) + SetLastError(ERROR_NO_DRIVER_SELECTED); else { - struct DriverInfoElement *DriverInfo; - HWND hWnd; - HINF hInf; - - if (DeviceInfoData) - { - DriverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver; - hWnd = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->hwndParent; - } - else + SP_DEVINSTALL_PARAMS_W InstallParams; + struct DriverInfoElement *SelectedDriver; + WCHAR SectionName[MAX_PATH]; + DWORD SectionNameLength = 0; + + InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); + ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + if (!ret) + goto done; + + SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved; + if (!SelectedDriver) { - DriverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver; - hWnd = ((struct DeviceInfoSet *)DeviceInfoSet)->hwndParent; + SetLastError(ERROR_NO_DRIVER_SELECTED); + goto done; } - hInf = SetupOpenInfFileW(DriverInfo->InfPath, NULL, INF_STYLE_WIN4, NULL); - if (hInf != INVALID_HANDLE_VALUE) - { - WCHAR SectionName[MAX_PATH]; - DWORD SectionNameLength = 0; + ret = SetupDiGetActualSectionToInstallW( + SelectedDriver->InfFileDetails->hInf, + SelectedDriver->Details.SectionName, + SectionName, MAX_PATH, &SectionNameLength, NULL); + if (!ret) + goto done; - ret = SetupDiGetActualSectionToInstallW(hInf, DriverInfo->InfSection, - SectionName, MAX_PATH, &SectionNameLength, NULL); - if (ret) - { - PVOID callback_context = SetupInitDefaultQueueCallback(hWnd); - ret = SetupInstallFromInfSectionW(hWnd, hInf, SectionName, - SPINST_FILES, NULL, NULL, SP_COPY_NEWER, - SetupDefaultQueueCallbackW, callback_context, - NULL, NULL); - SetupTermDefaultQueueCallback(callback_context); - } - SetupCloseInfFile(hInf); + if (!InstallParams.InstallMsgHandler) + { + InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW; + InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent); + SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); } + ret = SetupInstallFromInfSectionW(InstallParams.hwndParent, + SelectedDriver->InfFileDetails->hInf, SectionName, + SPINST_FILES, NULL, NULL, SP_COPY_NEWER, + InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext, + DeviceInfoSet, DeviceInfoData); } +done: TRACE("Returning %d\n", ret); return ret; } @@ -4775,12 +7053,91 @@ SetupDiRegisterCoDeviceInstallers( IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData) { + BOOL ret = FALSE; /* Return value */ + TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData); - FIXME("SetupDiRegisterCoDeviceInstallers not implemented. Doing nothing\n"); - //SetLastError(ERROR_GEN_FAILURE); - //return FALSE; - return TRUE; + if (!DeviceInfoSet) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) + SetLastError(ERROR_INVALID_HANDLE); + else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (!DeviceInfoData) + SetLastError(ERROR_INVALID_PARAMETER); + else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else + { + SP_DEVINSTALL_PARAMS_W InstallParams; + struct DriverInfoElement *SelectedDriver; + BOOL Result; + DWORD DoAction; + WCHAR SectionName[MAX_PATH]; + DWORD SectionNameLength = 0; + HKEY hKey = INVALID_HANDLE_VALUE; + + InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); + Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + if (!Result) + goto cleanup; + + SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved; + if (SelectedDriver == NULL) + { + SetLastError(ERROR_NO_DRIVER_SELECTED); + goto cleanup; + } + + /* Get .CoInstallers section name */ + Result = SetupDiGetActualSectionToInstallW( + SelectedDriver->InfFileDetails->hInf, + SelectedDriver->Details.SectionName, + SectionName, MAX_PATH, &SectionNameLength, NULL); + if (!Result || SectionNameLength > MAX_PATH - wcslen(L".CoInstallers") - 1) + goto cleanup; + wcscat(SectionName, L".CoInstallers"); + + /* Open/Create driver key information */ +#if _WIN32_WINNT >= 0x502 + hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE); +#else + hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS); +#endif + if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND) + hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL); + if (hKey == INVALID_HANDLE_VALUE) + goto cleanup; + + /* Install .CoInstallers section */ + DoAction = SPINST_REGISTRY; + if (!(InstallParams.Flags & DI_NOFILECOPY)) + { + DoAction |= SPINST_FILES; + if (!InstallParams.InstallMsgHandler) + { + InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW; + InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent); + SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + } + } + Result = SetupInstallFromInfSectionW(InstallParams.hwndParent, + SelectedDriver->InfFileDetails->hInf, SectionName, + DoAction, hKey, NULL, SP_COPY_NEWER, + InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext, + DeviceInfoSet, DeviceInfoData); + if (!Result) + goto cleanup; + + ret = TRUE; + +cleanup: + if (hKey != INVALID_HANDLE_VALUE) + RegCloseKey(hKey); + } + + TRACE("Returning %d\n", ret); + return ret; } /*********************************************************************** @@ -4799,6 +7156,45 @@ SetupDiInstallDeviceInterfaces( return TRUE; } +BOOL +InfIsFromOEMLocation( + IN PCWSTR FullName, + OUT LPBOOL IsOEMLocation) +{ + PWCHAR last; + + last = strrchrW(FullName, '\\'); + if (!last) + { + /* No directory specified */ + *IsOEMLocation = FALSE; + } + else + { + WCHAR Windir[MAX_PATH]; + UINT ret; + + ret = GetWindowsDirectory(Windir, MAX_PATH); + if (ret == 0 || ret >= MAX_PATH) + { + SetLastError(ERROR_GEN_FAILURE); + return FALSE; + } + + if (strncmpW(FullName, Windir, last - FullName) == 0) + { + /* The path is %SYSTEMROOT%\Inf */ + *IsOEMLocation = FALSE; + } + else + { + /* The file is in another place */ + *IsOEMLocation = TRUE; + } + } + return TRUE; +} + /*********************************************************************** * SetupDiInstallDevice (SETUPAPI.@) */ @@ -4807,27 +7203,26 @@ SetupDiInstallDevice( IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData) { - struct DriverInfoElement *DriverInfo; - struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved; + SP_DEVINSTALL_PARAMS_W InstallParams; + struct DriverInfoElement *SelectedDriver; SYSTEMTIME DriverDate; WCHAR SectionName[MAX_PATH]; WCHAR Buffer[32]; DWORD SectionNameLength = 0; BOOL Result = FALSE; - INFCONTEXT ContextService; - INT Flags; + ULONG DoAction; DWORD RequiredSize; - HINF hInf = INVALID_HANDLE_VALUE; LPCWSTR AssociatedService = NULL; LPWSTR pSectionName = NULL; - LPWSTR ClassName = NULL; + WCHAR ClassName[MAX_CLASS_NAME_LEN]; GUID ClassGuid; LPWSTR lpGuidString = NULL, lpFullGuidString = NULL; BOOL RebootRequired = FALSE; HKEY hKey = INVALID_HANDLE_VALUE; HKEY hClassKey = INVALID_HANDLE_VALUE; + BOOL NeedtoCopyFile; + LARGE_INTEGER fullVersion; LONG rc; - HWND hWnd; BOOL ret = FALSE; /* Return value */ TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData); @@ -4840,10 +7235,6 @@ SetupDiInstallDevice( SetLastError(ERROR_INVALID_HANDLE); else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) SetLastError(ERROR_INVALID_USER_BUFFER); - else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver == NULL) - SetLastError(ERROR_INVALID_PARAMETER); - else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver == NULL) - SetLastError(ERROR_INVALID_PARAMETER); else Result = TRUE; @@ -4853,46 +7244,37 @@ SetupDiInstallDevice( goto cleanup; } - /* FIXME: If DI_FLAGSEX_SETFAILEDINSTALL is set, set FAILEDINSTALL flag in ConfigFlags registry and exit */ + InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); + Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + if (!Result) + goto cleanup; - if (DeviceInfoData) + if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL) { - DriverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver; - hWnd = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->hwndParent; + /* FIXME: set FAILEDINSTALL in ConfigFlags registry value */ + goto cleanup; } - else + + SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved; + if (SelectedDriver == NULL) { - DriverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver; - hWnd = ((struct DeviceInfoSet *)DeviceInfoSet)->hwndParent; + SetLastError(ERROR_NO_DRIVER_SELECTED); + goto cleanup; } - FileTimeToSystemTime(&DriverInfo->Info.DriverDate, &DriverDate); - hInf = SetupOpenInfFileW(DriverInfo->InfPath, NULL, INF_STYLE_WIN4, NULL); - if (hInf == INVALID_HANDLE_VALUE) - goto cleanup; + FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate); - Result = SetupDiGetActualSectionToInstallW(hInf, DriverInfo->InfSection, + Result = SetupDiGetActualSectionToInstallW( + SelectedDriver->InfFileDetails->hInf, + SelectedDriver->Details.SectionName, SectionName, MAX_PATH, &SectionNameLength, NULL); - if (!Result || SectionNameLength > MAX_PATH - 9) + if (!Result || SectionNameLength > MAX_PATH - wcslen(DotServices)) goto cleanup; pSectionName = &SectionName[wcslen(SectionName)]; /* Get information from [Version] section */ - ClassName = NULL; - RequiredSize = 0; - if (!SetupDiGetINFClassW(DriverInfo->InfPath, &ClassGuid, ClassName, RequiredSize, &RequiredSize)) - { - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - goto cleanup; - ClassName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); - if (!ClassName) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - if (!SetupDiGetINFClassW(DriverInfo->InfPath, &ClassGuid, ClassName, RequiredSize, &RequiredSize)) - goto cleanup; - } + if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize)) + goto cleanup; /* Format ClassGuid to a string */ if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK) goto cleanup; @@ -4909,55 +7291,80 @@ SetupDiInstallDevice( lpFullGuidString[RequiredSize + 2] = '\0'; /* Open/Create driver key information */ - hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_SET_VALUE); +#if _WIN32_WINNT >= 0x502 + hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE); +#else + hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS); +#endif if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND) hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL); if (hKey == INVALID_HANDLE_VALUE) goto cleanup; /* Install main section */ - /* Files have already been copied in SetupDiInstallDriverFiles. - * Process only registry entries. */ + DoAction = SPINST_REGISTRY; + if (!(InstallParams.Flags & DI_NOFILECOPY)) + { + DoAction |= SPINST_FILES; + if (!InstallParams.InstallMsgHandler) + { + InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW; + InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent); + SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); + } + } *pSectionName = '\0'; - Result = SetupInstallFromInfSectionW(hWnd, hInf, SectionName, - SPINST_REGISTRY, hKey, NULL, 0, - SetupDefaultQueueCallbackW, NULL, - NULL, NULL); + Result = SetupInstallFromInfSectionW(InstallParams.hwndParent, + SelectedDriver->InfFileDetails->hInf, SectionName, + DoAction, hKey, NULL, SP_COPY_NEWER, + InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext, + DeviceInfoSet, DeviceInfoData); if (!Result) goto cleanup; + if (!(InstallParams.Flags & DI_NOFILECOPY) && !(InstallParams.Flags & DI_NOVCP)) + { + if (Result && InstallParams.InstallMsgHandler == SetupDefaultQueueCallbackW) + { + /* Delete resources allocated by SetupInitDefaultQueueCallback */ + SetupTermDefaultQueueCallback(InstallParams.InstallMsgHandlerContext); + } + } + InstallParams.Flags |= DI_NOFILECOPY; + SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); /* Write information to driver key */ *pSectionName = UNICODE_NULL; + memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER)); TRACE("Write information to driver key\n"); TRACE("DriverDate : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear); - TRACE("DriverDesc : '%S'\n", DriverInfo->Info.Description); - TRACE("DriverVersion : '%u.%u.%u.%u'\n", DriverInfo->Info.DriverVersion & 0xff, (DriverInfo->Info.DriverVersion >> 8) & 0xff, (DriverInfo->Info.DriverVersion >> 16) & 0xff, (DriverInfo->Info.DriverVersion >> 24) & 0xff); - TRACE("InfPath : '%S'\n", DriverInfo->InfPath); - TRACE("InfSection : '%S'\n", DriverInfo->InfSection); - TRACE("InfSectionExt : '%S'\n", &SectionName[wcslen(DriverInfo->InfSection)]); /* FIXME */ - TRACE("MatchingDeviceId: '%S'\n", DriverInfo->MatchingId); - TRACE("ProviderName : '%S'\n", DriverInfo->Info.ProviderName); + TRACE("DriverDesc : '%S'\n", SelectedDriver->Info.Description); + TRACE("DriverVersion : '%u.%u.%u.%u'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff); + TRACE("InfPath : '%S'\n", SelectedDriver->Details.InfFileName); + TRACE("InfSection : '%S'\n", SelectedDriver->Details.SectionName); + TRACE("InfSectionExt : '%S'\n", &SectionName[wcslen(SelectedDriver->Details.SectionName)]); + TRACE("MatchingDeviceId: '%S'\n", SelectedDriver->MatchingId); + TRACE("ProviderName : '%S'\n", SelectedDriver->Info.ProviderName); swprintf(Buffer, L"%u-%u-%u", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear); rc = RegSetValueEx(hKey, L"DriverDate", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"DriverDateData", 0, REG_BINARY, (const BYTE *)&DriverInfo->Info.DriverDate, sizeof(FILETIME)); + rc = RegSetValueEx(hKey, L"DriverDateData", 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"DriverDesc", 0, REG_SZ, (const BYTE *)DriverInfo->Info.Description, (wcslen(DriverInfo->Info.Description) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, L"DriverDesc", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) { - swprintf(Buffer, L"%u.%u.%u.%u", DriverInfo->Info.DriverVersion & 0xff, (DriverInfo->Info.DriverVersion >> 8) & 0xff, (DriverInfo->Info.DriverVersion >> 16) & 0xff, (DriverInfo->Info.DriverVersion >> 24) & 0xff); + swprintf(Buffer, L"%u.%u.%u.%u", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff); rc = RegSetValueEx(hKey, L"DriverVersion", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR)); } if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"InfPath", 0, REG_SZ, (const BYTE *)DriverInfo->InfPath, (wcslen(DriverInfo->InfPath) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, L"InfPath", 0, REG_SZ, (const BYTE *)SelectedDriver->Details.InfFileName, (wcslen(SelectedDriver->Details.InfFileName) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"InfSection", 0, REG_SZ, (const BYTE *)DriverInfo->InfSection, (wcslen(DriverInfo->InfSection) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, L"InfSection", 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (wcslen(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"InfSectionExt", 0, REG_SZ, (const BYTE *)&SectionName[wcslen(DriverInfo->InfSection)], (wcslen(SectionName) - wcslen(DriverInfo->InfSection) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, L"InfSectionExt", 0, REG_SZ, (const BYTE *)&SectionName[wcslen(SelectedDriver->Details.SectionName)], (wcslen(SectionName) - wcslen(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"MatchingDeviceId", 0, REG_SZ, (const BYTE *)DriverInfo->MatchingId, (wcslen(DriverInfo->MatchingId) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, L"MatchingDeviceId", 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (wcslen(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"ProviderName", 0, REG_SZ, (const BYTE *)DriverInfo->Info.ProviderName, (wcslen(DriverInfo->Info.ProviderName) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, L"ProviderName", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (wcslen(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR)); if (rc != ERROR_SUCCESS) { SetLastError(rc); @@ -4966,91 +7373,40 @@ SetupDiInstallDevice( RegCloseKey(hKey); hKey = INVALID_HANDLE_VALUE; + /* FIXME: Process .LogConfigOverride section */ + /* Install .Services section */ - wcscpy(pSectionName, L".Services"); - Result = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService); - while (Result) - { - LPWSTR ServiceName = NULL; - LPWSTR ServiceSection = NULL; + wcscpy(pSectionName, DotServices); + Result = InstallServicesSection( + SelectedDriver->InfFileDetails->hInf, + SectionName, + DeviceInfoSet, + DeviceInfoData, + &AssociatedService, + &RebootRequired); + if (!Result) + goto cleanup; - Result = SetupGetStringFieldW( - &ContextService, - 1, /* Field index */ - NULL, 0, - &RequiredSize); - if (!Result) - goto nextfile; - if (RequiredSize > 0) - { - /* We got the needed size for the buffer */ - ServiceName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); - if (!ServiceName) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto nextfile; - } - Result = SetupGetStringFieldW( - &ContextService, - 1, /* Field index */ - ServiceName, RequiredSize, - &RequiredSize); - if (!Result) - goto nextfile; - } - Result = SetupGetIntField( - &ContextService, - 2, /* Field index */ - &Flags); - if (!Result) - { - /* The field may be empty. Ignore the error */ - Flags = 0; - } - Result = SetupGetStringFieldW( - &ContextService, - 3, /* Field index */ + /* Copy .inf file to Inf\ directory (if needed) */ + Result = InfIsFromOEMLocation(SelectedDriver->InfFileDetails->FullInfFileName, &NeedtoCopyFile); + if (!Result) + goto cleanup; + if (NeedtoCopyFile) + { + Result = SetupCopyOEMInfW( + SelectedDriver->InfFileDetails->FullInfFileName, + NULL, + SPOST_NONE, + SP_COPY_NOOVERWRITE, NULL, 0, - &RequiredSize); - if (!Result) - goto nextfile; - if (RequiredSize > 0) - { - /* We got the needed size for the buffer */ - ServiceSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); - if (!ServiceSection) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto nextfile; - } - Result = SetupGetStringFieldW( - &ContextService, - 3, /* Field index */ - ServiceSection, RequiredSize, - &RequiredSize); - if (!Result) - goto nextfile; - } - SetLastError(ERROR_SUCCESS); - Result = SetupInstallServicesFromInfSectionExW(hInf, ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL); - if (Result && (Flags & SPSVCINST_ASSOCSERVICE)) - { - AssociatedService = ServiceName; - ServiceName = NULL; - if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) - RebootRequired = TRUE; - } -nextfile: - HeapFree(GetProcessHeap(), 0, ServiceName); - HeapFree(GetProcessHeap(), 0, ServiceSection); + NULL, + NULL); if (!Result) goto cleanup; - Result = SetupFindNextLine(&ContextService, &ContextService); + /* FIXME: create a new struct InfFileDetails, and set it to SelectedDriver->InfFileDetails, + * to release use of current InfFile */ } - /* Copy .inf file to Inf\ directory */ - FIXME("FIXME: Copy .inf file to Inf\\ directory\n"); /* SetupCopyOEMInf */ - /* Open device registry key */ hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE); if (hKey == INVALID_HANDLE_VALUE) @@ -5058,29 +7414,30 @@ nextfile: /* Install .HW section */ wcscpy(pSectionName, L".HW"); - Result = SetupInstallFromInfSectionW(hWnd, hInf, SectionName, + Result = SetupInstallFromInfSectionW(InstallParams.hwndParent, + SelectedDriver->InfFileDetails->hInf, SectionName, SPINST_REGISTRY, hKey, NULL, 0, - SetupDefaultQueueCallbackW, NULL, - NULL, NULL); + InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext, + DeviceInfoSet, DeviceInfoData); if (!Result) goto cleanup; /* Write information to enum key */ TRACE("Write information to enum key\n"); - TRACE("Service : '%S'\n", AssociatedService); TRACE("Class : '%S'\n", ClassName); TRACE("ClassGUID : '%S'\n", lpFullGuidString); - TRACE("DeviceDesc : '%S'\n", DriverInfo->Info.Description); - TRACE("Mfg : '%S'\n", DriverInfo->Info.MfgName); - rc = RegSetValueEx(hKey, L"Service", 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR)); - if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"Class", 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR)); + TRACE("DeviceDesc : '%S'\n", SelectedDriver->Info.Description); + TRACE("Mfg : '%S'\n", SelectedDriver->Info.MfgName); + TRACE("Service : '%S'\n", AssociatedService); + rc = RegSetValueEx(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"ClassGUID", 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"DeviceDesc", 0, REG_SZ, (const BYTE *)DriverInfo->Info.Description, (wcslen(DriverInfo->Info.Description) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) - rc = RegSetValueEx(hKey, L"Mfg", 0, REG_SZ, (const BYTE *)DriverInfo->Info.MfgName, (wcslen(DriverInfo->Info.MfgName) + 1) * sizeof(WCHAR)); + rc = RegSetValueEx(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (wcslen(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR)); + if (rc == ERROR_SUCCESS && AssociatedService && *AssociatedService) + rc = RegSetValueEx(hKey, REGSTR_VAL_SERVICE, 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR)); if (rc != ERROR_SUCCESS) { SetLastError(rc); @@ -5088,14 +7445,8 @@ nextfile: } /* Start the device */ - if (!RebootRequired && !(Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG))) - { - PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData; - NTSTATUS Status; - RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DevInfo->DeviceName); - Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA)); - ret = NT_SUCCESS(Status); - } + if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG))) + ret = ResetDevice(DeviceInfoSet, DeviceInfoData); else ret = TRUE; @@ -5108,10 +7459,7 @@ cleanup: if (lpGuidString) RpcStringFreeW(&lpGuidString); HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService); - HeapFree(GetProcessHeap(), 0, ClassName); HeapFree(GetProcessHeap(), 0, lpFullGuidString); - if (hInf != INVALID_HANDLE_VALUE) - SetupCloseInfFile(hInf); TRACE("Returning %d\n", ret); return ret;