验证服务是否标记为删除

时间:2011-03-16 06:33:56

标签: c# wix wix3.5

有时当我卸载设置(使用WIX制作)时,服务仍然标记为删除,用户必须重新启动计算机才能再次安装。 如何验证服务是否已标记为删除,并告知用户在进行其他安装之前重新启动计算机?

6 个答案:

答案 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#?

这篇文章解释了为什么您可能会首先收到“标记为删除”的消息以及如何解决这个问题。

http://weblogs.asp.net/avnerk/archive/2007/09/05/windows-services-services-msc-and-the-quot-this-service-is-marked-for-deletion-quot-error.aspx

修改

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方法(不涉及调用CreateServiceDeleteService,两者都有不良副作用),但 包含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;
    }
}