Winapi SetServiceStatus设置服务停止,但QueryServiceStatusEx返回服务停止挂起

Winapi SetServiceStatus设置服务停止,但QueryServiceStatusEx返回服务停止挂起,winapi,service,Winapi,Service,我在我的服务/客户端程序中偶然发现了一个严重问题,其工作方式如下: 客户端应用程序使用ControlService(…SERVICE\u CONTROL\u STOP…)停止服务 服务停止时,应用程序会定期调用QueryServiceStatusEx,检查dwCurrentState是否已停止service\u。它还检查dwWaitHint是否超时 同时,该服务执行以下操作: 在清理之前,它使用dwCurrentState=SERVICE\u STOP\u PENDING和dwWaitHi

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

  • 客户端应用程序使用
    ControlService(…SERVICE\u CONTROL\u STOP…)
    停止服务
  • 服务停止时,应用程序会定期调用
    QueryServiceStatusEx
    ,检查
    dwCurrentState
    是否已停止
    service\u
    。它还检查
    dwWaitHint
    是否超时
同时,该服务执行以下操作:

  • 在清理之前,它使用
    dwCurrentState
    =
    SERVICE\u STOP\u PENDING
    dwWaitHint
    =
    3000
    调用
    SetServiceStatus
  • 清理后,它使用
    dwCurrentState
    =
    SERVICE\u停止
    dwWaitHint
    =
    0
    调用
    SetServiceStatus
在复制并记录该问题后,我提出了以下建议:

除上次客户端调用
QueryServiceStatusEx
时的情况外,一切正常,该次调用返回
dwCurrentState
=
SERVICE\u STOP\u PENDING
dwWaitHint
=
0
!这使得它的行为就像操作超时一样

我甚至不知道这是怎么发生的,我可以在日志中清楚地看到服务在退出之前设置了
dwCurrentState
=
service\u已停止

这是一个已知的问题吗?你知道这里可能发生什么事吗

更新:

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

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
如您所见,该服务在24437和24546之间停止(
GetTickCount
),其状态在26218处更改。这意味着它被标记为
SERVICE\u STOP\u PENDING
,持续1672秒。Windows会改变它的状态吗?为什么它被标记为等待这么久

更新2:

更多意见:

  • 调用
    SetServiceStatus
    会影响除
    dwCurrentState
    之外的所有内容,只要服务进程正在运行,就会将其保留为
    SERVICE\u STOP\u PENDING
    。这是Windows的一个功能吗?有文件记录吗
  • LPSERVICE\u MAIN\u函数返回后,以及从
    StartServiceCtrlDispatcher
    返回前,我的服务进程挂起超过一秒钟。为什么会这样?(请注意,它发生在启动Windows时)
  • 尝试写入服务可执行文件有时会返回
    错误\u共享\u冲突
    ,即使其状态为
    服务\u已停止
    。是否有可靠的方法确保过程完全结束
有人能解释这些吗?陈雷蒙

更新3:


更有趣的信息:
QueryServiceStatusEx
返回dwWaitHint:0、dwCurrentState:3、dwCheckPoint:0,即使我从未将
dwWaitHint
dwCheckPoint
设置为零!这里发生了什么?

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

SCM要求服务停止。查询到的状态是服务\u正在运行。该服务将状态设置为service_STOPPED,再次查询,并获得service_STOP_PENDING(等待提示为0)。最后,服务在StartServiceCtrlDispatcher返回并停止服务后查询状态

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

服务正在运行、服务停止挂起和服务停止或

服务正在运行、服务已停止和服务已停止

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

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


这种行为是可复制的,似乎是故意的。但是,正如您所说,它似乎没有任何文档记录。

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

SCM要求服务停止。查询到的状态是服务\u正在运行。该服务将状态设置为service_STOPPED,再次查询,并获得service_STOP_PENDING(等待提示为0)。最后,服务在StartServiceCtrlDispatcher返回并停止服务后查询状态

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

服务正在运行、服务停止挂起和服务停止或

服务正在运行、服务已停止和服务已停止

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

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


这种行为是可复制的,似乎是故意的。但是,正如你所说,它似乎在任何地方都没有被记录下来。

好吧,你对此无能为力,所以就把问题扔出去吧。dwWaitHint对于停止状态没有任何意义,所以不要更改它。这就是MS在其(“ReportSvcStatus(SERVICE_stopped,no_ERROR,0);”)中所做的,a