【发布时间】:2021-01-22 16:26:02
【问题描述】:
我正在开发一个用 C 代码编写的 Windows 服务。
在服务初始化代码中,我注册了一个 SERVICE_ACCEPT_PRESHUTDOWN 事件,如下所示:
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;
在服务控制处理程序中,我在 SERVICE_CONTROL_PRESHUTDOWN 事件中编写了写入文件的逻辑,如下所示:
DWORD WINAPI SvcCtrlHandler(DWORD dwCtrl, DWORD eventType, void *eventData, void *context)
{
if (dwCtrl == SERVICE_CONTROL_STOP)
{
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
else if (dwCtrl == SERVICE_CONTROL_PRESHUTDOWN)
{
char sentence[] = "Hello World";
FILE *fptr;
fptr = fopen("C:\\test\\program.txt", "w");
if (fptr == NULL) {
printf("Error!");
}
else
{
fprintf(fptr, "%s", sentence);
fclose(fptr);
}
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus);
return NO_ERROR;
}
但重启后,我无法在 test 文件夹中看到文件 program.txt。需要帮助解决此问题。
我还尝试了什么:
我还尝试使用 SvcReportEvent 函数写入事件查看器:
//
// Purpose:
// Logs messages to the event log
//
// Parameters:
// szFunction - name of function that failed
//
// Return value:
// None
//
// Remarks:
// The service must have an entry in the Application event log.
//
VOID SvcReportEvent(LPTSTR szFunction)
{
HANDLE hEventSource;
LPCTSTR lpszStrings[2];
TCHAR Buffer[80];
hEventSource = RegisterEventSource(NULL, SVCNAME);
if( NULL != hEventSource )
{
StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());
lpszStrings[0] = SVCNAME;
lpszStrings[1] = Buffer;
ReportEvent(hEventSource, // event log handle
EVENTLOG_ERROR_TYPE, // event type
0, // event category
SVC_ERROR, // event identifier
NULL, // no security identifier
2, // size of lpszStrings array
0, // no binary data
lpszStrings, // array of strings
NULL); // no binary data
DeregisterEventSource(hEventSource);
}
}
SvcCtrlHandler函数修改完成:
DWORD WINAPI SvcCtrlHandler(DWORD dwCtrl, DWORD eventType, void *eventData, void *context)
{
if (dwCtrl == SERVICE_CONTROL_STOP)
{
SvcReportEvent((LPTSTR)TEXT("In function SvcCtrlHandler in condition SERVICE_CONTROL_STOP"));
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
else if (dwCtrl == SERVICE_CONTROL_PRESHUTDOWN)
{
SvcReportEvent((LPTSTR)TEXT("In function SvcCtrlHandler in condition SERVICE_CONTROL_PRESHUTDOWN"));
gSvcStatus.dwWin32ExitCode = 0;
gSvcStatus.dwCurrentState = SERVICE_STOPPED;
}
SetServiceStatus(g_ServiceStatusHandle, &gSvcStatus);
return NO_ERROR;
}
观察:
- 当我重新启动计算机时,没有写入 Eventviewer 日志
- 当我手动停止服务时,会在事件查看器中写入一条日志:
在 SERVICE_CONTROL_STOP 条件下的函数 SvcCtrlHandler 中
注意:我在编写服务时引用的链接:https://docs.microsoft.com/en-us/windows/win32/services/the-complete-service-sample?redirectedfrom=MSDN
【问题讨论】:
-
您确定在每次调用 SetServiceStatus 时都设置了 SERVICE_ACCEPT_PRESHUTDOWN 标志吗?另外,我建议添加 SERVICE_ACCEPT_SHUTDOWN 和相应的处理程序,看看是否被调用。
-
嗨。是的,我在每次调用 SetSerivceStatus 时都设置了 PRESHUTDOWN 标志。我还尝试添加推荐的 SHUTDOWN 处理程序。由于某种原因,即使是这个处理程序也没有被调用。我也尝试过只使用 SHUTDOWN 处理程序,因为我读过的一些帖子表明只有一个 SHUTDOWN/PRESHUTDOWN 被调用。但对我来说,他们都没有被叫到。
-
奇怪。确保您对 SetServiceStatus() 的调用成功并且没有返回错误。这是什么版本的 Windows?
-
嗨@CoreTech。我想知道您是否可以与我分享一个基于 C 的最低工作服务,以供参考如何处理 SHUTDOWN / PRESHUTDOWN 事件。我目前正在寻找一个示例来执行此操作,但我没有在网上找到任何满足我要求的东西。
-
@CoreTech "另外,我建议添加SERVICE_ACCEPT_SHUTDOWN" - SERVICE_ACCEPT_PRESHUTDOWN 和 SERVICE_ACCEPT_SHUTDOWN 不能一起使用,见Correct way to register for pre-shutdown notification from C++
标签: c windows windows-services