我有一个基于ATL 7 CAtlServiceModuleT
课程的Windows服务。此服务提供系统上各种应用程序使用的COM对象,如果服务在运行时停止,这些其他应用程序自然会开始出错。
我知道ATL DLL通过在DllCanUnloadNow()
中返回S_OK来解决这个问题,如果CComModule的GetLockCount()
返回0。也就是说,它会检查以确保当前没有人正在使用由DLL。我想在服务中使用相同的功能。
以下是我在覆盖CAtlServiceModuleT::OnStop()
时所做的事情:
void CMyServiceModule::OnStop()
{
if( GetLockCount() != 0 ) {
return;
}
BaseClass::OnStop();
}
现在,当用户尝试从“服务”面板停止服务时,会显示一条错误消息:
Windows无法在本地计算机上停止XYZ服务。 该服务未返回错误。这可能是内部Windows错误或内部服务错误。 如果问题仍然存在,请与系统管理员联系。
确实拒绝了Stop请求,但它似乎使服务处于错误状态。第二个Stop请求会产生以下错误消息:
Windows无法在本地计算机上停止XYZ服务。
错误1061:此时服务无法接受控制消息。
有趣的是,这次服务确实停止了(虽然我不愿意,因为仍有未完成的COM引用)。
我有两个问题:
答案 0 :(得分:1)
你不能这样做。一旦SCM向您的服务发送SERVICE_CONTROL_STOP,您就必须停止。
如果您的其他应用程序也是服务,您可以在SCM中使它们成为依赖项。当然,如果使用此服务的应用程序只是无法使用的常规应用程序。
答案 1 :(得分:1)
当ATL的锁定计数增加到1时,在SetServiceStatus()
字段中省略SERVICE_ACCEPT_STOP
标记,调用SERVICE_STATUS::dwControlsAccepted
。然后,您根本不会收到任何SERVICE_CONTROL_STOP
个请求。任何停止服务的尝试都将立即失败。当ATL的锁定计数回落到0时,再次使用指定的SetServiceStatus()
标志调用SERVICE_ACCEPT_STOP
。
我只需要在2个(较旧的)基于ATL的服务中执行此操作,并且它运行良好。当然,我无法找出直接覆盖Lock()和Unlock()的最佳方法,所以我只是在我的服务中放了一个小循环,频繁地检查GetLockCount()
并在调用时SetServiceStatus()
调用{{1}}需要的。
答案 2 :(得分:0)
在构造函数中,更新m_status.dwControlsAccepted
删除SERVICE_ACCEPT_STOP
。例如:
CMyServiceModule::CMyServiceModule()
: ATL::CAtlServiceModuleT<CMyServiceModule, IDS_SERVICENAME>()
{
m_status.dw &= ~SERVICE_ACCEPT_STOP
}