From: "Rémi Bernon" Subject: [PATCH 2/2] setupapi/tests: Add some service installation flags tests. Message-Id: <20220127123005.2097396-2-rbernon@codeweavers.com> Date: Thu, 27 Jan 2022 13:30:05 +0100 In-Reply-To: <20220127123005.2097396-1-rbernon@codeweavers.com> References: <20220127123005.2097396-1-rbernon@codeweavers.com> Signed-off-by: Rémi Bernon --- I believe this should show that patches 224469 and 224464 are the right thing to do if we want the services to be started after their initial registration, when initializing a prefix. Otherwise I don't see what's wrong in the 224469, 224465, 224464 series. dlls/setupapi/tests/install.c | 188 ++++++++++++++++++++++++++++------ 1 file changed, 157 insertions(+), 31 deletions(-) diff --git a/dlls/setupapi/tests/install.c b/dlls/setupapi/tests/install.c index 758a0761037..44b7d09d1e5 100644 --- a/dlls/setupapi/tests/install.c +++ b/dlls/setupapi/tests/install.c @@ -609,13 +609,26 @@ static void test_install_svc_from(void) /* TODO: Test the Flags */ } -static void test_driver_install(void) +static void test_service_install(const char *executable, const char *argument) { - HANDLE handle; + struct + { + const char *add_service_flags; + const char *service_type; + const char *start_type; + DWORD expect_start_error; + } tests[] = + { + {.add_service_flags = "", .service_type = "1", .start_type = "4", .expect_start_error = ERROR_SERVICE_DISABLED}, + {.add_service_flags = "", .service_type = "0x10", .start_type = "2", .expect_start_error = 0}, + {.add_service_flags = "0x800", .service_type = "0x10", .start_type = "2", .expect_start_error = ERROR_SERVICE_ALREADY_RUNNING}, + }; + SC_HANDLE scm_handle, svc_handle; + SERVICE_STATUS status; BOOL ret; char path[MAX_PATH + 9], windir[MAX_PATH], driver[MAX_PATH]; - DWORD attrs; + DWORD i, attrs; /* Minimal stuff needed */ static const char *inf = "[Version]\n" @@ -625,14 +638,15 @@ static void test_driver_install(void) "[DefaultInstall]\n" "CopyFiles=Winetest.DriverFiles\n" "[DefaultInstall.Services]\n" - "AddService=Winetest,,Winetest.Service\n" + "AddService=Winetest,%s,Winetest.Service\n" "[Winetest.Service]\n" - "ServiceBinary=%12%\\winetest.sys\n" - "ServiceType=1\n" - "StartType=4\n" + "ServiceBinary=%%12%%\\winetest.sys %s service\n" + "ServiceType=%s\n" + "StartType=%s\n" "ErrorControl=1\n" "[Winetest.DriverFiles]\n" "winetest.sys"; + char buffer[1024]; /* Bail out if we don't have enough rights */ SetLastError(0xdeadbeef); @@ -649,36 +663,70 @@ static void test_driver_install(void) lstrcpyA(driver, windir); lstrcatA(driver, "\\system32\\drivers\\winetest.sys"); - /* Create a dummy driver file */ - handle = CreateFileA("winetest.sys", GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - CloseHandle(handle); + ret = CopyFileA(executable, "winetest.sys", TRUE); + ok(ret, "CopyFileA failed, error %u\n", GetLastError()); - create_inf_file(inffile, inf); - sprintf(path, "%s\\%s", CURR_DIR, inffile); - run_cmdline("DefaultInstall", 128, path); + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("%u", i); - /* Driver should have been installed */ - attrs = GetFileAttributesA(driver); - ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected driver to exist\n"); + sprintf(buffer, inf, tests[i].add_service_flags, argument, tests[i].service_type, tests[i].start_type); + create_inf_file(inffile, buffer); + sprintf(path, "%s\\%s", CURR_DIR, inffile); + run_cmdline("DefaultInstall", 128, path); - scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL); + /* Driver should have been installed */ + attrs = GetFileAttributesA(driver); + ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected driver to exist\n"); - /* Open the service to see if it's really there */ - svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE); - ok(svc_handle != NULL, "Service was not created\n"); + scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL); - SetLastError(0xdeadbeef); - ret = DeleteService(svc_handle); - ok(ret, "Service could not be deleted : %d\n", GetLastError()); + /* Open the service to see if it's really there */ + svc_handle = OpenServiceA(scm_handle, "Winetest", SERVICE_START|SERVICE_STOP|SERVICE_QUERY_STATUS|DELETE); + ok(svc_handle != NULL, "Service was not created\n"); - CloseServiceHandle(svc_handle); - CloseServiceHandle(scm_handle); + ret = StartServiceA(svc_handle, 0, NULL); + if (!tests[i].expect_start_error) + ok(ret, "StartServiceA failed, error %u\n", GetLastError()); + else + { + ok(!ret, "StartServiceA succeeded\n"); + ok(GetLastError() == tests[i].expect_start_error, "got error %u\n", GetLastError()); + } + + ret = QueryServiceStatus(svc_handle, &status); + ok(ret, "QueryServiceStatus failed: %u\n", GetLastError()); + while (status.dwCurrentState == SERVICE_START_PENDING) + { + Sleep(100); + ret = QueryServiceStatus(svc_handle, &status); + ok(ret, "QueryServiceStatus failed: %u\n", GetLastError()); + } + + ret = ControlService(svc_handle, SERVICE_CONTROL_STOP, &status); + while (status.dwCurrentState == SERVICE_STOP_PENDING) + { + Sleep(100); + ret = QueryServiceStatus(svc_handle, &status); + ok(ret, "QueryServiceStatus failed: %u\n", GetLastError()); + } + ok(status.dwCurrentState == SERVICE_STOPPED, "expected SERVICE_STOPPED, got %d\n", status.dwCurrentState); + + SetLastError(0xdeadbeef); + ret = DeleteService(svc_handle); + ok(ret, "Service could not be deleted : %d\n", GetLastError()); + + CloseServiceHandle(svc_handle); + CloseServiceHandle(scm_handle); + + /* File cleanup */ + DeleteFileA(inffile); + DeleteFileA(driver); + + winetest_pop_context(); + } - /* File cleanup */ - DeleteFileA(inffile); DeleteFileA("winetest.sys"); - DeleteFileA(driver); } static void test_profile_items(void) @@ -2132,11 +2180,89 @@ static void test_register_dlls(void) ok(ret, "Failed to delete test DLL, error %u.\n", GetLastError()); } +static WCHAR service_name[] = L"Wine Test Service"; +static SERVICE_STATUS_HANDLE service_handle; +static HANDLE stop_event; + +static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) +{ + SERVICE_STATUS status; + + status.dwServiceType = SERVICE_WIN32; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + switch(ctrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + trace( "shutting down\n" ); + status.dwCurrentState = SERVICE_STOP_PENDING; + status.dwControlsAccepted = 0; + SetServiceStatus( service_handle, &status ); + SetEvent( stop_event ); + return NO_ERROR; + default: + trace( "got service ctrl %x\n", ctrl ); + status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus( service_handle, &status ); + return NO_ERROR; + } +} + +static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) +{ + SERVICE_STATUS status; + + trace( "starting service\n" ); + + stop_event = CreateEventW( NULL, TRUE, FALSE, NULL ); + + service_handle = RegisterServiceCtrlHandlerExW( L"Wine Test Service", service_handler, NULL ); + if (!service_handle) + return; + + status.dwServiceType = SERVICE_WIN32; + status.dwCurrentState = SERVICE_RUNNING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 10000; + SetServiceStatus( service_handle, &status ); + + WaitForSingleObject( stop_event, INFINITE ); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwControlsAccepted = 0; + SetServiceStatus( service_handle, &status ); + trace( "service stopped\n" ); +} + START_TEST(install) { - char temp_path[MAX_PATH], prev_path[MAX_PATH]; + char temp_path[MAX_PATH], prev_path[MAX_PATH], path[MAX_PATH]; + char **argv; DWORD len; + int argc; + argc = winetest_get_mainargs(&argv); + if (argc > 2 && !strcmp( argv[2], "service" )) + { + static const SERVICE_TABLE_ENTRYW service_table[] = + { + { service_name, ServiceMain }, + { NULL, NULL } + }; + + StartServiceCtrlDispatcherW( service_table ); + return; + } + + GetFullPathNameA(argv[0], ARRAY_SIZE(path), path, NULL); GetCurrentDirectoryA(MAX_PATH, prev_path); GetTempPathA(MAX_PATH, temp_path); SetCurrentDirectoryA(temp_path); @@ -2154,7 +2280,7 @@ START_TEST(install) test_registry(); test_install_from(); test_install_svc_from(); - test_driver_install(); + test_service_install(path, argv[1]); test_dirid(); test_install_files_queue(); test_need_media(); -- 2.34.1