【发布时间】:2020-05-22 23:17:33
【问题描述】:
我创建了一个小型 Windows 服务来捕获一些事件,包括系统关闭。每次我关闭计算机时,服务事件都不会被调用。但是当我重新启动计算机时,该事件正常工作。
我已经尝试使用:SERVICE_ACCEPT_PRESHUTDOWN + SERVICE_CONTROL_PRESHUTDOWN,但没有成功。
我怎样才能捕捉到计算机关机事件?
Ps:编译后我使用以下命令注册服务:sc.exe create "ZSimpleService" binPath = "C:\path\ZSimpleService.exe"
编辑 1:我使用的是 Windows 10
代码:
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
DWORD WINAPI CtrlHandlerEx(DWORD CtrlCode, DWORD eventType, LPVOID eventData, LPVOID context);
#define SERVICE_NAME _T("ZSimpleService")
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv) {
g_StatusHandle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, CtrlHandlerEx,
NULL);
if (g_StatusHandle == NULL) {
goto EXIT;
}
// Tell the service controller we are starting
ZeroMemory( & g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SESSIONCHANGE
| SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL) {
//...
goto EXIT;
}
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(g_ServiceStopEvent);
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
}
EXIT: return;
}
void suspending() {
FILE *file = fopen("C:\\test\\suspending.txt", "w+");
if (file)
fprintf(file, "...");
}
void logoff() {
FILE *file = fopen("C:\\test\\logoff.txt", "w+");
if (file)
fprintf(file, "...");
}
void lock_session() {
FILE *file = fopen("C:\\test\\lock_session.txt", "w+");
if (file)
fprintf(file, "...");
}
void poweroff() {
FILE *file = fopen("C:\\test\\poweroff.txt", "w+");
if (file)
fprintf(file, "...");
}
DWORD WINAPI CtrlHandlerEx(DWORD CtrlCode, DWORD eventType, LPVOID eventData,
LPVOID context) {
switch (CtrlCode) {
case SERVICE_CONTROL_STOP: {
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
SetEvent(g_ServiceStopEvent);
return NO_ERROR;
}
case SERVICE_CONTROL_POWEREVENT: {
if (eventType == PBT_APMQUERYSUSPEND) {
//Computer is suspending
suspending();
}
return NO_ERROR;
}
case SERVICE_CONTROL_SESSIONCHANGE: {
switch (eventType) {
case WTS_SESSION_LOGOFF:
//User is logging off
logoff();
break;
case WTS_SESSION_LOCK:
//User locks the session
lock_session();
break;
}
return NO_ERROR;
}
case SERVICE_CONTROL_SHUTDOWN: {
//Computer is shutting down
poweroff();
return NO_ERROR;
}
default:
return ERROR_CALL_NOT_IMPLEMENTED;
}
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam) {
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
//many cool code....
Sleep(3000);
}
return 0;
}
DWORD RunService() {
SERVICE_TABLE_ENTRY serviceTable[] = { { SERVICE_NAME, ServiceMain },
{ 0, 0 } };
if (StartServiceCtrlDispatcher(serviceTable)) {
return 0;
} else {
DWORD erro = GetLastError();
//handler erro...
return 1;
}
}
int _tmain(int argc, TCHAR *argv[]) {
RunService();
return 0;
}
【问题讨论】:
-
可能你的电脑真的不是关机而是休眠
-
我从命令行关闭了 windows 1903:
shutdown /s。它对我有用(创建 logoff.txt 和 poweroff.txt)。您如何关闭机器以及您的 Windows 版本是多少? -
@RitaHan-MSFT 你好,我用关机命令试过了,它奏效了!但我不明白为什么在:开始菜单->关机/重启->关机。关机不起作用,我关机时别名
CtrlHandlerEx收到:CtrlCode SERVICE_CONTROL_POWEREVENT和eventType PBT_APMQUERYSUSPEND -
从事件查看器发现关闭菜单似乎在调用
SetSuspendStateAPI 以使机器进入睡眠模式,因此您不会收到SERVICE_CONTROL_SHUTDOWN事件。
标签: c++ c winapi events service