У меня есть сервис, который устанавливается моим установщиком WIX:
<Component Id = "cmp_myService" Guid = "{5FC8815E-33T8-4C3D-9654-849EE4CB1E22}">
<File Id = "f_myService" Name = "MyService.exe" Source = "$(var.SourcePath)MyService.exe" KeyPath = "yes" />
<ServiceInstall Id = "si_myServiceInstall" Name = "My Service" DisplayName = "It is my service" Type = "ownProcess" Interactive = "yes" Start = "auto" ErrorControl = "normal" Description = "Here is some description" />
<ServiceControl Id = "sc_startStopMyService" Name = "My Service" Start = "install" Stop = "both" Remove = "uninstall" Wait = "yes" />
</Component>
Также у меня есть пользовательское действие ca1_removeInstallDirOnUnsinstall
, которое удаляет папку со всем ее содержимым (MyService.exe
находится внутри этой папки)
<Custom Action = "ca1_removeInstallDirOnUnsinstall" After = "DeleteServices"><![CDATA[REMOVE = "ALL"]]></Custom>
Я планирую выполнение этого пользовательского действия сразу после действия DeleteServices
в последовательности выполнения. Я предполагаю, что на этом этапе MyService.exe
следует остановить и удалить. Но я получаю исключение Access to the path 'MyService.exe' is denied
, что означает, что сервис еще не удален. Почему это происходит и где мое пользовательское действие должно быть запланировано, чтобы быть уверенным, что служба уже удалена?
Связанные файлы журнала:
MSI (s) (64:3C) [08:42:32:597]: Doing action: StopServices
MSI (s) (64:3C) [08:42:32:597]: Note: 1: 2205 2: 3: ActionText
Action ended 8:42:32: UnpublishFeatures. Return value 1.
Action start 8:42:32: StopServices.
MSI (s) (64:3C) [08:42:32:597]: Doing action: DeleteServices
MSI (s) (64:3C) [08:42:32:597]: Note: 1: 2205 2: 3: ActionText
Action ended 8:42:32: StopServices. Return value 1.
Action start 8:42:32: DeleteServices.
MSI (s) (64:3C) [08:42:32:597]: Doing action: ca1_removeInstallDirOnUnsinstall
MSI (s) (64:3C) [08:42:32:597]: Note: 1: 2205 2: 3: ActionText
Action ended 8:42:32: DeleteServices. Return value 1.
MSI (s) (64:80) [08:42:32:597]: Invoking remote custom action. DLL: C:\windows\Installer\MSIA125.tmp, Entrypoint: RemoveInstallDirRecursively
MSI (s) (64:B8) [08:42:32:597]: Generating random cookie.
MSI (s) (64:B8) [08:42:32:597]: Created Custom Action Server with PID 6176 (0x1820).
MSI (s) (64:98) [08:42:32:644]: Running as a service.
MSI (s) (64:B4) [08:42:32:644]: Hello, I'm your 32bit Impersonated custom action server.
Action start 8:42:32: ca1_removeInstallDirOnUnsinstall.
SFXCA: Extracting custom action to temporary directory: C:\windows\Installer\MSIA125.tmp-\
SFXCA: Binding to CLR version v4.0.30319
Calling custom action CustomAction!CustomAction.FilesAndFoldersCustomAction.RemoveInstallDirRecursively
Access to the path 'MyService.exe' is denied.
@SteinÅsmul Да, я удаляю файлы журнала, оставшиеся после удаления процесса.
InstallFinalize: DeleteServices
происходит раньше InstallFiles
. Я предполагаю, что у msiexec.exe
может быть блокировка папки для потенциальной переустановки в рамках крупного обновления, но я не уверен (найдите блокировки, используя: perfmon.exe , procexp64.exe). Вы можете поместить действие удаления прямо перед InstallFinalize
(что завершает операции с повышенными правами, которые изменяют систему). Это расположение должно работать, но никаких гарантий. Не рекомендуется уничтожать целые папки.
Рекомендация: Как правило, вам не следует удалять целые папки (это довольно рискованно — что-то испортите, и вы можете в конечном итоге удалить половину вашего компьютера. Серьезно. Я видел, как это случалось. Не с MSI, а с «очисткой EXE»). Я бы поместил файлы журнала в профиль пользователя или в другое место за пределами %ProgramFiles%
. Или, может быть, используйте event log
или даже базу данных для загрузки в Интернет, чтобы не оставить слишком много файлов.
Приемлемые остатки: по моему мнению, файлы журналов и другие пользовательские данные не следует пытаться удалять автоматически. Почему? Это пользовательские данные, другими словами: они принадлежат пользователю. Вы не можете просто удалить их сразу? Я бы просто оставил данные на месте на случай, если они захотят их проанализировать или переустановить приложение (последнее особенно важно для лицензионных ключей — вы их оставляете?).
WiX: WiX имеет несколько встроенных конструкций, помогающих удалять файлы и папки. Существуют встроенные варианты MSI (RemoveFile , RemoveFolder ), которые просто удаляют файлы по шаблону или имени. Затем есть RemoveFileEx , описанный Бобом Арнсоном (команда разработчиков WiX). Пожалуйста, прочитайте сообщение в блоге. Я считаю, что он может выполнять эту работу рекурсивно (все подпапки). Как вы понимаете, я редко использую эти конструкции, так как предпочитаю другие подходы к очистке. Откровенно говоря, я просто пытаюсь задокументировать процедуру очистки в формате PDF или в онлайн-статье KDB.
Ссылки:
Это довольно исчерпывающий ответ. Я согласен оставить мои лог-файлы нетронутыми. Спасибо! P.S. Я попытался запланировать действие после InstallFinilize только для проверки, и оно действительно работает, поэтому, несмотря на то, что я не тестировал сценарий блокировки, я почти уверен, что вы правы.
Это только кажется, что работает после InstallFinalize
. Действие не будет выполняться с повышенными правами после InstallFinalize
, поэтому, если оно попытается сделать что-то, требующее повышенного доступа, оно потерпит неудачу. Возможно, это работает, когда вы запускаете всю настройку с повышенными правами, запуская ее от имени администратора. Сбой проявляется, когда вы запускаете установку, когда в систему входит обычная учетная запись пользователя (да, это возможно с помощью политики или через системы распространения). После InstallFinalize
действие также становится немедленным — это означает, что оно выполняется напрямую и, возможно, дважды (в зависимости от некоторых технических особенностей) во время последовательности установки.
Удаление целых папок редко является хорошей идеей. MSI сделает это самостоятельно, если папка пуста. Какие файлы вы удаляете? Лог-файлы?