From: Rémi Bernon rbernon@codeweavers.com
Changes by Paul Gofman to the original patch: - validate device_path length before copying in SetupDiOpenDeviceInterfaceW(); - don't use DIGCF_PRESENT flag. --- dlls/setupapi/devinst.c | 72 +++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 17 deletions(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 5a4e72b6771..275b6d363c0 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -3656,29 +3656,67 @@ done: /*********************************************************************** * SetupDiOpenDeviceInterfaceW (SETUPAPI.@) */ -BOOL WINAPI SetupDiOpenDeviceInterfaceW( - HDEVINFO DeviceInfoSet, - PCWSTR DevicePath, - DWORD OpenFlags, - PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) -{ - FIXME("%p %s %08lx %p\n", - DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData); +BOOL WINAPI SetupDiOpenDeviceInterfaceW(HDEVINFO devinfo, const WCHAR *device_path, + DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data) +{ + SP_DEVINFO_DATA device_data = {.cbSize = sizeof(device_data)}; + WCHAR instance_id[MAX_PATH], *tmp; + struct device_iface *iface; + struct device *device; + + TRACE("%p %s %#lx %p\n", devinfo, debugstr_w(device_path), flags, iface_data); + + if (flags) + FIXME("flags %#lx not implemented\n", flags); + + if (!device_path || wcslen(device_path) >= MAX_PATH) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + wcscpy(instance_id, device_path + 4); + if ((tmp = wcsrchr(instance_id, '#'))) *tmp = 0; + while ((tmp = wcschr(instance_id, '#'))) *tmp = '\'; + + if (!SetupDiGetClassDevsExW(NULL, instance_id, NULL, DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES, + devinfo, NULL, NULL)) + return FALSE; + if (!SetupDiOpenDeviceInfoW(devinfo, instance_id, NULL, 0, &device_data)) + return FALSE; + + if (!(device = get_device(devinfo, &device_data))) + return FALSE; + LIST_FOR_EACH_ENTRY(iface, &device->interfaces, struct device_iface, entry) + { + if (iface->symlink && !wcsicmp(device_path, iface->symlink)) + { + copy_device_iface_data(iface_data, iface); + return TRUE; + } + } + return FALSE; }
/*********************************************************************** * SetupDiOpenDeviceInterfaceA (SETUPAPI.@) */ -BOOL WINAPI SetupDiOpenDeviceInterfaceA( - HDEVINFO DeviceInfoSet, - PCSTR DevicePath, - DWORD OpenFlags, - PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) -{ - FIXME("%p %s %08lx %p\n", DeviceInfoSet, - debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData); - return FALSE; +BOOL WINAPI SetupDiOpenDeviceInterfaceA(HDEVINFO devinfo, const char *device_path, + DWORD flags, SP_DEVICE_INTERFACE_DATA *iface_data) +{ + WCHAR device_pathW[MAX_PATH]; + + TRACE("%p %s %#lx %p\n", devinfo, debugstr_a(device_path), flags, iface_data); + + if (!device_path || strlen(device_path) >= MAX_PATH) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + MultiByteToWideChar(CP_ACP, 0, device_path, -1, device_pathW, ARRAY_SIZE(device_pathW)); + return SetupDiOpenDeviceInterfaceW(devinfo, device_pathW, flags, iface_data); }
/***********************************************************************
From: Paul Gofman pgofman@codeweavers.com
--- dlls/setupapi/tests/devinst.c | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c index 0c902ce783b..722c08c866c 100644 --- a/dlls/setupapi/tests/devinst.c +++ b/dlls/setupapi/tests/devinst.c @@ -32,6 +32,7 @@ #include "wincrypt.h" #include "mscat.h" #include "devguid.h" +#include "ntddvdeo.h" #include "initguid.h" #include "devpkey.h" #include "setupapi.h" @@ -3940,6 +3941,64 @@ todo_wine { SetupDiDestroyDeviceInfoList(set); }
+static void test_SetupDiOpenDeviceInterface(void) +{ + BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; + SP_DEVICE_INTERFACE_DATA iface = { sizeof(iface) }; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; + SP_DEVINFO_DATA device = { sizeof(device) }; + WCHAR device_path[256]; + char device_patha[256]; + HDEVINFO set; + BOOL ret; + + set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, NULL, DIGCF_DEVICEINTERFACE); + ok(set != INVALID_HANDLE_VALUE, "got %p.\n", set); + ret = SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_DISPLAY_ADAPTER, 0, &iface); + if (!ret && GetLastError() == ERROR_NO_MORE_ITEMS) + { + skip("No display adapters, skipping test.\n"); + SetupDiDestroyDeviceInfoList(set); + return; + } + ok(ret, "got error %lu.\n", GetLastError()); + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer; + iface_data->cbSize = sizeof(*iface_data); + ret = SetupDiGetDeviceInterfaceDetailW(set, &iface, iface_data, sizeof(iface_detail_buffer), NULL, &device); + ok(ret, "got error %lu.\n", GetLastError()); + wcscpy(device_path, iface_data->DevicePath); + SetupDiDestroyDeviceInfoList(set); + + set = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "got %p.\n", set); + memset(&iface, 0xcc, sizeof(iface)); + iface.cbSize = sizeof(iface); + ret = SetupDiOpenDeviceInterfaceW(set, device_path, 0, &iface); + ok(ret, "got error %lu.\n", GetLastError()); + ok(IsEqualGUID(&iface.InterfaceClassGuid, &GUID_DEVINTERFACE_DISPLAY_ADAPTER), "got %s.\n", + debugstr_guid(&iface.InterfaceClassGuid)); + memset(&iface, 0xcc, sizeof(iface)); + iface.cbSize = sizeof(iface); + ret = SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_DISPLAY_ADAPTER, 0, &iface); + ok(ret, "got error %lu.\n", GetLastError()); + SetupDiDestroyDeviceInfoList(set); + + set = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "got %p.\n", set); + WideCharToMultiByte(CP_ACP, 0, device_path, -1, device_patha, sizeof(device_patha), NULL, NULL); + memset(&iface, 0xcc, sizeof(iface)); + iface.cbSize = sizeof(iface); + ret = SetupDiOpenDeviceInterfaceA(set, device_patha, 0, &iface); + ok(ret, "got error %lu.\n", GetLastError()); + ok(IsEqualGUID(&iface.InterfaceClassGuid, &GUID_DEVINTERFACE_DISPLAY_ADAPTER), "got %s.\n", + debugstr_guid(&iface.InterfaceClassGuid)); + memset(&iface, 0xcc, sizeof(iface)); + iface.cbSize = sizeof(iface); + ret = SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_DISPLAY_ADAPTER, 0, &iface); + ok(ret, "got error %lu.\n", GetLastError()); + SetupDiDestroyDeviceInfoList(set); +} + static BOOL file_exists(const char *path) { return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES; @@ -4699,6 +4758,7 @@ START_TEST(devinst) test_driver_list(); test_call_class_installer(); test_get_class_devs(); + test_SetupDiOpenDeviceInterface();
if (!testsign_create_cert(&ctx)) return;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/cfgmgr32/cfgmgr32.spec | 4 +- dlls/cfgmgr32/tests/cfgmgr32.c | 54 ++++++++++++++++ dlls/setupapi/devinst.c | 113 +++++++++++++++++++++++++++++++++ dlls/setupapi/setupapi.spec | 4 +- dlls/setupapi/stubs.c | 20 ------ include/cfgmgr32.h | 16 +++++ 6 files changed, 187 insertions(+), 24 deletions(-)
diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index d940bb63427..99d14ee7c50 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -84,9 +84,9 @@ @ stub CM_Get_Device_Interface_Alias_ExA @ stub CM_Get_Device_Interface_Alias_ExW @ stub CM_Get_Device_Interface_ListA -@ stub CM_Get_Device_Interface_ListW +@ stdcall CM_Get_Device_Interface_ListW(ptr ptr ptr long long) setupapi.CM_Get_Device_Interface_ListW @ stub CM_Get_Device_Interface_List_ExA -@ stub CM_Get_Device_Interface_List_ExW +@ stdcall CM_Get_Device_Interface_List_ExW(ptr ptr ptr long long ptr) setupapi.CM_Get_Device_Interface_List_ExW @ stdcall CM_Get_Device_Interface_List_SizeA(ptr ptr str long) setupapi.CM_Get_Device_Interface_List_SizeA @ stdcall CM_Get_Device_Interface_List_SizeW(ptr ptr wstr long) setupapi.CM_Get_Device_Interface_List_SizeW @ stdcall CM_Get_Device_Interface_List_Size_ExA(ptr ptr str long ptr) setupapi.CM_Get_Device_Interface_List_Size_ExA diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index c28b61527a2..4c9737a7bec 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -363,9 +363,63 @@ static void test_CM_Register_Notification( void ) } }
+static void test_CM_Get_Device_Interface_List(void) +{ + BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; + SP_DEVINFO_DATA device = { sizeof(device) }; + unsigned int count, count2; + WCHAR *buffer, *p; + CONFIGRET ret; + HDEVINFO set; + ULONG size; + GUID guid; + BOOL bret; + + guid = GUID_DEVINTERFACE_DISPLAY_ADAPTER; + + ret = CM_Get_Device_Interface_List_SizeW(&size, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + ok(!ret, "got %#lx.\n", ret); + + buffer = malloc(size * sizeof(*buffer)); + ret = CM_Get_Device_Interface_ListW( &guid, NULL, buffer, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + ok(!ret, "got %#lx.\n", ret); + + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer; + + count = 0; + p = buffer; + while (*p) + { + set = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "got %p.\n", set); + bret = SetupDiOpenDeviceInterfaceW(set, p, 0, &iface); + ok(bret, "got error %lu.\n", GetLastError()); + memset(iface_detail_buffer, 0xcc, sizeof(iface_detail_buffer)); + iface_data->cbSize = sizeof(*iface_data); + bret = SetupDiGetDeviceInterfaceDetailW(set, &iface, iface_data, sizeof(iface_detail_buffer), NULL, &device); + ok(bret, "got error %lu.\n", GetLastError()); + ok(!wcsicmp(iface_data->DevicePath, p), "got %s, expected %s.\n", debugstr_w(p), debugstr_w(iface_data->DevicePath)); + SetupDiDestroyDeviceInfoList(set); + p += wcslen(p) + 1; + ++count; + } + + free(buffer); + + set = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); + ok(set != INVALID_HANDLE_VALUE, "got %p.\n", set); + for (count2 = 0; SetupDiEnumDeviceInterfaces(set, NULL, &guid, count2, &iface); ++count2) + ; + SetupDiDestroyDeviceInfoList(set); + ok(count == count2, "got %u, expected %u.\n", count, count2); +} + START_TEST(cfgmgr32) { test_CM_MapCrToWin32Err(); test_CM_Get_Device_ID_List(); test_CM_Register_Notification(); + test_CM_Get_Device_Interface_List(); } diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 275b6d363c0..475291a289d 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -4560,6 +4560,119 @@ CONFIGRET WINAPI CM_Get_Device_ID_List_SizeA(ULONG *len, const char *filter, ULO return CM_Get_Device_ID_List_Size_ExA(len, filter, flags, NULL); }
+static CONFIGRET get_device_interface_list(const GUID *class_guid, DEVINSTID_W device_id, WCHAR *buffer, ULONG *len, + ULONG flags) +{ + const ULONG supported_flags = CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES; + + BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; + SP_DEVINFO_DATA device = { sizeof(device) }; + ULONG query_flags = DIGCF_DEVICEINTERFACE; + CONFIGRET ret = CR_SUCCESS; + unsigned int i, id_len; + HDEVINFO set; + ULONG needed; + WCHAR *p; + + if (!len || (buffer && !*len)) + return CR_INVALID_POINTER; + + needed = 1; + + if (buffer) + *buffer = 0; + if (flags & ~supported_flags) + FIXME("Flags %#lx are not supported.\n", flags); + + if (!buffer) + *len = 0; + + if (!buffer) + *len = needed; + + if (!(flags & CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES)) query_flags |= DIGCF_PRESENT; + set = SetupDiGetClassDevsW(class_guid, device_id, NULL, query_flags); + if (set == INVALID_HANDLE_VALUE) + return CR_SUCCESS; + + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer; + iface_data->cbSize = sizeof(*iface_data); + + p = buffer; + for (i = 0; SetupDiEnumDeviceInterfaces(set, NULL, class_guid, i, &iface); ++i) + { + ret = SetupDiGetDeviceInterfaceDetailW(set, &iface, iface_data, sizeof(iface_detail_buffer), NULL, &device); + if (!ret) continue; + id_len = wcslen(iface_data->DevicePath) + 1; + needed += id_len; + if (buffer) + { + if (needed > *len) + { + SetupDiDestroyDeviceInfoList(set); + *buffer = 0; + return CR_BUFFER_SMALL; + } + memcpy(p, iface_data->DevicePath, sizeof(*p) * id_len); + p += id_len; + } + } + SetupDiDestroyDeviceInfoList(set); + *len = needed; + if (buffer) + *p = 0; + return CR_SUCCESS; +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_Size_ExW (SETUPAPI.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExW(PULONG len, LPGUID class, DEVINSTID_W id, + ULONG flags, HMACHINE machine) +{ + TRACE("%p %s %s 0x%08lx %p\n", len, debugstr_guid(class), debugstr_w(id), flags, machine); + + if (machine) + FIXME("machine %p.\n", machine); + + return get_device_interface_list(class, id, NULL, len, flags); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_SizeW (SETUPAPI.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeW(PULONG len, LPGUID class, DEVINSTID_W id, ULONG flags) +{ + TRACE("%p %s %s 0x%08lx\n", len, debugstr_guid(class), debugstr_w(id), flags); + return get_device_interface_list(class, id, NULL, len, flags); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_W (SETUPAPI.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_ExW(LPGUID class, DEVINSTID_W id, PZZWSTR buffer, ULONG len, ULONG flags, + HMACHINE machine) +{ + TRACE("%s %s %p %lu %#lx\n", debugstr_guid(class), debugstr_w(id), buffer, len, flags); + + if (machine) + FIXME("machine %p.\n", machine); + + return get_device_interface_list(class, id, buffer, &len, flags); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_W (SETUPAPI.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_ListW(LPGUID class, DEVINSTID_W id, PZZWSTR buffer, ULONG len, ULONG flags) +{ + TRACE("%s %s %p %lu %#lx\n", debugstr_guid(class), debugstr_w(id), buffer, len, flags); + + return get_device_interface_list(class, id, buffer, &len, flags); +} + /*********************************************************************** * SetupDiGetINFClassA (SETUPAPI.@) */ diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index f77cb301dfe..e38946587c2 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -94,9 +94,9 @@ @ stub CM_Get_Device_Interface_Alias_ExA @ stub CM_Get_Device_Interface_Alias_ExW @ stub CM_Get_Device_Interface_ListA -@ stub CM_Get_Device_Interface_ListW +@ stdcall CM_Get_Device_Interface_ListW(ptr ptr ptr long long) @ stub CM_Get_Device_Interface_List_ExA -@ stub CM_Get_Device_Interface_List_ExW +@ stdcall CM_Get_Device_Interface_List_ExW(ptr ptr ptr long long ptr) @ stdcall CM_Get_Device_Interface_List_SizeA(ptr ptr str long) @ stdcall CM_Get_Device_Interface_List_SizeW(ptr ptr wstr long) @ stdcall CM_Get_Device_Interface_List_Size_ExA(ptr ptr str long ptr) diff --git a/dlls/setupapi/stubs.c b/dlls/setupapi/stubs.c index 0766b1364bf..96ecc778a9d 100644 --- a/dlls/setupapi/stubs.c +++ b/dlls/setupapi/stubs.c @@ -277,16 +277,6 @@ CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeA(PULONG len, LPGUID class, DE return CR_FAILURE; }
-/*********************************************************************** - * CM_Get_Device_Interface_List_SizeW (SETUPAPI.@) - */ -CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeW(PULONG len, LPGUID class, DEVINSTID_W id, - ULONG flags) -{ - FIXME("%p %p %s 0x%08lx: stub\n", len, class, debugstr_w(id), flags); - return CR_FAILURE; -} - /*********************************************************************** * CM_Get_Device_Interface_List_Size_ExA (SETUPAPI.@) */ @@ -297,16 +287,6 @@ CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExA(PULONG len, LPGUID class, return CR_FAILURE; }
-/*********************************************************************** - * CM_Get_Device_Interface_List_Size_ExW (SETUPAPI.@) - */ -CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExW(PULONG len, LPGUID class, DEVINSTID_W id, - ULONG flags, HMACHINE machine) -{ - FIXME("%p %p %s 0x%08lx %p: stub\n", len, class, debugstr_w(id), flags, machine); - return CR_FAILURE; -} - /*********************************************************************** * CM_Get_Device_Interface_AliasA (SETUPAPI.@) */ diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h index 3e814757e2b..ee84533a2d0 100644 --- a/include/cfgmgr32.h +++ b/include/cfgmgr32.h @@ -196,6 +196,10 @@ typedef DWORD CONFIGRET; #define CM_GETIDLIST_FILTER_CLASS 0x00000200 #define CM_GETIDLIST_FILTER_BITS 0x100003FF
+#define CM_GET_DEVICE_INTERFACE_LIST_PRESENT 0x00000000 +#define CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES 0x00000001 +#define CM_GET_DEVICE_INTERFACE_LIST_BITS 0x00000001 + typedef DWORD DEVINST, *PDEVINST; typedef DWORD DEVNODE, *PDEVNODE; typedef HANDLE HMACHINE, *PHMACHINE; @@ -314,6 +318,18 @@ CMAPI CONFIGRET WINAPI CM_Get_Device_ID_List_Size_ExW(PULONG,PCWSTR,ULONG,HMACHI #define CM_Get_Device_ID_List_Size_Ex WINELIB_NAME_AW(CM_Get_Device_ID_List_Size_Ex) CMAPI CONFIGRET WINAPI CM_Get_Device_ID_Size(PULONG,DEVINST,ULONG); CMAPI CONFIGRET WINAPI CM_Get_Device_ID_Size_Ex(PULONG,DEVINST,ULONG,HMACHINE); +CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_ListW(LPGUID,DEVINSTID_W,PZZWSTR,ULONG,ULONG); +CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_ListA(LPGUID,DEVINSTID_A,PZZSTR,ULONG,ULONG); +#define CM_Get_Device_Interface_List WINELIB_NAME_AW(CM_Get_Device_Interface_List) +CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeW(PULONG,LPGUID,DEVINSTID_W,ULONG); +CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeA(PULONG,LPGUID,DEVINSTID_A,ULONG); +#define CM_Get_Device_Interface_List_Size WINELIB_NAME_AW(CM_Get_Device_Interface_List_Size) +CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_ExW(LPGUID,DEVINSTID_W,PZZWSTR,ULONG,ULONG,HMACHINE); +CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_ExA(LPGUID,DEVINSTID_A,PZZSTR,ULONG,ULONG,HMACHINE); +#define CM_Get_Device_Interface_List_Ex WINELIB_NAME_AW(CM_Get_Device_Interface_List_Ex) +CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExW(PULONG,LPGUID,DEVINSTID_W,ULONG,HMACHINE); +CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExA(PULONG,LPGUID,DEVINSTID_A,ULONG,HMACHINE); +#define CM_Get_Device_Interface_List_Size_Ex WINELIB_NAME_AW(CM_Get_Device_Interface_List_Size_Ex) CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_PropertyW(LPCWSTR,const DEVPROPKEY*,DEVPROPTYPE*,PBYTE,PULONG,ULONG); CMAPI CONFIGRET WINAPI CM_Get_DevNode_PropertyW(DEVINST,const DEVPROPKEY *,DEVPROPTYPE *type,PVOID,PULONG,ULONG); CMAPI CONFIGRET WINAPI CM_Get_DevNode_PropertyExW(DEVINST,const DEVPROPKEY *,DEVPROPTYPE *type,PVOID,PULONG,ULONG,HMACHINE);
From: Paul Gofman pgofman@codeweavers.com
--- dlls/cfgmgr32/cfgmgr32.spec | 4 +- dlls/cfgmgr32/tests/cfgmgr32.c | 21 +++++++- dlls/setupapi/devinst.c | 93 ++++++++++++++++++++++++++++++++++ dlls/setupapi/setupapi.spec | 4 +- dlls/setupapi/stubs.c | 20 -------- 5 files changed, 117 insertions(+), 25 deletions(-)
diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 99d14ee7c50..6d493144455 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -83,9 +83,9 @@ @ stdcall CM_Get_Device_Interface_AliasW(wstr ptr ptr ptr long) setupapi.CM_Get_Device_Interface_AliasW @ stub CM_Get_Device_Interface_Alias_ExA @ stub CM_Get_Device_Interface_Alias_ExW -@ stub CM_Get_Device_Interface_ListA +@ stdcall CM_Get_Device_Interface_ListA(ptr ptr ptr long long) setupapi.CM_Get_Device_Interface_ListA @ stdcall CM_Get_Device_Interface_ListW(ptr ptr ptr long long) setupapi.CM_Get_Device_Interface_ListW -@ stub CM_Get_Device_Interface_List_ExA +@ stdcall CM_Get_Device_Interface_List_ExA(ptr ptr ptr long long ptr) setupapi.CM_Get_Device_Interface_List_ExA @ stdcall CM_Get_Device_Interface_List_ExW(ptr ptr ptr long long ptr) setupapi.CM_Get_Device_Interface_List_ExW @ stdcall CM_Get_Device_Interface_List_SizeA(ptr ptr str long) setupapi.CM_Get_Device_Interface_List_SizeA @ stdcall CM_Get_Device_Interface_List_SizeW(ptr ptr wstr long) setupapi.CM_Get_Device_Interface_List_SizeW diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 4c9737a7bec..165d262e29e 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -370,10 +370,11 @@ static void test_CM_Get_Device_Interface_List(void) SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; SP_DEVINFO_DATA device = { sizeof(device) }; unsigned int count, count2; + char *buffera, *pa; WCHAR *buffer, *p; + ULONG size, size2; CONFIGRET ret; HDEVINFO set; - ULONG size; GUID guid; BOOL bret;
@@ -386,6 +387,24 @@ static void test_CM_Get_Device_Interface_List(void) ret = CM_Get_Device_Interface_ListW( &guid, NULL, buffer, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); ok(!ret, "got %#lx.\n", ret);
+ ret = CM_Get_Device_Interface_List_SizeA(&size2, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + ok(!ret, "got %#lx.\n", ret); + ok(size2 == size, "got %lu, %lu.\n", size, size2); + buffera = malloc(size2 * sizeof(*buffera)); + ret = CM_Get_Device_Interface_ListA(&guid, NULL, buffera, size2, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + ok(!ret, "got %#lx.\n", ret); + p = malloc(size2 * sizeof(*p)); + pa = buffera; + *p = 0; + while (*pa) + { + MultiByteToWideChar(CP_ACP, 0, pa, -1, p + (pa - buffera), size2 - (pa - buffera)); + pa += strlen(pa) + 1; + } + ok(!memcmp(p, buffer, size * sizeof(*p)), "results differ %s %s.\n", debugstr_w(p), debugstr_w(buffer)); + free(p); + free(buffera); + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer;
count = 0; diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 475291a289d..0cfd5253565 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -4673,6 +4673,99 @@ CONFIGRET WINAPI CM_Get_Device_Interface_ListW(LPGUID class, DEVINSTID_W id, PZZ return get_device_interface_list(class, id, buffer, &len, flags); }
+/*********************************************************************** + * CM_Get_Device_Interface_List_SizeA (SETUPAPI.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeA(PULONG len, LPGUID class, DEVINSTID_A id, + ULONG flags) +{ + return CM_Get_Device_Interface_List_Size_ExA(len, class, id, flags, NULL); +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_Size_ExA (SETUPAPI.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExA(PULONG len, LPGUID class, DEVINSTID_A id, + ULONG flags, HMACHINE machine) +{ + WCHAR *wid = NULL; + unsigned int slen; + CONFIGRET ret; + + TRACE("%p %s %s 0x%08lx %p\n", len, debugstr_guid(class), debugstr_a(id), flags, machine); + + if (machine) + FIXME("machine %p.\n", machine); + + if (id) + { + slen = strlen(id) + 1; + if (!(wid = malloc(slen * sizeof(*wid)))) + return CR_OUT_OF_MEMORY; + MultiByteToWideChar(CP_ACP, 0, id, slen, wid, slen); + } + ret = CM_Get_Device_Interface_List_SizeW(len, class, wid, flags); + free(wid); + return ret; +} + +/*********************************************************************** + * CM_Get_Device_Interface_List_ExA (SETUPAPI.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_List_ExA(LPGUID class, DEVINSTID_A id, PZZSTR buffer, ULONG len, ULONG flags, + HMACHINE machine) +{ + WCHAR *wbuffer, *wid = NULL, *p; + unsigned int slen; + CONFIGRET ret; + + TRACE("%s %s %p %lu 0x%08lx %p\n", debugstr_guid(class), debugstr_a(id), buffer, len, flags, machine); + + if (machine) + FIXME("machine %p.\n", machine); + + if (!buffer || !len) + return CR_INVALID_POINTER; + + if (!(wbuffer = malloc(len * sizeof(*wbuffer)))) + return CR_OUT_OF_MEMORY; + + if (id) + { + slen = strlen(id) + 1; + if (!(wid = malloc(slen * sizeof(*id)))) + { + free(wbuffer); + return CR_OUT_OF_MEMORY; + } + MultiByteToWideChar(CP_ACP, 0, id, slen, wid, slen); + } + + if (!(ret = CM_Get_Device_Interface_List_ExW(class, wid, wbuffer, len, flags, machine))) + { + p = wbuffer; + while (*p) + { + slen = wcslen(p) + 1; + WideCharToMultiByte(CP_ACP, 0, p, slen, buffer, slen, NULL, NULL); + p += slen; + buffer += slen; + } + *buffer = 0; + } + free(wid); + free(wbuffer); + return ret; +} + +/*********************************************************************** + * CM_Get_Device_Interface_ListA (SETUPAPI.@) + */ +CONFIGRET WINAPI CM_Get_Device_Interface_ListA(LPGUID class, DEVINSTID_A id, PZZSTR buffer, ULONG len, ULONG flags) +{ + return CM_Get_Device_Interface_List_ExA(class, id, buffer, len, flags, NULL); +} + /*********************************************************************** * SetupDiGetINFClassA (SETUPAPI.@) */ diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index e38946587c2..d5beb4e1ab7 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -93,9 +93,9 @@ @ stdcall CM_Get_Device_Interface_AliasW(wstr ptr ptr ptr long) @ stub CM_Get_Device_Interface_Alias_ExA @ stub CM_Get_Device_Interface_Alias_ExW -@ stub CM_Get_Device_Interface_ListA +@ stdcall CM_Get_Device_Interface_ListA(ptr ptr ptr long long) @ stdcall CM_Get_Device_Interface_ListW(ptr ptr ptr long long) -@ stub CM_Get_Device_Interface_List_ExA +@ stdcall CM_Get_Device_Interface_List_ExA(ptr ptr ptr long long ptr) @ stdcall CM_Get_Device_Interface_List_ExW(ptr ptr ptr long long ptr) @ stdcall CM_Get_Device_Interface_List_SizeA(ptr ptr str long) @ stdcall CM_Get_Device_Interface_List_SizeW(ptr ptr wstr long) diff --git a/dlls/setupapi/stubs.c b/dlls/setupapi/stubs.c index 96ecc778a9d..44c81a1fd97 100644 --- a/dlls/setupapi/stubs.c +++ b/dlls/setupapi/stubs.c @@ -267,26 +267,6 @@ BOOL WINAPI SetupDiGetClassImageIndex(PSP_CLASSIMAGELIST_DATA ClassImageListData return FALSE; }
-/*********************************************************************** - * CM_Get_Device_Interface_List_SizeA (SETUPAPI.@) - */ -CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeA(PULONG len, LPGUID class, DEVINSTID_A id, - ULONG flags) -{ - FIXME("%p %p %s 0x%08lx: stub\n", len, class, debugstr_a(id), flags); - return CR_FAILURE; -} - -/*********************************************************************** - * CM_Get_Device_Interface_List_Size_ExA (SETUPAPI.@) - */ -CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExA(PULONG len, LPGUID class, DEVINSTID_A id, - ULONG flags, HMACHINE machine) -{ - FIXME("%p %p %s 0x%08lx %p: stub\n", len, class, debugstr_a(id), flags, machine); - return CR_FAILURE; -} - /*********************************************************************** * CM_Get_Device_Interface_AliasA (SETUPAPI.@) */
From: Paul Gofman pgofman@codeweavers.com
--- dlls/cfgmgr32/main.c | 47 +++++++++++++++++++++++++++++++--- dlls/cfgmgr32/tests/cfgmgr32.c | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 3 deletions(-)
diff --git a/dlls/cfgmgr32/main.c b/dlls/cfgmgr32/main.c index fbe39365975..fbff2c2fbf9 100644 --- a/dlls/cfgmgr32/main.c +++ b/dlls/cfgmgr32/main.c @@ -23,6 +23,10 @@ #include "winuser.h" #include "dbt.h" #include "wine/plugplay.h" +#include "setupapi.h" + +#include "initguid.h" +#include "devpkey.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
@@ -250,8 +254,45 @@ CONFIGRET WINAPI CM_Get_Device_Interface_PropertyW( LPCWSTR device_interface, co DEVPROPTYPE *property_type, BYTE *property_buffer, ULONG *property_buffer_size, ULONG flags ) { - FIXME("%s %p %p %p %p %ld stub!\n", debugstr_w(device_interface), property_key, property_type, - property_buffer, property_buffer_size, flags); + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVINFO_DATA device = { sizeof(device) }; + HDEVINFO set; + DWORD err; + BOOL ret; + + TRACE( "%s %p %p %p %p %ld.\n", debugstr_w(device_interface), property_key, property_type, property_buffer, + property_buffer_size, flags); + + if (!property_key) return CR_FAILURE; + if (!device_interface || !property_type || !property_buffer_size) return CR_INVALID_POINTER; + if (*property_buffer_size && !property_buffer) return CR_INVALID_POINTER; + if (flags) return CR_INVALID_FLAG; + + if (memcmp( property_key, &DEVPKEY_Device_InstanceId, sizeof(*property_key) )) + { + FIXME( "property %s\%lx.\n", debugstr_guid( &property_key->fmtid ), property_key->pid ); + return CR_NO_SUCH_VALUE; + }
- return CR_CALL_NOT_IMPLEMENTED; + set = SetupDiCreateDeviceInfoListExW( NULL, NULL, NULL, NULL ); + if (set == INVALID_HANDLE_VALUE) return CR_OUT_OF_MEMORY; + if (!SetupDiOpenDeviceInterfaceW( set, device_interface, 0, &iface )) + { + SetupDiDestroyDeviceInfoList( set ); + TRACE( "No interface %s, err %lu.\n", debugstr_w( device_interface ), GetLastError()); + return CR_NO_SUCH_DEVICE_INTERFACE; + } + if (!SetupDiEnumDeviceInfo( set, 0, &device )) + { + SetupDiDestroyDeviceInfoList( set ); + return CR_FAILURE; + } + ret = SetupDiGetDeviceInstanceIdW( set, &device, (WCHAR *)property_buffer, *property_buffer_size / sizeof(WCHAR), + property_buffer_size ); + err = ret ? 0 : GetLastError(); + SetupDiDestroyDeviceInfoList( set ); + *property_type = DEVPROP_TYPE_STRING; + *property_buffer_size *= sizeof(WCHAR); + if (!err) return CR_SUCCESS; + return err == ERROR_INSUFFICIENT_BUFFER ? CR_BUFFER_SMALL : CR_FAILURE; } diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 165d262e29e..2af35d90fdd 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -369,10 +369,12 @@ static void test_CM_Get_Device_Interface_List(void) SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; SP_DEVINFO_DATA device = { sizeof(device) }; + WCHAR instance_id[256], expected_id[256]; unsigned int count, count2; char *buffera, *pa; WCHAR *buffer, *p; ULONG size, size2; + DEVPROPTYPE type; CONFIGRET ret; HDEVINFO set; GUID guid; @@ -420,7 +422,48 @@ static void test_CM_Get_Device_Interface_List(void) bret = SetupDiGetDeviceInterfaceDetailW(set, &iface, iface_data, sizeof(iface_detail_buffer), NULL, &device); ok(bret, "got error %lu.\n", GetLastError()); ok(!wcsicmp(iface_data->DevicePath, p), "got %s, expected %s.\n", debugstr_w(p), debugstr_w(iface_data->DevicePath)); + bret = SetupDiGetDeviceInstanceIdW(set, &device, expected_id, ARRAY_SIZE(expected_id), NULL); + ok(bret, "got error %lu.\n", GetLastError()); SetupDiDestroyDeviceInfoList(set); + + size = 0xdeadbeef; + type = 0xdeadbeef; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, NULL, &size, 0); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ok(type == 0xdeadbeef, "got type %#lx.\n", type); + ok(size == 0xdeadbeef, "got %#lx.\n", size); + + size = 0; + type = 0xdeadbeef; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, NULL, &size, 0); + ok(ret == CR_BUFFER_SMALL, "got %#lx.\n", ret); + ok(type == DEVPROP_TYPE_STRING, "got type %#lx.\n", type); + ok(size && size != 0xdeadbeef, "got %#lx.\n", size); + + ret = CM_Get_Device_Interface_PropertyW(p, NULL, &type, (BYTE *)instance_id, &size, 0); + ok(ret == CR_FAILURE, "got %#lx.\n", ret); + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, NULL, (BYTE *)instance_id, &size, 0); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ret = CM_Get_Device_Interface_PropertyW(NULL, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, NULL, 0); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 1); + ok(ret == CR_INVALID_FLAG, "got %#lx.\n", ret); + + size = 0; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, NULL, &size, 0); + ok(ret == CR_BUFFER_SMALL, "got %#lx.\n", ret); + + --size; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0); + ok(ret == CR_BUFFER_SMALL, "got %#lx.\n", ret); + + type = 0xdeadbeef; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0); + ok(!ret, "got %#lx.\n", ret); + ok(type == DEVPROP_TYPE_STRING, "got type %#lx.\n", type); + ok(!wcsicmp(instance_id, expected_id), "got %s, expected %s.\n", debugstr_w(instance_id), debugstr_w(expected_id)); p += wcslen(p) + 1; ++count; } @@ -433,6 +476,9 @@ static void test_CM_Get_Device_Interface_List(void) ; SetupDiDestroyDeviceInfoList(set); ok(count == count2, "got %u, expected %u.\n", count, count2); + + ret = CM_Get_Device_Interface_PropertyW(L"qqq", &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0); + ok(ret == CR_NO_SUCH_DEVICE_INTERFACE, "got %#lx.\n", ret); }
START_TEST(cfgmgr32)
Fixes MySims Kingdom not working with controllers.
WRT the last patch, we don't set any properties for devicee interfaces currently. I could not find device id in the properties subkeys for device interfaces on Windows (as well as any properties, actually, across a few interfaces I checked). So I guess even we will be adding properties for device interfaces device instance id will be treated as a special case anyway. DEVPKEY_Device_InstanceId is the only property which this specific game queries with CM_Get_Device_Interface_PropertyW(), so I don't have a real world example of any other been used.
This merge request was approved by Paul Gofman.