SetServiceStatus设置SERVICE_STOPPED,但QueryServiceStatusEx返回SERVICE_STOP_PENDING

时间:2013-12-07 20:05:19

标签: winapi service

我在我的服务/客户端程序中偶然发现了一个严重的问题,该问题的工作方式如下:

  • 客户端应用使用ControlService(... SERVICE_CONTROL_STOP ...)停止服务。
  • 当服务停止时,应用会定期致电QueryServiceStatusEx以检查dwCurrentState是否为SERVICE_STOPPED。它还会检查dwWaitHint是否超时。

同时服务这样做:

  • 在清理之前,它会使用SetServiceStatus = dwCurrentStateSERVICE_STOP_PENDING = dwWaitHint来呼叫3000
  • 清理完毕后,系统会SetServiceStatus = dwCurrentStateSERVICE_STOPPED = dwWaitHint致电0

在复制并记录问题后,我想出了这个:

一切正常,除了客户最后一次调用QueryServiceStatusEx,其返回dwCurrentState = SERVICE_STOP_PENDINGdwWaitHint = {{ 1}}!这使得它的行为就像操作超时一样。

我不知道这是怎么发生的,我可以在日志中清楚地看到服务在退出之前设置0 = dwCurrentState

这是一个已知问题吗?你有什么线索可能会发生在这里吗?

更新

以下是客户端应用的日志:

SERVICE_STOPPED

如您所见,该服务已在24437和24546(24437 ssStatus.dwWaitHint: 3000, ssStatus.dwCurrentState: 3 24546 ssStatus.dwWaitHint: 0, ssStatus.dwCurrentState: 3 24609 ssStatus.dwWaitHint: 0, ssStatus.dwCurrentState: 3 ... 26000 ssStatus.dwWaitHint: 0, ssStatus.dwCurrentState: 3 26062 ssStatus.dwWaitHint: 0, ssStatus.dwCurrentState: 3 26218 Stopped )之间停止,并且其状态在26218处已更改。这意味着它被标记为GetTickCount另外1,672秒。 Windows可以改变它的状态吗?为什么它被标记为待定这么久?

更新2:

更多观察:

  • 调用SERVICE_STOP_PENDING会影响除SetServiceStatus之外的所有内容,只要服务进程正在运行,该内容将保留为dwCurrentState。这是Windows的一个功能吗?是否记录在案?
  • SERVICE_STOP_PENDING返回后,从LPSERVICE_MAIN_FUNCTION返回之前,我的服务流程会暂停一两秒钟。为什么会这样? (P.S.它在启动Windows时发生)。
  • 尝试写入服务可执行文件有时会返回StartServiceCtrlDispatcher,即使它的状态为ERROR_SHARING_VIOLATION。有没有可靠的方法来确保过程完全结束?

有人能解释一下吗?雷蒙德·陈?

更新3:

更有趣的信息:SERVICE_STOPPED返回dwWaitHint:0,d​​wCurrentState:3,dwCheckPoint:0即使我从未将QueryServiceStatusExdwWaitHint设置为零!这是怎么回事?

1 个答案:

答案 0 :(得分:1)

我创建了一个简单的服务,并尝试从服务本身查询服务状态,以便查询与状态的变化同步。

SCM要求服务停止。查询状态为SERVICE_RUNNING。该服务将状态设置为SERVICE_STOPPED,再次查询它并获得SERVICE_STOP_PENDING(等待提示为0)。最后,服务在StartServiceCtrlDispatcher返回并获得SERVICE_STOPPED后查询状态。

这不完全一致;这三个查询有两种可能的结果:

SERVICE_RUNNING,SERVICE_STOP_PENDING和SERVICE_STOPPED或

SERVICE_RUNNING,SERVICE_STOPPED和SERVICE_STOPPED。

我在sc命令行工具中看到了同样的事情。如果我要求它停止我的服务,它有时会将状态报告为已停止,有时会将其报告为待处理状态,即使我的服务从未将其设置为待处理状态。

在服务将状态设置为SERVICE_STOPPED之后,但在Windows将控制权返回给调度程序(主)线程之前,有一个简短的SERVICE_STOP_PENDING窗口。如果机器正在启动并因此繁忙,则此SERVICE_STOP_PENDING窗口可能会很长。

行为是可重复的,似乎是刻意的。但是,正如你所说,它似乎没有在任何地方记录。