From 2e5c712eb6fba447c10c09df4ff2b9311c85880f Mon Sep 17 00:00:00 2001 From: winesync Date: Mon, 25 Sep 2023 17:37:59 +0200 Subject: [PATCH] [WINESYNC] setupapi: Avoid debugstr buffer overflow. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Józef Kucia Signed-off-by: Alexandre Julliard wine commit id 88e28d971bd119f214e29d4ebfa819af9f18f5b7 by Józef Kucia [WINESYNC] setupapi: Handle an empty string for the source file in SetupQueueCopySection(). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47185 Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id 86724af01241b257a4b4b39682031c9c7a3aaeaa by Zebediah Figura [WINESYNC] setupapi/tests: Add some basic tests for SetupDi{Get, Set}DeviceInstallParams(). Signed-off-by: Zebediah Figura Signed-off-by: Aric Stewart Signed-off-by: Alexandre Julliard wine commit id 45d199023f440209c5753e055db233924664df22 by Zebediah Figura [WINESYNC] setupapi/tests: Add tests for SetupDiGetActualSectionToInstall(). Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id 6244f05941f13bf330d68208849d74ae54f116a0 by Zebediah Figura [WINESYNC] setupapi: Return the section name in SetupDiGetActualSectionToInstall() even if it doesn't exist. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id 23320d05b628575ab9ccb44e4482a30268e9a93e by Zebediah Figura [WINESYNC] setupapi/tests: Add some tests for SetupInstallFile(). Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id 2ddc60c8f0276c739b2f512397d32e1b9425e4b0 by Zebediah Figura [WINESYNC] setupapi: Retrieve the default destination path in SetupInstallFile(). Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id d5f6d6419b16ef81ce882f01a318189251320fcb by Zebediah Figura [WINESYNC] setupapi: Clear the Win32 error if no copy was necessary. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id a748f685a502891bc8fa5f4719f80b6feb39ac9c by Zebediah Figura [WINESYNC] setupapi: Don't fail a queued copy if no copy was necessary. This fixes a regression introduced by 3e5c9798a80641e0e39e95e4467c60405b22b062. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47219 Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id 8bc25b24af0276985ad080c8364c11cfff3a1fe5 by Zebediah Figura [WINESYNC] setupapi/tests: Add tests for building and enumerating driver lists. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id 57c3ebec7c803857f39a6cb1033f8a67e3949190 by Zebediah Figura [WINESYNC] setupapi: Add a basic implementation of SetupDiCallClassInstaller(). Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard wine commit id 43ee138d4747722cfc7d27e59014a47c3003a898 by Zebediah Figura --- dll/win32/setupapi/parser.c | 8 +- dll/win32/setupapi/queue.c | 23 +- modules/rostests/winetests/setupapi/devinst.c | 553 +++++++++++++++++- modules/rostests/winetests/setupapi/install.c | 101 ++++ sdk/tools/winesync/setupapi.cfg | 2 +- 5 files changed, 655 insertions(+), 32 deletions(-) diff --git a/dll/win32/setupapi/parser.c b/dll/win32/setupapi/parser.c index fb2ffa5cf19..c7d0614732e 100644 --- a/dll/win32/setupapi/parser.c +++ b/dll/win32/setupapi/parser.c @@ -2012,12 +2012,8 @@ BOOL WINAPI SetupGetBinaryField( PINFCONTEXT context, DWORD index, BYTE *buffer, } buffer[i - index] = value; } - if (TRACE_ON(setupapi)) - { - TRACE( "%p/%p/%d/%d index %d returning:\n", - context->Inf, context->CurrentInf, context->Section, context->Line, index ); - for (i = index; i < line->nb_fields; i++) TRACE( " %02x\n", buffer[i - index] ); - } + TRACE( "%p/%p/%d/%d index %d\n", + context->Inf, context->CurrentInf, context->Section, context->Line, index ); return TRUE; } diff --git a/dll/win32/setupapi/queue.c b/dll/win32/setupapi/queue.c index 203479f4066..bff31982e29 100644 --- a/dll/win32/setupapi/queue.c +++ b/dll/win32/setupapi/queue.c @@ -922,6 +922,7 @@ BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, SP_FILE_COPY_PARAMS_W params; INT flags; BOOL ret; + DWORD len; TRACE("queue %p, src_root %s, hinf %p, hlist %p, section %s, style %#x.\n", queue, debugstr_w(src_root), hinf, hlist, debugstr_w(section), style); @@ -993,7 +994,7 @@ BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, if (!SetupGetStringFieldW( &context, 1, dst_file, ARRAY_SIZE( dst_file ), NULL )) goto end; - if (!SetupGetStringFieldW( &context, 2, src_file, ARRAY_SIZE( src_file ), NULL )) + if (!SetupGetStringFieldW( &context, 2, src_file, ARRAY_SIZE( src_file ), &len ) || len <= sizeof(WCHAR)) strcpyW( src_file, dst_file ); if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */ @@ -1396,6 +1397,8 @@ static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style, #endif TRACE("Did copy... rc was %i\n",rc); } + else + SetLastError(ERROR_SUCCESS); /* after copy processing */ if (style & SP_COPY_DELETESOURCE) @@ -1467,7 +1470,7 @@ BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR sour static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0}; BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE)); - WCHAR *buffer, *p, *inf_source = NULL; + WCHAR *buffer, *p, *inf_source = NULL, dest_path[MAX_PATH]; unsigned int len; TRACE("%p %p %s %s %s %x %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root), @@ -1475,8 +1478,11 @@ BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR sour if (in_use) FIXME("no file in use support\n"); + dest_path[0] = 0; + if (hinf) { + WCHAR *dest_dir; INFCONTEXT ctx; if (!inf_context) @@ -1496,6 +1502,13 @@ BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR sour return FALSE; } source = inf_source; + + if ((dest_dir = get_destination_dir( hinf, NULL ))) + { + strcpyW( dest_path, dest_dir ); + strcatW( dest_path, backslashW ); + heap_free( dest_dir ); + } } else if (!source) { @@ -1522,7 +1535,9 @@ BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR sour while (*source == '\\') source++; strcpyW( p, source ); - ret = do_file_copyW( buffer, dest, style, handler, context ); + strcatW( dest_path, dest ); + + ret = do_file_copyW( buffer, dest_path, style, handler, context ); HeapFree( GetProcessHeap(), 0, inf_source ); HeapFree( GetProcessHeap(), 0, buffer ); @@ -1546,7 +1561,7 @@ static BOOL queue_copy_file( const WCHAR *source, const WCHAR *dest, if (op->dst_path && !create_full_pathW(op->dst_path)) return FALSE; - if (do_file_copyW(source, dest, op->style, handler, context)) + if (do_file_copyW(source, dest, op->style, handler, context) || GetLastError() == ERROR_SUCCESS) return TRUE; /* try to extract it from the cabinet file */ diff --git a/modules/rostests/winetests/setupapi/devinst.c b/modules/rostests/winetests/setupapi/devinst.c index 3bc770ae2d9..d8bf0120929 100644 --- a/modules/rostests/winetests/setupapi/devinst.c +++ b/modules/rostests/winetests/setupapi/devinst.c @@ -45,6 +45,21 @@ static GUID guid2 = {0x6a55b5a5, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c, BOOL (WINAPI *pSetupDiSetDevicePropertyW)(HDEVINFO, PSP_DEVINFO_DATA, const DEVPROPKEY *, DEVPROPTYPE, const BYTE *, DWORD, DWORD); BOOL (WINAPI *pSetupDiGetDevicePropertyW)(HDEVINFO, PSP_DEVINFO_DATA, const DEVPROPKEY *, DEVPROPTYPE *, BYTE *, DWORD, DWORD *, DWORD); +static BOOL wow64; + +static void create_file(const char *name, const char *data) +{ + HANDLE file; + DWORD size; + BOOL ret; + + file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "Failed to create %s, error %u.\n", name, GetLastError()); + ret = WriteFile(file, data, strlen(data), &size, NULL); + ok(ret && size == strlen(data), "Failed to write %s, error %u.\n", name, GetLastError()); + CloseHandle(file); +} + static void test_create_device_list_ex(void) { static const WCHAR machine[] = { 'd','u','m','m','y',0 }; @@ -107,26 +122,6 @@ todo_wine RegCloseKey(root_key); } -static void create_inf_file(LPCSTR filename) -{ - DWORD dwNumberOfBytesWritten; - HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - static const char data[] = - "[Version]\n" - "Signature=\"$Chicago$\"\n" - "Class=Bogus\n" - "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n" - "[ClassInstall32]\n" - "AddReg=BogusClass.NT.AddReg\n" - "[BogusClass.NT.AddReg]\n" - "HKR,,,,\"Wine test devices\"\n"; - - WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL); - CloseHandle(hf); -} - static void get_temp_filename(LPSTR path) { static char curr[MAX_PATH] = { 0 }; @@ -152,10 +147,20 @@ static void test_install_class(void) char tmpfile[MAX_PATH]; BOOL ret; + static const char inf_data[] = + "[Version]\n" + "Signature=\"$Chicago$\"\n" + "Class=Bogus\n" + "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n" + "[ClassInstall32]\n" + "AddReg=BogusClass.NT.AddReg\n" + "[BogusClass.NT.AddReg]\n" + "HKR,,,,\"Wine test devices\"\n"; + tmpfile[0] = '.'; tmpfile[1] = '\\'; get_temp_filename(tmpfile + 2); - create_inf_file(tmpfile + 2); + create_file(tmpfile + 2, inf_data); ret = SetupDiInstallClassA(NULL, NULL, 0, NULL); ok(!ret, "Expected failure.\n"); @@ -1885,10 +1890,510 @@ static void test_device_interface_key(void) SetupDiDestroyDeviceInfoList(set); } +static void test_device_install_params(void) +{ + SP_DEVINFO_DATA device = {sizeof(device)}; + SP_DEVINSTALL_PARAMS_A params; + HDEVINFO set; + BOOL ret; + + set = SetupDiCreateDeviceInfoList(&guid, NULL); + ok(set != INVALID_HANDLE_VALUE, "Failed to create device list, error %#x.\n", GetLastError()); + ret = SetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, &device); + ok(ret, "Failed to create device, error %#x.\n", GetLastError()); + + params.cbSize = sizeof(params) - 1; + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceInstallParamsA(set, &device, ¶ms); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "Got unexpected error %#x.\n", GetLastError()); + + params.cbSize = sizeof(params) + 1; + SetLastError(0xdeadbeef); + ret = SetupDiGetDeviceInstallParamsA(set, &device, ¶ms); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "Got unexpected error %#x.\n", GetLastError()); + + params.cbSize = sizeof(params) - 1; + SetLastError(0xdeadbeef); + ret = SetupDiSetDeviceInstallParamsA(set, &device, ¶ms); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "Got unexpected error %#x.\n", GetLastError()); + + params.cbSize = sizeof(params) + 1; + SetLastError(0xdeadbeef); + ret = SetupDiSetDeviceInstallParamsA(set, &device, ¶ms); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "Got unexpected error %#x.\n", GetLastError()); + + memset(¶ms, 0xcc, sizeof(params)); + params.cbSize = sizeof(params); + ret = SetupDiGetDeviceInstallParamsA(set, &device, ¶ms); + ok(ret, "Failed to get device install params, error %#x.\n", GetLastError()); + ok(!params.Flags, "Got flags %#x.\n", params.Flags); + ok(!params.FlagsEx, "Got extended flags %#x.\n", params.FlagsEx); + ok(!params.hwndParent, "Got parent %p.\n", params.hwndParent); + ok(!params.InstallMsgHandler, "Got callback %p.\n", params.InstallMsgHandler); + ok(!params.InstallMsgHandlerContext, "Got callback context %p.\n", params.InstallMsgHandlerContext); + ok(!params.FileQueue, "Got queue %p.\n", params.FileQueue); + ok(!params.ClassInstallReserved, "Got class installer data %#lx.\n", params.ClassInstallReserved); + ok(!params.DriverPath[0], "Got driver path %s.\n", params.DriverPath); + + params.Flags = DI_INF_IS_SORTED; + params.FlagsEx = DI_FLAGSEX_ALLOWEXCLUDEDDRVS; + strcpy(params.DriverPath, "C:\\windows"); + ret = SetupDiSetDeviceInstallParamsA(set, &device, ¶ms); + ok(ret, "Failed to set device install params, error %#x.\n", GetLastError()); + + memset(¶ms, 0xcc, sizeof(params)); + params.cbSize = sizeof(params); + ret = SetupDiGetDeviceInstallParamsA(set, &device, ¶ms); + ok(ret, "Failed to get device install params, error %#x.\n", GetLastError()); + ok(params.Flags == DI_INF_IS_SORTED, "Got flags %#x.\n", params.Flags); + ok(params.FlagsEx == DI_FLAGSEX_ALLOWEXCLUDEDDRVS, "Got extended flags %#x.\n", params.FlagsEx); + ok(!params.hwndParent, "Got parent %p.\n", params.hwndParent); + ok(!params.InstallMsgHandler, "Got callback %p.\n", params.InstallMsgHandler); + ok(!params.InstallMsgHandlerContext, "Got callback context %p.\n", params.InstallMsgHandlerContext); + ok(!params.FileQueue, "Got queue %p.\n", params.FileQueue); + ok(!params.ClassInstallReserved, "Got class installer data %#lx.\n", params.ClassInstallReserved); + ok(!strcasecmp(params.DriverPath, "C:\\windows"), "Got driver path %s.\n", params.DriverPath); + + SetupDiDestroyDeviceInfoList(set); +} + +#ifdef __i386__ +#define MYEXT "x86" +#define WOWEXT "AMD64" +#define WRONGEXT "ARM" +#elif defined(__x86_64__) +#define MYEXT "AMD64" +#define WOWEXT "x86" +#define WRONGEXT "ARM64" +#elif defined(__arm__) +#define MYEXT "ARM" +#define WOWEXT "ARM64" +#define WRONGEXT "x86" +#elif defined(__aarch64__) +#define MYEXT "ARM64" +#define WOWEXT "ARM" +#define WRONGEXT "AMD64" +#else +#define MYEXT +#define WOWEXT +#define WRONGEXT +#endif + +static void test_get_actual_section(void) +{ + static const char inf_data[] = "[Version]\n" + "Signature=\"$Chicago$\"\n" + "[section1]\n" + "[section2]\n" + "[section2.nt]\n" + "[section3]\n" + "[section3.nt" MYEXT "]\n" + "[section4]\n" + "[section4.nt]\n" + "[section4.nt" MYEXT "]\n" + "[section5.nt]\n" + "[section6.nt" MYEXT "]\n" + "[section7]\n" + "[section7.nt" WRONGEXT "]\n" + "[section8.nt" WRONGEXT "]\n" + "[section9.nt" MYEXT "]\n" + "[section9.nt" WOWEXT "]\n" + "[section10.nt" WOWEXT "]\n"; + + char inf_path[MAX_PATH], section[LINE_LEN], *extptr; + DWORD size; + HINF hinf; + BOOL ret; + + GetTempPathA(sizeof(inf_path), inf_path); + strcat(inf_path, "setupapi_test.inf"); + create_file(inf_path, inf_data); + + hinf = SetupOpenInfFileA(inf_path, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "Failed to open INF file, error %#x.\n", GetLastError()); + + ret = SetupDiGetActualSectionToInstallA(hinf, "section1", section, ARRAY_SIZE(section), NULL, NULL); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcmp(section, "section1"), "Got unexpected section %s.\n", section); + + size = 0xdeadbeef; + ret = SetupDiGetActualSectionToInstallA(hinf, "section1", NULL, 5, &size, NULL); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(size == 9, "Got size %u.\n", size); + + SetLastError(0xdeadbeef); + size = 0xdeadbeef; + ret = SetupDiGetActualSectionToInstallA(hinf, "section1", section, 5, &size, NULL); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#x.\n", GetLastError()); + ok(size == 9, "Got size %u.\n", size); + + SetLastError(0xdeadbeef); + ret = SetupDiGetActualSectionToInstallA(hinf, "section1", section, ARRAY_SIZE(section), &size, NULL); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section1"), "Got unexpected section %s.\n", section); + ok(size == 9, "Got size %u.\n", size); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section1", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section1"), "Got unexpected section %s.\n", section); + ok(!extptr || !*extptr /* Windows 10 1809 */, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section2", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section2.NT"), "Got unexpected section %s.\n", section); + ok(extptr == section + 8, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section3", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section3.NT" MYEXT), "Got unexpected section %s.\n", section); + ok(extptr == section + 8, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section4", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section4.NT" MYEXT), "Got unexpected section %s.\n", section); + ok(extptr == section + 8, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section5", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section5.NT"), "Got unexpected section %s.\n", section); + ok(extptr == section + 8, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section6", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section6.NT" MYEXT), "Got unexpected section %s.\n", section); + ok(extptr == section + 8, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section7", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section7"), "Got unexpected section %s.\n", section); + ok(!extptr || !*extptr /* Windows 10 1809 */, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section8", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section8"), "Got unexpected section %s.\n", section); + ok(!extptr || !*extptr /* Windows 10 1809 */, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "nonexistent", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "nonexistent"), "Got unexpected section %s.\n", section); + ok(!extptr || !*extptr /* Windows 10 1809 */, "Got extension %s.\n", extptr); + + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section9", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section9.NT" MYEXT), "Got unexpected section %s.\n", section); + ok(extptr == section + 8, "Got extension %s.\n", extptr); + + if (0) + { + /* For some reason, this call hangs on Windows 10 1809. */ + extptr = section; + ret = SetupDiGetActualSectionToInstallA(hinf, "section10", section, ARRAY_SIZE(section), NULL, &extptr); + ok(ret, "Failed to get section, error %#x.\n", GetLastError()); + ok(!strcasecmp(section, "section10"), "Got unexpected section %s.\n", section); + ok(!extptr, "Got extension %s.\n", extptr); + } + + SetupCloseInfFile(hinf); + ret = DeleteFileA(inf_path); + ok(ret, "Failed to delete %s, error %u.\n", inf_path, GetLastError()); +} + +static void test_driver_list(void) +{ + char inf_dir[MAX_PATH], inf_path[MAX_PATH], inf_path2[MAX_PATH]; + static const char hardware_id[] = "bogus_hardware_id\0"; + static const char compat_id[] = "bogus_compat_id\0"; + SP_DEVINSTALL_PARAMS_A params = {sizeof(params)}; + SP_DRVINFO_DATA_A driver = {sizeof(driver)}; + SP_DEVINFO_DATA device = {sizeof(device)}; + HDEVINFO set; + BOOL ret; + + static const char inf_data[] = "[Version]\n" + "Signature=\"$Chicago$\"\n" + "ClassGuid={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n" + "[Manufacturer]\n" + "mfg1=mfg1_key,NT" MYEXT "\n" + "mfg2=mfg2_key,NT" MYEXT "\n" + "mfg1_wow=mfg1_key,NT" WOWEXT "\n" + "mfg2_wow=mfg2_key,NT" WOWEXT "\n" + "mfg3=mfg3_key,NT" WRONGEXT "\n" + "[mfg1_key.nt" MYEXT "]\n" + "desc1=,bogus_hardware_id\n" + "desc2=,bogus_hardware_id\n" + "desc3=,wrong_hardware_id\n" + "desc4=,wrong_hardware_id,bogus_compat_id\n" + "[mfg1_key.nt" WOWEXT "]\n" + "desc1=,bogus_hardware_id\n" + "desc2=,bogus_hardware_id\n" + "desc3=,wrong_hardware_id\n" + "desc4=,wrong_hardware_id,bogus_compat_id\n" + "[mfg2_key.nt" MYEXT "]\n" + "desc5=,bogus_hardware_id\n" + "[mfg2_key.nt" WOWEXT "]\n" + "desc5=,bogus_hardware_id\n" + "[mfg3_key.nt" WRONGEXT "]\n" + "desc6=,bogus_hardware_id\n"; + + static const char inf_data_file1[] = "[Version]\n" + "Signature=\"$Chicago$\"\n" + "ClassGuid={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n" + "[Manufacturer]\n" + "mfg1=mfg1_key,NT" MYEXT ",NT" WOWEXT "\n" + "[mfg1_key.nt" MYEXT "]\n" + "desc1=,bogus_hardware_id\n" + "[mfg1_key.nt" WOWEXT "]\n" + "desc1=,bogus_hardware_id\n"; + + static const char inf_data_file2[] = "[Version]\n" + "Signature=\"$Chicago$\"\n" + "ClassGuid={6a55b5a5-3f65-11db-b704-0011955c2bdb}\n" + "[Manufacturer]\n" + "mfg1=mfg1_key,NT" MYEXT ",NT" WOWEXT "\n" + "[mfg1_key.nt" MYEXT "]\n" + "desc2=,bogus_hardware_id\n" + "[mfg1_key.nt" WOWEXT "]\n" + "desc2=,bogus_hardware_id\n"; + + GetTempPathA(sizeof(inf_path), inf_path); + strcat(inf_path, "setupapi_test.inf"); + create_file(inf_path, inf_data); + set = SetupDiCreateDeviceInfoList(NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "Failed to create device list, error %#x.\n", GetLastError()); + ret = SetupDiCreateDeviceInfoA(set, "Root\\BOGUS\\0000", &GUID_NULL, NULL, NULL, 0, &device); + ok(ret, "Failed to create device, error %#x.\n", GetLastError()); + + ret = SetupDiSetDeviceRegistryPropertyA(set, &device, SPDRP_HARDWAREID, + (const BYTE *)hardware_id, sizeof(hardware_id)); + ok(ret, "Failed to set hardware ID, error %#x.\n", GetLastError()); + + ret = SetupDiSetDeviceRegistryPropertyA(set, &device, SPDRP_COMPATIBLEIDS, + (const BYTE *)compat_id, sizeof(compat_id)); + ok(ret, "Failed to set hardware ID, error %#x.\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 0, &driver); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_NO_MORE_ITEMS, "Got unexpected error %#x.\n", GetLastError()); + + ret = SetupDiGetDeviceInstallParamsA(set, &device, ¶ms); + ok(ret, "Failed to get device install params, error %#x.\n", GetLastError()); + strcpy(params.DriverPath, inf_path); + params.Flags = DI_ENUMSINGLEINF; + ret = SetupDiSetDeviceInstallParamsA(set, &device, ¶ms); + ok(ret, "Failed to set device install params, error %#x.\n", GetLastError()); + + ret = SetupDiBuildDriverInfoList(set, &device, SPDIT_COMPATDRIVER); + ok(ret, "Failed to build driver list, error %#x.\n", GetLastError()); + + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 0, &driver); + ok(ret, "Failed to enumerate drivers, error %#x.\n", GetLastError()); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#x.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc1"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, wow64 ? "mfg1_wow" : "mfg1"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 1, &driver); + ok(ret, "Failed to enumerate drivers, error %#x.\n", GetLastError()); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#x.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc2"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, wow64 ? "mfg1_wow" : "mfg1"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 2, &driver); + ok(ret, "Failed to enumerate drivers, error %#x.\n", GetLastError()); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#x.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc4"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, wow64 ? "mfg1_wow" : "mfg1"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 3, &driver); + ok(ret, "Failed to enumerate drivers, error %#x.\n", GetLastError()); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#x.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc5"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, wow64 ? "mfg2_wow" : "mfg2"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + SetLastError(0xdeadbeef); + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 4, &driver); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_NO_MORE_ITEMS, "Got unexpected error %#x.\n", GetLastError()); + + SetupDiDestroyDeviceInfoList(set); + ret = DeleteFileA(inf_path); + ok(ret, "Failed to delete %s, error %u.\n", inf_path, GetLastError()); + + /* Test building from a path. */ + + GetTempPathA(sizeof(inf_dir), inf_dir); + strcat(inf_dir, "setupapi_test"); + ret = CreateDirectoryA(inf_dir, NULL); + ok(ret, "Failed to create directory, error %u.\n", GetLastError()); + sprintf(inf_path, "%s/test1.inf", inf_dir); + create_file(inf_path, inf_data_file1); + sprintf(inf_path2, "%s/test2.inf", inf_dir); + create_file(inf_path2, inf_data_file2); + + set = SetupDiCreateDeviceInfoList(NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "Failed to create device list, error %#x.\n", GetLastError()); + ret = SetupDiCreateDeviceInfoA(set, "Root\\BOGUS\\0000", &GUID_NULL, NULL, NULL, 0, &device); + ok(ret, "Failed to create device, error %#x.\n", GetLastError()); + + ret = SetupDiSetDeviceRegistryPropertyA(set, &device, SPDRP_HARDWAREID, + (const BYTE *)hardware_id, sizeof(hardware_id)); + ok(ret, "Failed to set hardware ID, error %#x.\n", GetLastError()); + + ret = SetupDiGetDeviceInstallParamsA(set, &device, ¶ms); + ok(ret, "Failed to get device install params, error %#x.\n", GetLastError()); + strcpy(params.DriverPath, inf_dir); + ret = SetupDiSetDeviceInstallParamsA(set, &device, ¶ms); + ok(ret, "Failed to set device install params, error %#x.\n", GetLastError()); + + ret = SetupDiBuildDriverInfoList(set, &device, SPDIT_COMPATDRIVER); + ok(ret, "Failed to build driver list, error %#x.\n", GetLastError()); + + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 0, &driver); + ok(ret, "Failed to enumerate drivers, error %#x.\n", GetLastError()); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#x.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc1"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, "mfg1"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 1, &driver); + ok(ret, "Failed to enumerate drivers, error %#x.\n", GetLastError()); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#x.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc2"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, "mfg1"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + SetLastError(0xdeadbeef); + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 2, &driver); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_NO_MORE_ITEMS, "Got unexpected error %#x.\n", GetLastError()); + + SetupDiDestroyDeviceInfoList(set); + ret = DeleteFileA(inf_path); + ok(ret, "Failed to delete %s, error %u.\n", inf_path, GetLastError()); + ret = DeleteFileA(inf_path2); + ok(ret, "Failed to delete %s, error %u.\n", inf_path2, GetLastError()); + ret = RemoveDirectoryA(inf_dir); + ok(ret, "Failed to delete %s, error %u.\n", inf_dir, GetLastError()); + + /* Test the default path. */ + + create_file("C:/windows/inf/wine_test1.inf", inf_data_file1); + create_file("C:/windows/inf/wine_test2.inf", inf_data_file2); + + set = SetupDiCreateDeviceInfoList(NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "Failed to create device list, error %#x.\n", GetLastError()); + ret = SetupDiCreateDeviceInfoA(set, "Root\\BOGUS\\0000", &GUID_NULL, NULL, NULL, 0, &device); + ok(ret, "Failed to create device, error %#x.\n", GetLastError()); + + ret = SetupDiSetDeviceRegistryPropertyA(set, &device, SPDRP_HARDWAREID, + (const BYTE *)hardware_id, sizeof(hardware_id)); + ok(ret, "Failed to set hardware ID, error %#x.\n", GetLastError()); + + ret = SetupDiBuildDriverInfoList(set, &device, SPDIT_COMPATDRIVER); + ok(ret, "Failed to build driver list, error %#x.\n", GetLastError()); + + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 0, &driver); + ok(ret, "Failed to enumerate drivers, error %#x.\n", GetLastError()); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#x.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc1"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, "mfg1"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 1, &driver); + ok(ret, "Failed to enumerate drivers, error %#x.\n", GetLastError()); + ok(driver.DriverType == SPDIT_COMPATDRIVER, "Got wrong type %#x.\n", driver.DriverType); + ok(!strcmp(driver.Description, "desc2"), "Got wrong description '%s'.\n", driver.Description); + ok(!strcmp(driver.MfgName, "mfg1"), "Got wrong manufacturer '%s'.\n", driver.MfgName); + ok(!strcmp(driver.ProviderName, ""), "Got wrong provider '%s'.\n", driver.ProviderName); + + SetLastError(0xdeadbeef); + ret = SetupDiEnumDriverInfoA(set, &device, SPDIT_COMPATDRIVER, 2, &driver); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_NO_MORE_ITEMS, "Got unexpected error %#x.\n", GetLastError()); + + SetupDiDestroyDeviceInfoList(set); + ret = DeleteFileA("C:/windows/inf/wine_test1.inf"); + ok(ret, "Failed to delete %s, error %u.\n", inf_path, GetLastError()); + ret = DeleteFileA("C:/windows/inf/wine_test2.inf"); + ok(ret, "Failed to delete %s, error %u.\n", inf_path2, GetLastError()); + /* Windows "precompiles" INF files in this dir; try to avoid leaving them behind. */ + DeleteFileA("C:/windows/inf/wine_test1.pnf"); + DeleteFileA("C:/windows/inf/wine_test2.pnf"); +} + +static BOOL device_is_registered(HDEVINFO set, SP_DEVINFO_DATA *device) +{ + HKEY key = SetupDiOpenDevRegKey(set, device, DICS_FLAG_GLOBAL, 0, DIREG_DRV, 0); + ok(key == INVALID_HANDLE_VALUE, "Expected failure.\n"); + RegCloseKey(key); + return GetLastError() == ERROR_KEY_DOES_NOT_EXIST; +} + +static void test_call_class_installer(void) +{ + SP_DEVINFO_DATA device = {sizeof(device)}; + HDEVINFO set; + BOOL ret; + + if (wow64) + { + skip("SetupDiCallClassInstaller() does not work on WoW64.\n"); + return; + } + + set = SetupDiCreateDeviceInfoList(&guid, NULL); + ok(set != INVALID_HANDLE_VALUE, "Failed to create device list, error %#x.\n", GetLastError()); + ret = SetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, &device); + ok(ret, "Failed to create device, error %#x.\n", GetLastError()); + + ok(!device_is_registered(set, &device), "Expected device not to be registered.\n"); + ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device); + ok(ret, "Failed to call class installer, error %#x.\n", GetLastError()); + ok(device_is_registered(set, &device), "Expected device to be registered.\n"); + + /* This is probably not failure per se, but rather an indication that no + * class installer was called and no default handler exists. */ + ret = SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, set, &device); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_DI_DO_DEFAULT, "Got unexpected error %#x.\n", GetLastError()); + + ret = SetupDiCallClassInstaller(0xdeadbeef, set, &device); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_DI_DO_DEFAULT, "Got unexpected error %#x.\n", GetLastError()); + + ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); + ok(ret, "Failed to call class installer, error %#x.\n", GetLastError()); + ok(!device_is_registered(set, &device), "Expected device not to be registered.\n"); + + SetupDiDestroyDeviceInfoList(set); +} + START_TEST(devinst) { + static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); HKEY hkey; + test_get_actual_section(); + if ((hkey = SetupDiOpenClassRegKey(NULL, KEY_ALL_ACCESS)) == INVALID_HANDLE_VALUE) { skip("needs admin rights\n"); @@ -1896,6 +2401,9 @@ START_TEST(devinst) } RegCloseKey(hkey); + pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); + if (pIsWow64Process) pIsWow64Process(GetCurrentProcess(), &wow64); + test_create_device_list_ex(); test_open_class_key(); test_install_class(); @@ -1913,4 +2421,7 @@ START_TEST(devinst) test_get_inf_class(); test_devnode(); test_device_interface_key(); + test_device_install_params(); + test_driver_list(); + test_call_class_installer(); } diff --git a/modules/rostests/winetests/setupapi/install.c b/modules/rostests/winetests/setupapi/install.c index 85f532a78b8..a0a45969a42 100644 --- a/modules/rostests/winetests/setupapi/install.c +++ b/modules/rostests/winetests/setupapi/install.c @@ -1317,6 +1317,96 @@ static void run_queue_(unsigned int line, HSPFILEQ queue, PSP_FILE_CALLBACK_A cb ok_(__FILE__,line)(ret, "Failed to close queue, error %#x.\n", GetLastError()); } +static void test_install_file(void) +{ + static const char inf_data[] = "[Version]\n" + "Signature=\"$Chicago$\"\n" + "[section1]\n" + "one.txt\n" + "two.txt\n" + "three.txt\n" + "[SourceDisksNames]\n" + "1=heis\n" + "2=duo,,,alpha\n" + "[SourceDisksFiles]\n" + "one.txt=1\n" + "two.txt=1,beta\n" + "three.txt=2\n" + "[DestinationDirs]\n" + "DefaultDestDir=40000,dst\n"; + + char path[MAX_PATH]; + INFCONTEXT infctx; + HINF hinf; + BOOL ret; + + create_inf_file(inffile, inf_data); + + sprintf(path, "%s\\%s", CURR_DIR, inffile); + hinf = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "Failed to open INF file, error %#x.\n", GetLastError()); + + ret = CreateDirectoryA("src", NULL); + ok(ret, "Failed to create test directory, error %u.\n", GetLastError()); + ret = CreateDirectoryA("src/alpha", NULL); + ok(ret, "Failed to create test directory, error %u.\n", GetLastError()); + ret = CreateDirectoryA("src/beta", NULL); + ok(ret, "Failed to create test directory, error %u.\n", GetLastError()); + ret = CreateDirectoryA("dst", NULL); + ok(ret, "Failed to create test directory, error %u.\n", GetLastError()); + create_file("src/one.txt"); + create_file("src/beta/two.txt"); + create_file("src/alpha/three.txt"); + + ret = SetupFindFirstLineA(hinf, "section1", "one.txt", &infctx); + ok(ret, "Failed to find line.\n"); + SetLastError(0xdeadbeef); + ret = SetupInstallFileA(hinf, &infctx, "one.txt", "src", "one.txt", 0, NULL, NULL); + ok(ret, "Expected success.\n"); + ok(GetLastError() == ERROR_SUCCESS, "Got unexpected error %#x.\n", GetLastError()); + ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + + SetLastError(0xdeadbeef); + ret = SetupInstallFileA(hinf, &infctx, "one.txt", "src", "one.txt", SP_COPY_REPLACEONLY, NULL, NULL); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_SUCCESS, "Got unexpected error %#x.\n", GetLastError()); + ok(!file_exists("dst/one.txt"), "Destination file should not exist.\n"); + + ret = SetupFindFirstLineA(hinf, "section1", "two.txt", &infctx); + ok(ret, "Failed to find line.\n"); + SetLastError(0xdeadbeef); + ret = SetupInstallFileA(hinf, &infctx, "two.txt", "src", "two.txt", 0, NULL, NULL); + todo_wine ok(ret, "Expected success.\n"); + todo_wine ok(GetLastError() == ERROR_SUCCESS, "Got unexpected error %#x.\n", GetLastError()); + todo_wine ok(delete_file("dst/two.txt"), "Destination file should exist.\n"); + + ret = SetupFindFirstLineA(hinf, "section1", "three.txt", &infctx); + ok(ret, "Failed to find line.\n"); + SetLastError(0xdeadbeef); + ret = SetupInstallFileA(hinf, &infctx, "three.txt", "src", "three.txt", 0, NULL, NULL); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Got unexpected error %#x.\n", GetLastError()); + ok(!file_exists("dst/three.txt"), "Destination file should not exist.\n"); + + ret = SetupFindFirstLineA(hinf, "section1", "three.txt", &infctx); + ok(ret, "Failed to find line.\n"); + SetLastError(0xdeadbeef); + ret = SetupInstallFileA(hinf, &infctx, "three.txt", "src/alpha", "three.txt", 0, NULL, NULL); + ok(ret, "Expected success.\n"); + ok(GetLastError() == ERROR_SUCCESS, "Got unexpected error %#x.\n", GetLastError()); + ok(delete_file("dst/three.txt"), "Destination file should exist.\n"); + + SetupCloseInfFile(hinf); + delete_file("src/one.txt"); + delete_file("src/beta/two.txt"); + delete_file("src/beta/"); + delete_file("src/alpha/three.txt"); + delete_file("src/alpha/"); + delete_file("src/"); + delete_file("dst/"); + ok(delete_file(inffile), "Failed to delete INF file.\n"); +} + static void test_need_media(void) { static const char inf_data[] = "[Version]\n" @@ -1378,6 +1468,16 @@ static void test_need_media(void) ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); ok(delete_file("dst/one.txt"), "Destination file should exist.\n"); + got_need_media = 0; + queue = SetupOpenFileQueue(); + ok(queue != INVALID_HANDLE_VALUE, "Failed to open queue, error %#x.\n", GetLastError()); + ret = SetupQueueCopyA(queue, "src", NULL, "one.txt", "File One", NULL, + "dst", NULL, SP_COPY_WARNIFSKIP | SP_COPY_REPLACEONLY); + ok(ret, "Failed to queue copy, error %#x.\n", GetLastError()); + run_queue(queue, need_media_cb); + ok(got_need_media == 1, "Got %u callbacks.\n", got_need_media); + ok(!file_exists("dst/one.txt"), "Destination file should exist.\n"); + /* Test with a subdirectory. */ got_need_media = 0; @@ -1857,6 +1957,7 @@ START_TEST(install) test_install_files_queue(); test_need_media(); test_close_queue(); + test_install_file(); UnhookWindowsHookEx(hhook); diff --git a/sdk/tools/winesync/setupapi.cfg b/sdk/tools/winesync/setupapi.cfg index 558bd916dd4..eabc8d35caf 100644 --- a/sdk/tools/winesync/setupapi.cfg +++ b/sdk/tools/winesync/setupapi.cfg @@ -10,4 +10,4 @@ files: dlls/setupapi/setupcab.c: dll/win32/setupapi/setupcab.c dlls/setupapi/stringtable.c: dll/win32/setupapi/stringtable_wine.c tags: - wine: wine-4.8 + wine: 43ee138d4747722cfc7d27e59014a47c3003a898