From: zhangyue <test@.com> --- dlls/setupapi/devinst.c | 103 ++++++++++++++++++++++++++++++++++ dlls/setupapi/tests/devinst.c | 80 ++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 8f36ead4ef3..121dda98a59 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -3132,6 +3132,63 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo, return FALSE; } + if (Property == SPDRP_ENUMERATOR_NAME) + { + const WCHAR *backslash; + DWORD len; + int size_needed, size_written; + + if (!device->instanceId || !*device->instanceId) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + backslash = wcschr(device->instanceId, L'\\'); + len = backslash ? (DWORD)(backslash - device->instanceId) : lstrlenW(device->instanceId); + if (len == 0) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + size_needed = WideCharToMultiByte(CP_ACP, 0, device->instanceId, len, NULL, 0, NULL, NULL); + if (size_needed <= 0) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + size_needed++; + + if (RequiredSize) + *RequiredSize = size_needed; + + if (PropertyRegDataType) + *PropertyRegDataType = REG_SZ; + + if (!PropertyBuffer || (int)PropertyBufferSize < size_needed) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + size_written = WideCharToMultiByte(CP_ACP, 0, + device->instanceId, len, + (char *)PropertyBuffer, + PropertyBufferSize - 1, + NULL, NULL); + + if (size_written <= 0) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + ((char *)PropertyBuffer)[size_written] = 0; + return TRUE; + } + if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA) { DWORD size = PropertyBufferSize; @@ -3149,6 +3206,10 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo, if (RequiredSize) *RequiredSize = size; } + else + { + SetLastError(ERROR_INVALID_DATA); + } return ret; } @@ -3174,6 +3235,44 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo, return FALSE; } + if (Property == SPDRP_ENUMERATOR_NAME) + { + const WCHAR *backslash; + DWORD len, size_needed; + + if (!device->instanceId || !*device->instanceId) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + backslash = wcschr(device->instanceId, L'\\'); + len = backslash ? (DWORD)(backslash - device->instanceId) : lstrlenW(device->instanceId); + if (len == 0) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + size_needed = (len + 1) * sizeof(WCHAR); + + if (RequiredSize) + *RequiredSize = size_needed; + + if (PropertyRegDataType) + *PropertyRegDataType = REG_SZ; + + if (!PropertyBuffer || PropertyBufferSize < size_needed) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + memcpy(PropertyBuffer, device->instanceId, len * sizeof(WCHAR)); + ((WCHAR *)PropertyBuffer)[len] = 0; + return TRUE; + } + if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW) { DWORD size = PropertyBufferSize; @@ -3191,6 +3290,10 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo, if (RequiredSize) *RequiredSize = size; } + else + { + SetLastError(ERROR_INVALID_DATA); + } return ret; } diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c index d21a78b36ad..de29d93edd3 100644 --- a/dlls/setupapi/tests/devinst.c +++ b/dlls/setupapi/tests/devinst.c @@ -2438,6 +2438,46 @@ todo_wine { ok(ret, "Failed to get property, error %#lx.\n", GetLastError()); ok(!lstrcmpA(buf, "device_name"), "Got unexpected value %s.\n", buf); + /* SPDRP_UNUSED0: PropertyMap[3].nameW == NULL, fix returns ERROR_INVALID_DATA */ + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_UNUSED0, NULL, (BYTE *)buf, sizeof(buf), NULL); + ok(!ret, "Expected failure for SPDRP_UNUSED0.\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "Got unexpected error %#lx for SPDRP_UNUSED0.\n", GetLastError()); + + /* SPDRP_ENUMERATOR_NAME: enumerator is first segment of instanceId ("ROOT\...\0000" → "ROOT") */ + memset(buf, 0, sizeof(buf)); + ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, NULL, (BYTE *)buf, sizeof(buf), NULL); + ok(ret, "Failed to get SPDRP_ENUMERATOR_NAME, error %#lx.\n", GetLastError()); + ok(!strcmp(buf, "ROOT"), "Got unexpected enumerator '%s', expected 'ROOT'.\n", buf); + + /* SPDRP_ENUMERATOR_NAME: test PropertyRegDataType output */ + memset(buf, 0, sizeof(buf)); + type = 0xdeadbeef; + ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, &type, (BYTE *)buf, sizeof(buf), NULL); + ok(ret, "Failed to get SPDRP_ENUMERATOR_NAME, error %#lx.\n", GetLastError()); + ok(type == REG_SZ, "Got unexpected type %#lx, expected REG_SZ.\n", type); + + /* SPDRP_ENUMERATOR_NAME: test RequiredSize output (PropertyBuffer=NULL, PropertyBufferSize=0) */ + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, NULL, NULL, 0, &size); + ok(!ret, "Expected failure for NULL buffer.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#lx.\n", GetLastError()); + ok(size > 0, "Got unexpected size %lu.\n", size); + + /* SPDRP_ENUMERATOR_NAME: test with buffer too small */ + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, NULL, (BYTE *)buf, 3, &size); + ok(!ret, "Expected failure for small buffer.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#lx.\n", GetLastError()); + + /* SPDRP_ENUMERATOR_NAME: PropertyBuffer is NULL but PropertyBufferSize > 0 */ + /* Windows returns ERROR_INVALID_PARAMETER (A) or ERROR_PARTIAL_COPY (W) here, + * Wine returns ERROR_INVALID_DATA. Just check for failure. */ + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, NULL, NULL, sizeof(buf), NULL); + ok(!ret, "Expected failure for NULL buffer with size.\n"); + SetupDiDestroyDeviceInfoList(set); /* Create device from a registered class */ @@ -2598,6 +2638,46 @@ todo_wine { ok(ret, "Failed to get property, error %#lx.\n", GetLastError()); ok(!lstrcmpW(buf, L"device_name"), "Got unexpected value %s.\n", wine_dbgstr_w(buf)); + /* SPDRP_UNUSED0: PropertyMap[3].nameW == NULL, fix returns ERROR_INVALID_DATA */ + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_UNUSED0, NULL, (BYTE *)buf, sizeof(buf), NULL); + ok(!ret, "Expected failure for SPDRP_UNUSED0.\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "Got unexpected error %#lx for SPDRP_UNUSED0.\n", GetLastError()); + + /* SPDRP_ENUMERATOR_NAME: enumerator is first segment of instanceId ("ROOT\...\0000" → "ROOT") */ + memset(buf, 0, sizeof(buf)); + ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, NULL, (BYTE *)buf, sizeof(buf), NULL); + ok(ret, "Failed to get SPDRP_ENUMERATOR_NAME, error %#lx.\n", GetLastError()); + ok(!lstrcmpW(buf, L"ROOT"), "Got unexpected enumerator %s.\n", wine_dbgstr_w(buf)); + + /* SPDRP_ENUMERATOR_NAME: test PropertyRegDataType output */ + memset(buf, 0, sizeof(buf)); + type = 0xdeadbeef; + ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, &type, (BYTE *)buf, sizeof(buf), NULL); + ok(ret, "Failed to get SPDRP_ENUMERATOR_NAME, error %#lx.\n", GetLastError()); + ok(type == REG_SZ, "Got unexpected type %#lx, expected REG_SZ.\n", type); + + /* SPDRP_ENUMERATOR_NAME: test RequiredSize output (PropertyBuffer=NULL, PropertyBufferSize=0) */ + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, NULL, NULL, 0, &size); + ok(!ret, "Expected failure for NULL buffer.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#lx.\n", GetLastError()); + ok(size > 0, "Got unexpected size %lu.\n", size); + + /* SPDRP_ENUMERATOR_NAME: test with buffer too small */ + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, NULL, (BYTE *)buf, 3 * sizeof(WCHAR), &size); + ok(!ret, "Expected failure for small buffer.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#lx.\n", GetLastError()); + + /* SPDRP_ENUMERATOR_NAME: PropertyBuffer is NULL but PropertyBufferSize > 0 */ + /* Windows returns ERROR_INVALID_PARAMETER (A) or ERROR_PARTIAL_COPY (W) here, + * Wine returns ERROR_INVALID_DATA. Just check for failure. */ + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, NULL, NULL, sizeof(buf), NULL); + ok(!ret, "Expected failure for NULL buffer with size.\n"); + SetupDiDestroyDeviceInfoList(set); /* Create device from a registered class */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11189