【发布时间】:2022-08-14 05:36:53
【问题描述】:
如何正确使用 NotifyServiceStatusChange,以便在指定的服务被删除时收到通知?我当前的代码成功停止了服务并将其标记为删除。但是,我希望在服务完全删除时收到通知。
以下是我的代码的要点:
SC_HANDLE SCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
HANDLE EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
SERVICE_NOTIFY ServiceNotify;
ServiceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify.pszServiceNames = ServiceName;
ServiceNotify.pContext = &EventHandle;
ServiceNotify.pfnNotifyCallback = (PFN_SC_NOTIFY_CALLBACK)CallbackFunction;
DWORD status = NotifyServiceStatusChangeW(SCManager, SERVICE_NOTIFY_DELETED, &ServiceNotify);
WaitForSingleObject(EventHandle, INFINITE);
CloseServiceHandle(SCManager);
CloseHandle(EventHandle);
(服务名称为WCHAR*)
回调函数代码:
VOID CALLBACK CallbackFunction(IN PVOID pParameter) {
SERVICE_NOTIFY* ServiceNotify = pParameter;
HANDLE EventHandle = *(HANDLE*)ServiceNotify->pContext;
SetEvent(EventHandle);
}
NotifyServiceStatusChange 正在返回 ERROR_SUCCESS (0)。但是,我的回调函数根本没有被调用。我怎样才能解决这个问题?
编辑: 这是最小的可重现代码:
void ErrorExit(char* FunctionName, unsigned long ErrorCode) {
char* ErrorMessage;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, ErrorCode, LANG_USER_DEFAULT, (LPTSTR)&ErrorMessage, 0, NULL);
int MessageSize = (strlen(ErrorMessage) + strlen(FunctionName) + 50) * sizeof(char);
char* FullMessage = malloc(MessageSize);
sprintf_s(FullMessage, MessageSize, \"%s failed with error %d: %s\", FunctionName, ErrorCode, ErrorMessage);
MessageBoxA(NULL, FullMessage, \"Error\", MB_OK);
ExitProcess(ErrorCode);
}
PFN_SC_NOTIFY_CALLBACK CallbackFunction(PVOID pParameter) {
printf(\"CallbackFunction has been called.\\r\\n\");
SERVICE_NOTIFY* ServiceNotify = pParameter;
HANDLE EventHandle = ServiceNotify->pContext;
if (!SetEvent(EventHandle)) {
ErrorExit(\"SetEvent\", GetLastError());
}
}
int main()
{
WCHAR* ServiceName = L\"SERVICE NAME\"; // Input service name here
SC_HANDLE SCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (!SCManager) {
ErrorExit(\"OpenSCManagerW\", GetLastError());
}
SC_HANDLE ServiceHandle = OpenServiceW(SCManager, ServiceName,
SERVICE_ENUMERATE_DEPENDENTS | SERVICE_STOP | DELETE);
if (!ServiceHandle) {
ErrorExit(\"ServiceHandle\", GetLastError());
}
if (!DeleteService(ServiceHandle)) {
ErrorExit(\"DeleteService\", GetLastError());
}
if (!CloseServiceHandle(ServiceHandle)) {
ErrorExit(\"CloseServiceHandle\", GetLastError());
}
HANDLE EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!EventHandle) {
ErrorExit(\"CreateEventW\", GetLastError());
}
SERVICE_NOTIFY ServiceNotify;
ServiceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify.pszServiceNames = ServiceName;
ServiceNotify.pContext = EventHandle;
ServiceNotify.pfnNotifyCallback = CallbackFunction;
DWORD status = NotifyServiceStatusChangeW(SCManager, SERVICE_NOTIFY_DELETED, &ServiceNotify);
if (status != ERROR_SUCCESS) {
ErrorExit(\"NotifyServiceStatusChangeW\", GetLastError());
}
status = WaitForSingleObjectEx(EventHandle, INFINITE, TRUE);
if (status == WAIT_FAILED) {
ErrorExit(\"WaitForSingleObjectEx\", GetLastError());
}
printf(\"WaitForSingleObjectEx Result: %lu\\r\\n\", status);
system(\"pause\");
return 0;
}
当我运行它时,没有其他服务依赖于被删除的服务,并且被删除的服务已经停止。我的错误处理函数 \"ErrorExit\" 从未被调用过。屏幕上没有打印任何内容。我的程序只是暂停,我假设它来自 WaitForSingleObjectEx。
我知道该服务正在被删除,因为我打开了 ProcessHacker,它会通知我该服务正在被删除。
-
与您的问题无关,只是仅供参考,在将
EventHandle分配给pContext时,您不需要使用&运算符,因为HANDLE已经是一个指针类型。 -
您的回调函数被声明为错误的。
PFN_SC_NOTIFY_CALLBACK CallbackFunction(PVOID pParameter)应该改为VOID CALLBACK CallbackFunction(PVOID pParameter)。然后您可以在将CallbackFunction分配给ServiceNotify.pfnNotifyCallback时摆脱类型转换 -
此外,
WCHAR* ServiceName = L\"SERVICE NAME\";不会在任何符合标准的编译器中编译。您需要改用const WCHAR*(又名LPCWSTR)。 -
@RemyLebeau 谢谢。这些建议有助于使其发挥作用。我认为主要是它不是
const WCHAR*。您可以创建一个新答案或编辑您的原始答案以便我接受吗? -
我不需要更新任何内容,我的答案中的示例已经符合我上面提到的所有要点。