setupapi: Use INF parser to read class GUID and class name.

Previously, SetupDiGetINFClassW read INF files with
GetPrivateProfileString, which does not substitute %strkey% tokens.

This caused device installation to fail for devices which had driver
INF files using %strkey% tokens in Version section.

An example of such device is Vernier LabQuest Mini (08f7:0008) for
which Vernier's LoggerPro application includes a driver.

The INF file in question adds a new device setup class and has
following entries in Version section:

  Class = %ClassName%
  ClassGuid = %DeviceClassGUID%

Strings section includes following entries:

  DeviceClassGUID = "{6B8429BF-10AD-4b66-9FBA-2FE72B891721}"
  ClassName = "VST_WinUSB"

Previously, when LoggerPro was installed and LabQuest Mini was
hotplugged, device installation failed with the following error:

  fixme:setupapi:SetupDiGetINFClassW failed to convert "L"%DeviceClassGUID"" into a guid

This caused GUID_NULL to be used and Class was not set to the registry
for the device.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56579
This commit is contained in:
Tuomas Räsänen 2024-04-19 14:50:32 +03:00 committed by Alexandre Julliard
parent d8bbf6d0ae
commit 987695a427
2 changed files with 54 additions and 16 deletions

View file

@ -4280,8 +4280,11 @@ BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
DWORD size, PDWORD required_size)
{
BOOL have_guid, have_name;
DWORD dret;
DWORD class_name_len;
WCHAR buffer[MAX_PATH];
INFCONTEXT inf_ctx;
HINF hinf;
BOOL retval = FALSE;
if (!inf)
{
@ -4302,30 +4305,63 @@ BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
return FALSE;
}
if (!GetPrivateProfileStringW(Version, Signature, NULL, buffer, MAX_PATH, inf))
if ((hinf = SetupOpenInfFileW(inf, NULL, INF_STYLE_WIN4, NULL)) == INVALID_HANDLE_VALUE)
{
ERR("failed to open INF file %s\n", debugstr_w(inf));
return FALSE;
}
if (!SetupFindFirstLineW(hinf, Version, Signature, &inf_ctx))
{
ERR("INF file %s does not have mandatory [Version].Signature\n", debugstr_w(inf));
goto out;
}
if (!SetupGetStringFieldW(&inf_ctx, 1, buffer, ARRAY_SIZE(buffer), NULL))
{
ERR("failed to get [Version].Signature string from %s\n", debugstr_w(inf));
goto out;
}
if (lstrcmpiW(buffer, Chicago) && lstrcmpiW(buffer, WindowsNT))
return FALSE;
{
ERR("INF file %s has invalid [Version].Signature: %s\n", debugstr_w(inf), debugstr_w(buffer));
goto out;
}
have_guid = SetupFindFirstLineW(hinf, Version, ClassGUID, &inf_ctx);
buffer[0] = '\0';
have_guid = 0 < GetPrivateProfileStringW(Version, ClassGUID, NULL, buffer, MAX_PATH, inf);
if (have_guid)
{
if (!SetupGetStringFieldW(&inf_ctx, 1, buffer, ARRAY_SIZE(buffer), NULL))
{
ERR("failed to get [Version].ClassGUID as a string from '%s'\n", debugstr_w(inf));
goto out;
}
buffer[lstrlenW(buffer)-1] = 0;
if (RPC_S_OK != UuidFromStringW(buffer + 1, class_guid))
{
FIXME("failed to convert \"%s\" into a guid\n", debugstr_w(buffer));
ERR("INF file %s has invalid [Version].ClassGUID: %s\n", debugstr_w(inf), debugstr_w(buffer));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
goto out;
}
}
buffer[0] = '\0';
dret = GetPrivateProfileStringW(Version, Class, NULL, buffer, MAX_PATH, inf);
have_name = 0 < dret;
have_name = SetupFindFirstLineW(hinf, Version, Class, &inf_ctx);
class_name_len = 0;
if (have_name)
{
if (!SetupGetStringFieldW(&inf_ctx, 1, buffer, ARRAY_SIZE(buffer), NULL))
{
ERR("failed to get [Version].Class as a string from '%s'\n", debugstr_w(inf));
goto out;
}
class_name_len = lstrlenW(buffer);
}
if (dret >= MAX_PATH -1) FIXME("buffer might be too small\n");
if (have_guid && !have_name)
{
class_name[0] = '\0';
@ -4334,7 +4370,7 @@ BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
if (have_name)
{
if (dret < size) lstrcpyW(class_name, buffer);
if (class_name_len < size) lstrcpyW(class_name, buffer);
else
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
@ -4342,9 +4378,12 @@ BOOL WINAPI SetupDiGetINFClassW(PCWSTR inf, LPGUID class_guid, PWSTR class_name,
}
}
if (required_size) *required_size = dret + ((dret) ? 1 : 0);
if (required_size) *required_size = class_name_len + ((class_name_len) ? 1 : 0);
return (have_guid || have_name);
retval = (have_guid || have_name);
out:
SetupCloseInfFile(hinf);
return retval;
}
static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop_key, DEVPROPTYPE *prop_type,

View file

@ -2031,12 +2031,11 @@ static void test_get_inf_class(void)
WritePrivateProfileStringA("Strings", "ClassGuid", "{deadbeef-dead-beef-dead-beefdeadbeef}", filename);
count = 0xdeadbeef;
retval = SetupDiGetINFClassA(filename, &guid, cn, MAX_PATH, &count);
todo_wine {
ok(retval, "expected SetupDiGetINFClassA to succeed! error %lu\n", GetLastError());
ok(count == lstrlenA(deadbeef_class_name) + 1, "expected count=%d, got %lu\n", lstrlenA(deadbeef_class_name) + 1, count);
ok(!lstrcmpA(deadbeef_class_name, cn), "expected class_name='%s', got '%s'\n", deadbeef_class_name, cn);
ok(IsEqualGUID(&deadbeef_class_guid, &guid), "expected ClassGUID to be deadbeef-dead-beef-dead-beefdeadbeef\n");
}
DeleteFileA(filename);
}
}