diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c index 1552791a66b..e4ff7d79baa 100644 --- a/dlls/advapi32/tests/service.c +++ b/dlls/advapi32/tests/service.c @@ -2383,7 +2383,6 @@ static void test_servicenotify(SC_HANDLE scm_handle, const char *servicename) /* it's possible to have multiple notifications using different service handles */ dr = pNotifyServiceStatusChangeW(svc2, SERVICE_NOTIFY_STOPPED, &data2.notify); - todo_wine ok(dr == ERROR_SUCCESS, "NotifyServiceStatusChangeW gave wrong result: %u\n", dr); /* stop service and receive notifiction */ @@ -2394,7 +2393,6 @@ static void test_servicenotify(SC_HANDLE scm_handle, const char *servicename) dr2 = SleepEx(100, TRUE); ok(dr == WAIT_IO_COMPLETION || dr2 == WAIT_IO_COMPLETION, "Got wrong SleepEx result: %u\n", dr); ok(data.was_called == TRUE, "APC wasn't called\n"); - todo_wine ok(data2.was_called == TRUE, "APC wasn't called\n"); /* test cancelation: create notify on svc that will block until service diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 623e1fafbd0..8299dbf0e08 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -75,23 +75,24 @@ struct sc_manager_handle /* service control manager handle */ struct scmdatabase *db; }; -struct sc_service_handle /* service handle */ -{ - struct sc_handle hdr; - struct list entry; - struct service_entry *service_entry; -}; - struct sc_notify_handle { struct sc_handle hdr; - struct sc_service_handle *service; HANDLE event; DWORD notify_mask; LONG ref; SC_RPC_NOTIFY_PARAMS_LIST *params_list; }; +struct sc_service_handle /* service handle */ +{ + struct sc_handle hdr; + struct list entry; + BOOL status_notified; + struct service_entry *service_entry; + struct sc_notify_handle *notify; +}; + static void sc_notify_retain(struct sc_notify_handle *notify) { InterlockedIncrement(¬ify->ref); @@ -313,12 +314,10 @@ static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle) struct sc_service_handle *service = (struct sc_service_handle *)hdr; service_lock(service->service_entry); list_remove(&service->entry); - if (service->service_entry->notify && - service->service_entry->notify->service == service) + if (service->notify) { - SetEvent(service->service_entry->notify->event); - sc_notify_release(service->service_entry->notify); - service->service_entry->notify = NULL; + SetEvent(service->notify->event); + sc_notify_release(service->notify); } service_unlock(service->service_entry); release_service(service->service_entry); @@ -432,6 +431,8 @@ static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesi service->hdr.type = SC_HTYPE_SERVICE; service->hdr.access = dwDesiredAccess; + service->notify = NULL; + service->status_notified = FALSE; RtlMapGenericMask(&service->hdr.access, &g_svc_generic); service_lock(entry); @@ -835,7 +836,7 @@ static void fill_status_process(SERVICE_STATUS_PROCESS *status, struct service_e status->dwServiceFlags = 0; } -static void fill_notify(struct sc_notify_handle *notify) +static void fill_notify(struct sc_notify_handle *notify, struct service_entry *service) { SC_RPC_NOTIFY_PARAMS_LIST *list; SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams; @@ -848,7 +849,7 @@ static void fill_notify(struct sc_notify_handle *notify) cparams = (SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *)(list + 1); cparams->dwNotifyMask = notify->notify_mask; - fill_status_process(&cparams->ServiceStatus, notify->service->service_entry); + fill_status_process(&cparams->ServiceStatus, service); cparams->dwNotificationStatus = ERROR_SUCCESS; cparams->dwNotificationTriggered = 1 << (cparams->ServiceStatus.dwCurrentState - SERVICE_STOPPED); cparams->pszServiceNames = NULL; @@ -867,7 +868,7 @@ DWORD __cdecl svcctl_SetServiceStatus( SC_RPC_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus) { - struct sc_service_handle *service; + struct sc_service_handle *service, *service_handle; struct process_entry *process; DWORD err, mask; @@ -895,17 +896,19 @@ DWORD __cdecl svcctl_SetServiceStatus( } mask = 1 << (service->service_entry->status.dwCurrentState - SERVICE_STOPPED); - if (service->service_entry->notify && - (service->service_entry->notify->notify_mask & mask)) + LIST_FOR_EACH_ENTRY(service_handle, &service->service_entry->handles, struct sc_service_handle, entry) { - struct sc_notify_handle *notify = service->service_entry->notify; - fill_notify(notify); - service->service_entry->notify = NULL; - sc_notify_release(notify); - service->service_entry->status_notified = TRUE; + struct sc_notify_handle *notify = service_handle->notify; + if (notify && (notify->notify_mask & mask)) + { + fill_notify(notify, service->service_entry); + sc_notify_release(notify); + service_handle->notify = NULL; + service_handle->status_notified = TRUE; + } + else + service_handle->status_notified = FALSE; } - else - service->service_entry->status_notified = FALSE; service_unlock(service->service_entry); @@ -1736,32 +1739,29 @@ DWORD __cdecl svcctl_NotifyServiceStatusChange( notify->hdr.type = SC_HTYPE_NOTIFY; notify->hdr.access = 0; - notify->service = service; - notify->event = CreateEventW(NULL, TRUE, FALSE, NULL); notify->notify_mask = params.u.params->dwNotifyMask; service_lock(service->service_entry); - if (service->service_entry->notify) + if (service->notify) { service_unlock(service->service_entry); - HeapFree(GetProcessHeap(), 0, notify); + sc_notify_release(notify); return ERROR_ALREADY_REGISTERED; } mask = 1 << (service->service_entry->status.dwCurrentState - SERVICE_STOPPED); - if (!service->service_entry->status_notified && - (notify->notify_mask & mask)) + if (!service->status_notified && (notify->notify_mask & mask)) { - fill_notify(notify); - service->service_entry->status_notified = TRUE; + fill_notify(notify, service->service_entry); + service->status_notified = TRUE; } else { sc_notify_retain(notify); - service->service_entry->notify = notify; + service->notify = notify; } sc_notify_retain(notify); diff --git a/programs/services/services.h b/programs/services/services.h index c78f71c35b5..e1481d951ff 100644 --- a/programs/services/services.h +++ b/programs/services/services.h @@ -45,8 +45,6 @@ struct process_entry HANDLE overlapped_event; }; -struct sc_notify_handle; - struct service_entry { struct list entry; @@ -65,8 +63,6 @@ struct service_entry BOOL force_shutdown; BOOL marked_for_delete; BOOL is_wow64; - BOOL status_notified; - struct sc_notify_handle *notify; struct list handles; };