[WINESYNC] setupapi: Implement custom class installers in SetupDiCallClassInstaller().

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>

wine commit id fce26e60cc2400f3f3da27c221dce95593dd400e by Zebediah Figura <z.figura12@gmail.com>
This commit is contained in:
winesync 2023-09-14 19:55:52 +02:00 committed by Hermès Bélusca-Maïto
parent 2e5c712eb6
commit 3a3965c5a3
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
6 changed files with 257 additions and 5 deletions

View file

@ -6,6 +6,12 @@ add_definitions(
remove_definitions(-D_CRT_NON_CONFORMING_SWPRINTFS)
spec2def(coinst.dll coinst.spec)
add_library(setupapi_coinst MODULE coinst.c ${CMAKE_CURRENT_BINARY_DIR}/coinst.def)
set_target_properties(setupapi_coinst PROPERTIES OUTPUT_NAME "coinst")
set_module_type(setupapi_coinst win32dll)
add_importlibs(setupapi_coinst msvcrt kernel32)
list(APPEND SOURCE
devinst.c
diskspace.c
@ -18,11 +24,21 @@ list(APPEND SOURCE
testlist.c)
add_executable(setupapi_winetest ${SOURCE} setupapi.rc)
set_module_type(setupapi_winetest win32cui)
target_link_libraries(setupapi_winetest uuid)
add_importlibs(setupapi_winetest advapi32 cabinet setupapi user32 shell32 msvcrt kernel32 ntdll)
add_rostests_file(TARGET setupapi_winetest)
# CMake 3.9 and higher requires to specify this dependency manually
# see https://gitlab.kitware.com/cmake/cmake/issues/19933
set_property(SOURCE setupapi.rc PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/coinst.dll)
# setupapi.rc: let rc.exe find the dlls in their subdirectory, i.e. Debug.
if (MSVC_IDE)
target_include_directories(setupapi_winetest PRIVATE $<$<COMPILE_LANGUAGE:RC>:$<TARGET_FILE_DIR:setupapi_coinst>>)
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_compile_options(setupapi_winetest PRIVATE -Wno-format-overflow)
endif()
set_module_type(setupapi_winetest win32cui)
target_link_libraries(setupapi_winetest uuid)
add_importlibs(setupapi_winetest advapi32 cabinet setupapi user32 shell32 msvcrt kernel32 ntdll)
add_rostests_file(TARGET setupapi_winetest)

View file

@ -0,0 +1,51 @@
/*
* Test co-installer and class installer DLL
*
* Copyright 2018 Zebediah Figura
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winreg.h"
#include "setupapi.h"
unsigned int callback_count;
DI_FUNCTION last_message;
DWORD WINAPI class_success(DI_FUNCTION function, HDEVINFO set, SP_DEVINFO_DATA *device)
{
callback_count++;
last_message = function;
return ERROR_SUCCESS;
}
DWORD WINAPI ClassInstall(DI_FUNCTION function, HDEVINFO set, SP_DEVINFO_DATA *device)
{
return class_success(function, set, device);
}
DWORD WINAPI class_default(DI_FUNCTION function, HDEVINFO set, SP_DEVINFO_DATA *device)
{
return ERROR_DI_DO_DEFAULT;
}
DWORD WINAPI class_error(DI_FUNCTION function, HDEVINFO set, SP_DEVINFO_DATA *device)
{
return 0xdeadbeef;
}

View file

@ -0,0 +1,6 @@
@ stdcall class_success(long ptr ptr)
@ stdcall ClassInstall(long ptr ptr)
@ stdcall class_default(long ptr ptr)
@ stdcall class_error(long ptr ptr)
@ extern callback_count
@ extern last_message

View file

@ -60,6 +60,24 @@ static void create_file(const char *name, const char *data)
CloseHandle(file);
}
static void load_resource(const char *name, const char *filename)
{
DWORD written;
HANDLE file;
HRSRC res;
void *ptr;
file = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", filename, GetLastError());
res = FindResourceA(NULL, name, "TESTDLL");
ok( res != 0, "couldn't find resource\n" );
ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
CloseHandle( file );
}
static void test_create_device_list_ex(void)
{
static const WCHAR machine[] = { 'd','u','m','m','y',0 };
@ -2348,9 +2366,155 @@ static BOOL device_is_registered(HDEVINFO set, SP_DEVINFO_DATA *device)
return GetLastError() == ERROR_KEY_DOES_NOT_EXIST;
}
static unsigned int *coinst_callback_count;
static DI_FUNCTION *coinst_last_message;
static void test_class_installer(void)
{
SP_DEVINFO_DATA device = {sizeof(device)};
char regdata[200];
HKEY class_key;
HDEVINFO set;
BOOL ret;
LONG res;
res = RegCreateKeyA(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\Class"
"\\{6a55b5a4-3f65-11db-b704-0011955c2bdb}", &class_key);
ok(!res, "Failed to create class key, error %u.\n", res);
strcpy(regdata, "winetest_coinst.dll,class_success");
res = RegSetValueExA(class_key, "Installer32", 0, REG_SZ, (BYTE *)regdata, strlen(regdata)+1);
ok(!res, "Failed to set registry value, error %u.\n", res);
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());
ret = SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, set, &device);
ok(ret, "Failed to call class installer, error %#x.\n", GetLastError());
ok(*coinst_callback_count == 1, "Got %d callbacks.\n", *coinst_callback_count);
ok(*coinst_last_message == DIF_ALLOW_INSTALL, "Got unexpected message %#x.\n", *coinst_last_message);
*coinst_callback_count = 0;
ret = SetupDiCallClassInstaller(0xdeadbeef, set, &device);
ok(ret, "Failed to call class installer, error %#x.\n", GetLastError());
ok(*coinst_callback_count == 1, "Got %d callbacks.\n", *coinst_callback_count);
ok(*coinst_last_message == 0xdeadbeef, "Got unexpected message %#x.\n", *coinst_last_message);
*coinst_callback_count = 0;
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 not to be registered.\n");
ok(*coinst_callback_count == 1, "Got %d callbacks.\n", *coinst_callback_count);
ok(*coinst_last_message == DIF_REGISTERDEVICE, "Got unexpected message %#x.\n", *coinst_last_message);
*coinst_callback_count = 0;
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");
ok(*coinst_callback_count == 1, "Got %d callbacks.\n", *coinst_callback_count);
ok(*coinst_last_message == DIF_REMOVE, "Got unexpected message %#x.\n", *coinst_last_message);
*coinst_callback_count = 0;
SetupDiDestroyDeviceInfoList(set);
todo_wine ok(*coinst_callback_count == 1, "Got %d callbacks.\n", *coinst_callback_count);
todo_wine ok(*coinst_last_message == DIF_DESTROYPRIVATEDATA, "Got unexpected message %#x.\n", *coinst_last_message);
*coinst_callback_count = 0;
/* Test returning an error. */
strcpy(regdata, "winetest_coinst.dll,class_error");
res = RegSetValueExA(class_key, "Installer32", 0, REG_SZ, (BYTE *)regdata, strlen(regdata)+1);
ok(!res, "Failed to set registry value, error %u.\n", res);
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());
ret = SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, set, &device);
ok(!ret, "Expected failure.\n");
ok(GetLastError() == 0xdeadbeef, "Got unexpected 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, "Expected failure.\n");
ok(GetLastError() == 0xdeadbeef, "Got unexpected error %#x.\n", GetLastError());
ok(!device_is_registered(set, &device), "Expected device not to be registered.\n");
ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device);
ok(!ret, "Expected failure.\n");
ok(GetLastError() == 0xdeadbeef, "Got unexpected error %#x.\n", GetLastError());
ok(!device_is_registered(set, &device), "Expected device not to be registered.\n");
SetupDiDestroyDeviceInfoList(set);
/* Test returning ERROR_DI_DO_DEFAULT. */
strcpy(regdata, "winetest_coinst.dll,class_default");
res = RegSetValueExA(class_key, "Installer32", 0, REG_SZ, (BYTE *)regdata, strlen(regdata)+1);
ok(!res, "Failed to set registry value, error %u.\n", res);
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());
ret = SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, set, &device);
ok(!ret, "Expected failure.\n");
ok(GetLastError() == ERROR_DI_DO_DEFAULT, "Got unexpected 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");
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);
/* The default entry point is ClassInstall(). */
strcpy(regdata, "winetest_coinst.dll");
res = RegSetValueExA(class_key, "Installer32", 0, REG_SZ, (BYTE *)regdata, strlen(regdata)+1);
ok(!res, "Failed to set registry value, error %u.\n", res);
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());
ret = SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, set, &device);
ok(ret, "Failed to call class installer, error %#x.\n", GetLastError());
ok(*coinst_callback_count == 1, "Got %d callbacks.\n", *coinst_callback_count);
ok(*coinst_last_message == DIF_ALLOW_INSTALL, "Got unexpected message %#x.\n", *coinst_last_message);
*coinst_callback_count = 0;
SetupDiDestroyDeviceInfoList(set);
todo_wine ok(*coinst_callback_count == 1, "Got %d callbacks.\n", *coinst_callback_count);
todo_wine ok(*coinst_last_message == DIF_DESTROYPRIVATEDATA, "Got unexpected message %#x.\n", *coinst_last_message);
*coinst_callback_count = 0;
res = RegDeleteKeyA(class_key, "");
ok(!res, "Failed to delete class key, error %u.\n", res);
RegCloseKey(class_key);
}
static void test_call_class_installer(void)
{
SP_DEVINFO_DATA device = {sizeof(device)};
HMODULE coinst;
HDEVINFO set;
BOOL ret;
@ -2385,6 +2549,19 @@ static void test_call_class_installer(void)
ok(!device_is_registered(set, &device), "Expected device not to be registered.\n");
SetupDiDestroyDeviceInfoList(set);
load_resource("coinst.dll", "C:\\windows\\system32\\winetest_coinst.dll");
coinst = LoadLibraryA("winetest_coinst.dll");
coinst_callback_count = (void *)GetProcAddress(coinst, "callback_count");
coinst_last_message = (void *)GetProcAddress(coinst, "last_message");
test_class_installer();
FreeLibrary(coinst);
ret = DeleteFileA("C:\\windows\\system32\\winetest_coinst.dll");
ok(ret, "Failed to delete file, error %u.\n", GetLastError());
}
START_TEST(devinst)

View file

@ -23,3 +23,5 @@
/* @makedep: setupapi.manifest */
1 RT_MANIFEST setupapi.manifest
COINST.DLL TESTDLL "coinst.dll"

View file

@ -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: 43ee138d4747722cfc7d27e59014a47c3003a898
wine: fce26e60cc2400f3f3da27c221dce95593dd400e