Проверить, помечена ли услуга для удаления

Иногда, когда я удаляю установку (сделанную с помощью WIX), служба остается помеченной для удаления, и пользователь должен перезагрузить компьютер для повторной установки. Как я могу убедиться, что служба помечена для удаления, и сказать пользователю, чтобы он перезагрузил компьютер перед выполнением другой установки?


person ctescu    schedule 16.03.2011    source источник
comment
Не уверен, что вы сможете узнать это из ServiceController: ServiceController.GetServices(), но попробовать стоит.   -  person Jaroslav Jandek    schedule 16.03.2011


Ответы (6)


Вообще говоря, этот сценарий возникает, когда что-то остается привязанным к этой службе, не позволяя Windows удалить свою конфигурацию в реестре. (В большинстве случаев это просто апплет служб - services.msc - случайно оставленный открытым в фоновом режиме.)

Для обнаружения я предлагаю вам прочитать CreateService и другой Service API . Например, вы получите ERROR_SERVICE_MARKED_FOR_DELETE после вызова CreateService, если служба помечена для удаления.

Что касается предложенного вами решения по перезагрузке ... Windows продвинулась достаточно далеко, чтобы не требовать перезагрузки практически по любой причине. Если вы не устанавливаете специализированные драйверы ядра, перезагрузка не требуется. Не ленитесь! Помните о пользователе! Я рекомендую изменить логику установщика, чтобы обнаруживать потенциально конфликтующие запущенные программы, такие как апплет служб, и предлагать закрытие.

person Rafael Rivera    schedule 16.03.2011
comment
Как вы предполагаете определить, загружен ли сервисный апплет в mmc? - person vkrzv; 06.06.2013

Я не могу найти способ сделать это через API (который не требует вызова CreateService или DeleteService, оба имеют нежелательные побочные эффекты), но HKLM\SYSTEM\CurrentControlSet\Services\ServiceName, содержащий значение DeleteFlag=1 (REG_DWORD), кажется довольно показательным для этого неудачного состояния.

person Ilya    schedule 04.03.2012

Вот сообщение SO, которое может вам помочь. Хотя исходный вопрос касается установки службы, ответ также касается удалений и статусов.

Как программно установить службу Windows на 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

ИЗМЕНИТЬ

Согласно комментарию Кристофера Пейнтера, я обновляю этот ответ, чтобы продвигать передовой опыт. Хотя получение сообщения «помечено для удаления» чаще (по моему опыту) было результатом наличия консоли 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>
person bitxwise    schedule 16.03.2011
comment
Было бы неплохо, если бы -1 объяснили - person bitxwise; 17.03.2011
comment
WiX использует установщик Windows, который поддерживает установку / удаление служб. Любая попытка написать собственные действия в установщике считается плохой практикой. См. robmensching.com/blog/posts/2007/8/17/ - person Christopher Painter; 05.03.2012
comment
Спасибо за объяснение. Я согласен со многими моментами, изложенными в сообщении блога, на которое вы указали ссылку, однако я не полностью согласен с вашей интерпретацией сообщения. Не пытаясь начать войну, но автор сообщения подчеркнул, что настраиваемые действия ВООБЩЕ не рекомендуется по перечисленным причинам, по которым разработчики настройки должны писать настраиваемые действия. Тем не менее, OP, вероятно, должен использовать ‹ScheduleReboot After = InstallFinalize /› в теге ‹InstallExecuteSequence› через WiX XML вместо написания настраиваемого действия для лучшей практики. Я обновлю ответ, чтобы отразить это. - person bitxwise; 06.03.2012
comment
См. Его причину #a (изобретение велосипеда). Любое обсуждение программной установки службы в C # по определению является нарушением этого принципа. В установщике Windows есть таблица ServiceInstall для выполнения этой работы. Стандартные действия встроенных служб установщика Windows AFAIK обрабатывают службы, помеченные для удаления. - person Christopher Painter; 06.03.2012
comment
Я думаю, что в большинстве магазинов все сводится к 1. количеству усилий / времени / навыков разработчика и 2. приоритетам. Дело могло быть в любом случае. Я написал вещи, которые, возможно, уже существовали, но написал их с улучшением. Тот факт, что интерфейс уже существует, не означает, что инновации должны умереть от него. Я не говорю, что ОП пытается быть новаторским. Я просто говорю, что не полностью согласен с жестким правилом вашей интерпретации. Еще раз спасибо за понимание. - person bitxwise; 06.03.2012
comment
Я думаю, контекст, который может помочь вам понять Роба / мою философию, заключается в том, что установщик Windows является декларативным, а не императивным языком программирования. Хотя я понимаю, о чем вы говорите, установщики - это не язык программирования общего назначения, в котором мы пытаемся внедрять инновации. Основное внимание уделяется надежности установки, и внедрение настраиваемых действий почти всегда снижает этот результат. - person Christopher Painter; 06.03.2012
comment
Другими словами, предполагается, что у группы установщиков Windows в Microsoft были последние 13 лет, чтобы правильно установить службу, и что любой разработчик установки, который попытается сделать это сам, выполнит низкую работу. Исходя из опыта (16 лет написания установщиков) я принимаю это предположение как почти факт. - person Christopher Painter; 06.03.2012
comment
Так что, по вашему мнению, вместо того, чтобы решать проблему в отведенное время, нужно потратить это время на попытки изучить новую технологию и не дать результата? Развитие часто - это идеализм против прагматизма. - person John Nicholas; 05.11.2012

Я также искал решение, которое позволяет определить, существует ли служба или помечена для удаления, даже если OpenService успешно. Я также обнаружил, что код ошибки ERROR_SERVICE_MARKED_FOR_DELETE, возвращаемый ChangeServiceConfig. Итак, вот способ проверить, помечена ли служба для удаления через ChangeServiceConfig с помощью C / C ++:

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;
    }
}
person xenophōn    schedule 11.06.2019
comment
Похоже на отличное решение без побочных эффектов (в отличие от вызова службы создания / удаления для получения ошибки). - person Tomas Pruzina; 16.02.2021

Используете ли вы элемент / таблицу ServiceControl для остановки службы во время удаления? Если да, то ваша служба успешно останавливается? Если нет, посмотрите, что происходит внутри вашей службы, чтобы убедиться, что она высвобождает все свои ресурсы и корректно завершает работу по запросу.

Вам не нужно писать какие-либо пользовательские действия для программного вызова SCM API. Установщик Windows должен справиться с этим за вас.

person Christopher Painter    schedule 16.03.2011
comment
Это не отвечает на вопрос. Некоторые службы просто невозможно остановить, например когда служба принадлежит драйверу устройства, который не может быть безопасно выгружен. - person Ilya; 04.03.2012
comment
То, что вы упустили, заключалось в том, что это не проблема установщика, а необходимость заглядывать внутрь вашего служебного кода. Если службу не удается остановить, не просите установщика остановить ее. - person Christopher Painter; 04.03.2012
comment
Цель вашего деинсталлятора - удалить службу. Деинсталлятор должен сначала остановить его, но если его невозможно остановить, он все равно удалит его (что пометит его для удаления при выключении системы). Если пользователь решит не перезапускать программу в конце деинсталлятора, а затем перейдет к переустановке, он потенциально столкнется с проблемой, когда установщик попытается снова создать службу. - person Ilya; 05.03.2012

В моем случае служба была помечена для удаления после ее удаления, потому что я неправильно удалил объект (в моем случае rabbitmq-connection).

Это не прямой ответ на вопрос, но может помочь решить его коренную проблему.

person Peter Widmer    schedule 04.12.2017