From 0aa0ba5a0486d0a2a986a78654e92df8ef2835e9 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 19 Sep 2007 17:58:24 -0700 Subject: [PATCH] Implement SetupDiGetClassDevsW --- dlls/setupapi/devinst.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 272 insertions(+), 2 deletions(-) diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 0bdabd4..5cf70f4 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -71,6 +71,7 @@ static const WCHAR Enum[] = {'S','y','s' 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 'E','n','u','m',0}; static const WCHAR DeviceDesc[] = {'D','e','v','i','c','e','D','e','s','c',0}; +static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0}; static const WCHAR HardwareId[] = {'H','a','r','d','w','a','r','e','I','D',0}; static const WCHAR CompatibleIDs[] = {'C','o','m','p','a','t','i','b','l','e','I','d','s',0}; static const WCHAR Service[] = {'S','e','r','v','i','c','e',0}; @@ -195,6 +196,9 @@ static BOOL SETUPDI_AddDeviceToSet(struc struct DeviceInfo *devInfo = SETUPDI_AllocateDeviceInfo(instanceId, phantom); + TRACE("%p, %s, %d, %s, %d\n", set, debugstr_guid(guid), devInst, + debugstr_w(instanceId), phantom); + if (devInfo) { if (set->devices) @@ -1504,6 +1508,254 @@ end: return ret; } +static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet, + HKEY key, const GUID *interface, LPCWSTR enumstr) +{ + struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet; + DWORD i, len; + WCHAR subKeyName[MAX_PATH]; + LONG l; + HKEY enumKey = INVALID_HANDLE_VALUE; + + TRACE("%s\n", debugstr_w(enumstr)); + + l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, + &enumKey, NULL); + for (i = 0; !l; i++) + { + len = sizeof(subKeyName) / sizeof(subKeyName[0]); + l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL); + if (!l) + { + HKEY subKey; + + l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); + if (!l) + { + WCHAR deviceInst[MAX_PATH * 3]; + DWORD dataType; + + len = sizeof(deviceInst); + l = RegQueryValueExW(subKey, DeviceInstance, NULL, &dataType, + (BYTE *)deviceInst, &len); + if (!l && dataType == REG_SZ) + { + TRACE("found instance ID %s\n", debugstr_w(deviceInst)); + if (!enumstr || !lstrcmpiW(enumstr, deviceInst)) + { + HKEY deviceKey; + + l = RegOpenKeyExW(enumKey, deviceInst, 0, KEY_READ, + &deviceKey); + if (!l) + { + WCHAR deviceClassStr[40] = { 0 }; + + len = sizeof(deviceClassStr); + l = RegQueryValueExW(deviceKey, ClassGUID, NULL, + &dataType, (BYTE *)deviceClassStr, &len); + if (!l && dataType == REG_SZ && + deviceClassStr[0] == '{' && + deviceClassStr[37] == '}') + { + GUID deviceClass; + SP_DEVINFO_DATA *dev; + + deviceClassStr[37] = 0; + UuidFromStringW(&deviceClassStr[1], + &deviceClass); + SETUPDI_AddDeviceToSet(set, &deviceClass, + 0 /* FIXME: DevInst */, deviceInst, + FALSE, &dev); + /* FIXME: add this interface, and all the + * device's interfaces, to the device + */ + } + RegCloseKey(deviceKey); + } + } + } + RegCloseKey(subKey); + } + } + } + if (enumKey != INVALID_HANDLE_VALUE) + RegCloseKey(enumKey); +} + +static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet, + const GUID *interface, LPCWSTR enumstr, DWORD flags) +{ + HKEY interfacesKey = SetupDiOpenClassRegKeyExW(interface, KEY_READ, + DIOCR_INTERFACE, NULL, NULL); + + TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(interface), + debugstr_w(enumstr), flags); + + if (interfacesKey != INVALID_HANDLE_VALUE) + { + if (flags & DIGCF_ALLCLASSES) + { + DWORD i, len; + WCHAR interfaceGuidStr[40]; + LONG l = ERROR_SUCCESS; + + for (i = 0; !l; i++) + { + len = sizeof(interfaceGuidStr) / sizeof(interfaceGuidStr[0]); + l = RegEnumKeyExW(interfacesKey, i, interfaceGuidStr, &len, + NULL, NULL, NULL, NULL); + if (!l) + { + if (interfaceGuidStr[0] == '{' && + interfaceGuidStr[37] == '}') + { + HKEY interfaceKey; + GUID interfaceGuid; + + interfaceGuidStr[37] = 0; + UuidFromStringW(&interfaceGuidStr[1], &interfaceGuid); + l = RegOpenKeyExW(interfacesKey, interfaceGuidStr, 0, + KEY_READ, &interfaceKey); + if (!l) + { + SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet, + interfaceKey, &interfaceGuid, enumstr); + RegCloseKey(interfaceKey); + } + } + } + } + } + else + { + /* In this case, SetupDiOpenClassRegKeyExW opened the specific + * interface's key, so just pass that long + */ + SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet, + interfacesKey, interface, enumstr); + } + RegCloseKey(interfacesKey); + } +} + +static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet, + LPCWSTR parent, HKEY key, const GUID *class, DWORD flags) +{ + struct DeviceInfoSet *set = (struct DeviceInfoSet *)set; + DWORD i, len; + WCHAR subKeyName[MAX_PATH]; + LONG l = ERROR_SUCCESS; + + TRACE("%s\n", debugstr_w(parent)); + + for (i = 0; !l; i++) + { + len = sizeof(subKeyName) / sizeof(subKeyName[0]); + l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL); + if (!l) + { + HKEY subKey; + + l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); + if (!l) + { + WCHAR classGuid[40]; + DWORD dataType; + + len = sizeof(classGuid); + l = RegQueryValueExW(subKey, ClassGUID, NULL, &dataType, + (BYTE *)classGuid, &len); + if (!l && dataType == REG_SZ) + { + if (classGuid[0] == '{' && classGuid[37] == '}') + { + GUID deviceClass; + + classGuid[37] = 0; + UuidFromStringW(&classGuid[1], &deviceClass); + if ((flags & DIGCF_ALLCLASSES) || + IsEqualGUID(class, &deviceClass)) + { + static const WCHAR fmt[] = {'%','s','\\','%','s',0}; + LPWSTR instanceId; + + instanceId = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(parent) + lstrlenW(subKeyName) + 2) + * sizeof(WCHAR)); + if (instanceId) + { + SP_DEVINFO_DATA *dev; + + sprintfW(instanceId, fmt, parent, subKeyName); + SETUPDI_AddDeviceToSet(set, &deviceClass, + 0 /* FIXME: DevInst */, instanceId, + FALSE, &dev); + HeapFree(GetProcessHeap(), 0, instanceId); + } + } + } + } + RegCloseKey(subKey); + } + } + } +} + +static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class, + LPCWSTR enumstr, DWORD flags) +{ + HKEY classesKey = SetupDiOpenClassRegKeyExW(class, KEY_READ, + DIOCR_INSTALLER, NULL, NULL); + + TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class), + debugstr_w(enumstr), flags); + + if (classesKey != INVALID_HANDLE_VALUE) + { + if (enumstr) + { + HKEY enumKey; + LONG l = RegOpenKeyExW(classesKey, enumstr, 0, KEY_READ, + &enumKey); + + if (!l) + { + SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr, + enumKey, class, flags); + RegCloseKey(enumKey); + } + } + else + { + DWORD i, len; + WCHAR subKeyName[MAX_PATH]; + LONG l = ERROR_SUCCESS; + + for (i = 0; !l; i++) + { + len = sizeof(subKeyName) / sizeof(subKeyName[0]); + l = RegEnumKeyExW(classesKey, i, subKeyName, &len, NULL, + NULL, NULL, NULL); + if (!l) + { + HKEY subKey; + + l = RegOpenKeyExW(classesKey, subKeyName, 0, KEY_READ, + &subKey); + if (!l) + { + SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, + subKeyName, subKey, class, flags); + RegCloseKey(subKey); + } + } + } + } + RegCloseKey(classesKey); + } +} + /*********************************************************************** * SetupDiGetClassDevsW (SETUPAPI.@) */ @@ -1513,11 +1765,29 @@ HDEVINFO WINAPI SetupDiGetClassDevsW( HWND parent, DWORD flags) { + static const DWORD unsupportedFlags = DIGCF_DEFAULT | DIGCF_PRESENT | + DIGCF_PROFILE; + HDEVINFO set; + TRACE("%s %s %p 0x%08x\n", debugstr_guid(class), debugstr_w(enumstr), parent, flags); + if (!(flags & DIGCF_ALLCLASSES) && !class) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + if (flags & unsupportedFlags) + WARN("unsupported flags %08x\n", flags & unsupportedFlags); /* WinXP always succeeds, returns empty list for unknown classes */ - FIXME("returning empty list\n"); - return SetupDiCreateDeviceInfoList(class, parent); + set = SetupDiCreateDeviceInfoList(class, parent); + if (set) + { + if (flags & DIGCF_DEVICEINTERFACE) + SETUPDI_EnumerateInterfaces(set, class, enumstr, flags); + else + SETUPDI_EnumerateDevices(set, class, enumstr, flags); + } + return set; } /*********************************************************************** -- 1.4.1