有时当我卸载设置(使用WIX制作)时,服务仍然标记为删除,用户必须重新启动计算机才能再次安装。 如何验证服务是否已标记为删除,并告知用户在进行其他安装之前重新启动计算机?
答案 0 :(得分:3)
一般来说,当某些内容仍然锁定在该服务上时会出现这种情况,从而阻止Windows在注册表中删除其配置。 (在大多数情况下,它只是服务小程序 - services.msc - 在后台意外打开。)
如需检测,建议您阅读CreateService和其他Service API。例如,如果服务被标记为删除,则在调用CreateService时将收到ERROR_SERVICE_MARKED_FOR_DELETE。
关于您提出的重新启动解决方案...... Windows已经发展得足够远,几乎不需要重启。除非您安装专门的内核驱动程序,否则无需重新启动。别懒!记住用户!我建议更改安装程序逻辑以检测可能存在冲突的运行程序,例如服务小程序,并建议关闭。
答案 1 :(得分:2)
这是一篇可以帮助你的SO帖子。虽然最初的问题是服务安装,但答案还包括卸载和状态。
How to install a windows service programmatically in C#?
这篇文章解释了为什么您可能会首先收到“标记为删除”的消息以及如何解决这个问题。
修改强>
Per Christopher Painter的评论,我正在更新这个答案,以促进最佳实践。虽然收到“标记为删除”消息(根据我的经验),使用services.msc控制台的结果比未释放的资源更多,但编写自定义操作以重新启动并不是最好的方法。
要在WiX处理后安排重启,请使用WiX XML(如何使用Wix#here解释),如下所示:
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
...
<InstallExecuteSequence>
<ScheduleReboot After="InstallFinalize"/>
<InstallExecuteSequence>
</Wix>
答案 2 :(得分:2)
我无法找到API方法(不涉及调用CreateService
或DeleteService
,两者都有不良副作用),但
包含HKLM\SYSTEM\CurrentControlSet\Services\ServiceName
(REG_DWORD)值的DeleteFlag=1
似乎很好地表明了这个不幸的状态。
答案 3 :(得分:0)
您是否在卸载期间使用ServiceControl元素/表来停止服务?如果是这样,您的服务是否成功停止?如果没有,请查看服务内部发生的情况,以确保它释放所有资源,并在请求时正常关闭。
您不需要编写任何自定义操作来以编程方式调用SCM API。 Windows Installer应该能够为您处理此问题。
答案 4 :(得分:0)
在我的情况下,服务在卸载后被标记为删除,因为我没有正确处理对象(在我的情况下是rabbitmq-connection)。
这不是问题的直接答案,但可能有助于解决问题的根本问题。
答案 5 :(得分:0)
即使OpenService
成功,我也搜索了确定服务是否存在或标记为删除的解决方案。我还发现ERROR_SERVICE_MARKED_FOR_DELETE
返回了错误代码ChangeServiceConfig
。因此,这是检查服务是否通过C / C ++通过ChangeServiceConfig
标记为删除的方法:
BOOL SetDisplayName(SC_HANDLE schService, LPCTSTR lpDisplayName)
{
return ChangeServiceConfig(schService, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, lpDisplayName);
}
//
// You need to obtain the hSCManager through OpenSCManager first
//
SC_HANDLE schService = OpenService(hSCManager, pszServiceName, SERVICE_CHANGE_CONFIG);
if (schService != nullptr)
{
//
// obtain the display name of a service
//
TCHAR szDisplayName[0x1000] = { 0 };
DWORD cchDisplayName = ARRAYSIZE(szDisplayName);
bResult = GetServiceDisplayName(schService, pszServiceName, szDisplayName, &cchDisplayName);
if (bResult)
{
//
// change the display name to the original display name
//
bResult = SetDisplayName(schService, szDisplayName);
if (!bResult)
{
DWORD dwError = GetLastError();
switch (dwError) {
case ERROR_ACCESS_DENIED:
case ERROR_CIRCULAR_DEPENDENCY:
case ERROR_DUPLICATE_SERVICE_NAME:
case ERROR_INVALID_SERVICE_ACCOUNT:
break;
case ERROR_INVALID_HANDLE:
break;
case ERROR_INVALID_PARAMETER:
break;
//
// the service is marked for deletion
//
case ERROR_SERVICE_MARKED_FOR_DELETE:
break;
default:
break;
}
}
}
}
else
{
DWORD dwError = GetLastError();
switch (dwError) {
case ERROR_ACCESS_DENIED:
break;
case ERROR_INVALID_HANDLE:
break;
case ERROR_INVALID_NAME:
break;
case ERROR_SERVICE_DOES_NOT_EXIST:
break;
default:
break;
}
}