28 _In_ SC_HANDLE hService,
29 _In_ DWORD dwNotifyMask,
30 _In_ PSERVICE_NOTIFYW pNotifyBuffer
33 typedef struct _PHP_SERVICE_NAME_ENTRY
37 ENUM_SERVICE_STATUS_PROCESS *ServiceEntry;
48 typedef struct _PHP_SERVICE_NOTIFY_CONTEXT
51 SC_HANDLE ServiceHandle;
53 BOOLEAN IsServiceManager;
55 SERVICE_NOTIFY Buffer;
97 static BOOLEAN PhpNonPollInitialized =
FALSE;
98 static BOOLEAN PhpNonPollActive =
FALSE;
99 static HANDLE PhpNonPollThreadHandle;
100 static ULONG PhpNonPollGate;
102 static HANDLE PhpNonPollEventHandle;
104 static LIST_ENTRY PhpNonPollServiceListHead;
105 static LIST_ENTRY PhpNonPollServicePendingListHead;
123 _In_opt_ LPENUM_SERVICE_STATUS_PROCESS Information
137 serviceItem->
Key = serviceItem->
Name->
sr;
139 serviceItem->
Type = Information->ServiceStatusProcess.dwServiceType;
140 serviceItem->
State = Information->ServiceStatusProcess.dwCurrentState;
141 serviceItem->
ControlsAccepted = Information->ServiceStatusProcess.dwControlsAccepted;
142 serviceItem->
Flags = Information->ServiceStatusProcess.dwServiceFlags;
143 serviceItem->
ProcessId = (HANDLE)Information->ServiceStatusProcess.dwProcessId;
195 lookupServiceItem.
Key = *Name;
199 &lookupServiceItemPtr
234 ServiceItem->NeedsConfigUpdate =
TRUE;
251 Data->OldService.State == SERVICE_STOPPED ||
252 Data->OldService.State == SERVICE_START_PENDING
254 Data->Service->State == SERVICE_RUNNING
262 Data->OldService.State == SERVICE_PAUSED ||
263 Data->OldService.State == SERVICE_CONTINUE_PENDING
265 Data->Service->State == SERVICE_RUNNING
273 Data->OldService.State == SERVICE_RUNNING ||
274 Data->OldService.State == SERVICE_PAUSE_PENDING
276 Data->Service->State == SERVICE_PAUSED
284 Data->OldService.State == SERVICE_RUNNING ||
285 Data->OldService.State == SERVICE_STOP_PENDING
287 Data->Service->State == SERVICE_STOPPED
312 (*serviceItem)->PendingProcess &&
313 (*serviceItem)->ProcessId == ProcessItem->ProcessId
328 if (!ProcessItem->ServiceList)
339 ServiceItem->PendingProcess =
FALSE;
340 ProcessItem->JustProcessed = 1;
348 HANDLE pointerHandle;
350 if (!ProcessItem->ServiceList)
363 ProcessItem->JustProcessed = 1;
367 _In_ SC_HANDLE ScManagerHandle,
371 SC_HANDLE serviceHandle;
373 serviceHandle = OpenService(ScManagerHandle, ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG);
377 LPQUERY_SERVICE_CONFIG config;
378 SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;
380 PSERVICE_TRIGGER_INFO triggerInfo;
386 ServiceItem->StartType = config->dwStartType;
387 ServiceItem->ErrorControl = config->dwErrorControl;
392 if (QueryServiceConfig2(
394 SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
395 (BYTE *)&delayedAutoStartInfo,
396 sizeof(SERVICE_DELAYED_AUTO_START_INFO),
400 ServiceItem->DelayedStart = delayedAutoStartInfo.fDelayedAutostart;
404 ServiceItem->DelayedStart =
FALSE;
409 ServiceItem->HasTriggers = triggerInfo->cTriggers != 0;
414 ServiceItem->HasTriggers =
FALSE;
417 CloseServiceHandle(serviceHandle);
421 static BOOLEAN PhpCompareServiceNameEntry(
429 static ULONG PhpHashServiceNameEntry(
440 static SC_HANDLE scManagerHandle = NULL;
441 static ULONG runCount = 0;
445 static ULONG nameEntriesCount;
446 static ULONG nameEntriesAllocated = 0;
448 LPENUM_SERVICE_STATUS_PROCESS services;
449 ULONG numberOfServices;
456 if (!PhpNonPollInitialized)
463 PhpNonPollInitialized =
TRUE;
466 if (PhpNonPollActive)
468 if (InterlockedExchange(&PhpNonPollGate, 0) == 0)
476 if (!scManagerHandle)
478 scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
480 if (!scManagerHandle)
484 services =
PhEnumServices(scManagerHandle, 0, 0, &numberOfServices);
495 nameEntriesCount = 0;
497 if (nameEntriesAllocated < numberOfServices)
499 nameEntriesAllocated = numberOfServices + 32;
501 if (nameEntries)
PhFree(nameEntries);
507 for (i = 0; i < numberOfServices; i++)
511 entry = &nameEntries[nameEntriesCount++];
513 entry->ServiceEntry = &services[i];
518 PhpHashServiceNameEntry(entry)
532 BOOLEAN found =
FALSE;
537 lookupNameEntry.Name = (*serviceItem)->Name->sr;
541 PhpHashServiceNameEntry(&lookupNameEntry)
544 for (; hashEntry; hashEntry = hashEntry->
Next)
550 if (PhpCompareServiceNameEntry(&lookupNameEntry, nameEntry))
560 if ((*serviceItem)->ProcessId)
576 if (!servicesToRemove)
583 if (servicesToRemove)
587 for (i = 0; i < servicesToRemove->
Count; i++)
600 for (hashEntry = nameHashSet[i]; hashEntry; hashEntry = hashEntry->
Next)
604 ENUM_SERVICE_STATUS_PROCESS *serviceEntry;
607 serviceEntry = nameEntry->ServiceEntry;
621 serviceItem->
State == SERVICE_RUNNING ||
622 serviceItem->
State == SERVICE_PAUSED
654 serviceItem->
Type != serviceEntry->ServiceStatusProcess.dwServiceType ||
655 serviceItem->
State != serviceEntry->ServiceStatusProcess.dwCurrentState ||
656 serviceItem->
ControlsAccepted != serviceEntry->ServiceStatusProcess.dwControlsAccepted ||
657 serviceItem->
ProcessId != (HANDLE)serviceEntry->ServiceStatusProcess.dwProcessId ||
666 serviceModifiedData.
Service = serviceItem;
674 serviceItem->
Type = serviceEntry->ServiceStatusProcess.dwServiceType;
675 serviceItem->
State = serviceEntry->ServiceStatusProcess.dwCurrentState;
676 serviceItem->
ControlsAccepted = serviceEntry->ServiceStatusProcess.dwControlsAccepted;
677 serviceItem->
ProcessId = (HANDLE)serviceEntry->ServiceStatusProcess.dwProcessId;
718 serviceItem->
State == SERVICE_RUNNING &&
767 _In_ PVOID pParameter
770 PSERVICE_NOTIFYW notifyBuffer = pParameter;
773 if (notifyBuffer->dwNotificationStatus == ERROR_SUCCESS)
775 if ((notifyBuffer->dwNotificationTriggered & (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED)) &&
776 notifyBuffer->pszServiceNames)
781 name = notifyBuffer->pszServiceNames;
799 InsertTailList(&PhpNonPollServicePendingListHead, &newNotifyContext->ListEntry);
802 name += nameLength + 1;
805 LocalFree(notifyBuffer->pszServiceNames);
810 InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry);
812 else if (notifyBuffer->dwNotificationStatus == ERROR_SERVICE_MARKED_FOR_DELETE)
814 if (!notifyContext->IsServiceManager)
818 InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry);
825 InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry);
829 NtSetEvent(PhpNonPollEventHandle, NULL);
836 if (NotifyContext->Buffer.pszServiceNames)
837 LocalFree(NotifyContext->Buffer.pszServiceNames);
839 CloseServiceHandle(NotifyContext->ServiceHandle);
849 SC_HANDLE scManagerHandle;
850 LPENUM_SERVICE_STATUS_PROCESS services;
851 ULONG numberOfServices;
853 PLIST_ENTRY listEntry;
858 PhpNonPollActive =
FALSE;
860 return STATUS_UNSUCCESSFUL;
865 scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
867 if (!scManagerHandle)
873 if (!(services =
PhEnumServices(scManagerHandle, 0, 0, &numberOfServices)))
876 for (i = 0; i < numberOfServices; i++)
878 SC_HANDLE serviceHandle;
880 if (serviceHandle = OpenService(scManagerHandle, services[i].lpServiceName, SERVICE_QUERY_STATUS))
884 notifyContext->ServiceHandle = serviceHandle;
886 InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry);
894 notifyContext->ServiceHandle = scManagerHandle;
895 notifyContext->IsServiceManager =
TRUE;
897 InsertTailList(&PhpNonPollServicePendingListHead, ¬ifyContext->ListEntry);
901 BOOLEAN lagging =
FALSE;
903 listEntry = PhpNonPollServicePendingListHead.Flink;
905 while (listEntry != &PhpNonPollServicePendingListHead)
908 listEntry = listEntry->Flink;
910 switch (notifyContext->State)
915 notifyContext->ServiceHandle =
916 OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS);
918 if (!notifyContext->ServiceHandle)
934 memset(¬ifyContext->Buffer, 0,
sizeof(SERVICE_NOTIFY));
935 notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
937 notifyContext->Buffer.pContext = notifyContext;
938 result = NotifyServiceStatusChangeW_I(
939 notifyContext->ServiceHandle,
940 notifyContext->IsServiceManager
941 ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED)
942 : (SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_STOP_PENDING |
943 SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_CONTINUE_PENDING | SERVICE_NOTIFY_PAUSE_PENDING |
944 SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_DELETE_PENDING),
945 ¬ifyContext->Buffer
951 notifyContext->State =
SnNone;
953 InsertTailList(&PhpNonPollServiceListHead, ¬ifyContext->ListEntry);
955 case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
959 case ERROR_SERVICE_MARKED_FOR_DELETE:
970 while (NtWaitForSingleObject(PhpNonPollEventHandle,
TRUE, NULL) != STATUS_WAIT_0)
980 listEntry = PhpNonPollServiceListHead.Flink;
982 while (listEntry != &PhpNonPollServiceListHead)
985 listEntry = listEntry->Flink;
989 listEntry = PhpNonPollServicePendingListHead.Flink;
991 while (listEntry != &PhpNonPollServicePendingListHead)
994 listEntry = listEntry->Flink;
998 CloseServiceHandle(scManagerHandle);
1001 NtClose(PhpNonPollEventHandle);
1003 return STATUS_SUCCESS;
1006 PhpNonPollActive =
FALSE;
1008 NtClose(PhpNonPollEventHandle);
1009 return STATUS_UNSUCCESSFUL;
1020 if (!NotifyServiceStatusChangeW_I)
1023 PhpNonPollActive =
TRUE;
1028 if (!PhpNonPollThreadHandle)
1030 PhpNonPollActive =
FALSE;