Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 验证服务是否标记为删除_C#_Wix_Wix3.5 - Fatal编程技术网

C# 验证服务是否标记为删除

C# 验证服务是否标记为删除,c#,wix,wix3.5,C#,Wix,Wix3.5,有时,当我卸载安装程序(使用WIX创建)时,服务仍然标记为删除,用户必须重新启动计算机才能再次安装。 如何验证该服务是否标记为删除,并告诉用户在进行其他安装之前重新启动计算机?以下是一篇SO帖子,可能会对您有所帮助。虽然最初的问题是关于服务安装的,但答案也包括卸载和状态 这里有一篇文章解释了为什么你会首先收到“标记为删除”的消息,以及如何避开它 编辑 根据Christopher Painter的评论,我正在更新这个答案,以促进最佳实践。根据我的经验,接收“标记为删除”消息通常是由于使用ser

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

以下是一篇SO帖子,可能会对您有所帮助。虽然最初的问题是关于服务安装的,但答案也包括卸载和状态

这里有一篇文章解释了为什么你会首先收到“标记为删除”的消息,以及如何避开它

编辑

根据Christopher Painter的评论,我正在更新这个答案,以促进最佳实践。根据我的经验,接收“标记为删除”消息通常是由于使用services.msc控制台而不是未释放的资源,但编写自定义操作以重新启动并不是最好的方法

要在WiX处理后计划重新启动,请使用WiX XML(解释了如何使用WiX#),如下所示:

<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
    ...
    <InstallExecuteSequence>
        <ScheduleReboot After="InstallFinalize"/>
    <InstallExecuteSequence>
</Wix>

...

一般来说,当某个服务仍然锁定在该服务上,阻止Windows删除其注册表中的配置时,就会出现这种情况。(在大多数情况下,它只是服务小程序--Services.msc--在后台意外打开。)

为了检测,我建议你仔细阅读和其他。例如,如果服务被标记为删除,则在调用CreateService时,您将收到错误\u SERVICE\u MARKED\u For\u DELETE


关于您建议的重新启动解决方案。。。Windows已经发展到几乎不需要任何原因重新启动的地步。除非您正在安装专门的内核驱动程序,否则不需要重新启动。别偷懒!记住用户!我建议更改您的安装程序逻辑,以检测可能存在冲突的运行程序,如服务小程序,并建议关闭。

您是否在卸载过程中使用ServiceControl元素/表来停止服务?如果是,您的服务是否成功停止?如果没有,请查看您的服务内部发生了什么,以确保它释放了所有资源,并在请求时优雅地关闭


您不需要编写任何自定义操作来编程调用SCM API。Windows Installer应该能够为您处理此问题。

我找不到API方法来处理此问题(它不涉及调用
CreateService
DeleteService
,两者都有不希望的副作用),但是
HKLM\SYSTEM\CurrentControlSet\Services\ServiceName
包含
DeleteFlag=1
(REG\u DWORD)值似乎很好地指示了这种不幸的状态。

在我的情况下,卸载服务后将其标记为删除,因为我没有正确地处理对象(在我的情况下是rabbitmq连接)


这不是对这个问题的直接回答,但可能有助于解决它的根本问题。

我还搜索了一个解决方案,以确定某个服务是否存在或是否标记为删除,即使
OpenService
成功。我还发现由
ChangeServiceConfig
返回的错误代码
error\u SERVICE\u标记为\u FOR\u DELETE
。因此,以下是通过使用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;
    }
}

不确定是否可以从
ServiceController
ServiceController.GetServices()
中找到它,但值得一试。如果解释了-1,wix使用支持安装/卸载服务的Windows Installer就更好了。在安装程序中编写自定义操作的任何尝试都被认为是一种不良做法。看:谢谢你的解释。我同意你链接的博客文章中的许多观点,但是我并不完全同意你对这篇文章的解释。我不想挑起战争,但这篇文章的作者强调,定制操作通常是不被鼓励的,因为上面列出了为什么设置开发人员会编写定制操作的原因。这就是说,OP可能应该通过WIXXML在标记中使用,而不是编写自定义操作,以便更好地实践。我将更新答案以反映这一点。参见他的理由a(重新发明轮子)。任何关于在c#中以编程方式安装服务的讨论都违反了这一原则。Windows Installer具有ServiceInstall表来执行此工作。AFAIK Windows Installer的内置服务标准操作处理处于标记为删除状态的服务。因此,与其在可用时间内解决问题,不如将时间花在尝试学习新技术上,而不能交付?发展往往是理想主义与实用主义的较量,这并不能回答问题。某些服务无法停止,例如,当服务属于无法安全卸载的设备驱动程序时。您忽略的一点是,这不是安装程序问题,请查看您的服务代码。如果无法停止服务,则不要要求安装程序停止。卸载程序的目标是删除该服务。卸载程序应该首先停止它,但如果它无法阻止,则无论如何都应该删除它(这将在系统关闭时标记为删除)。如果用户选择在卸载程序结束时不重新启动,然后重新安装,那么当安装程序再次尝试创建服务时,他可能会面临一个问题。您认为如何检测服务小程序是否加载到mmc?听起来是一个没有副作用的很好的解决方案(与调用create/delete服务获取错误不同)。