Composite MSI installations
How to bundle several MSI installations into one EXE file and execute them consecutively
Первоначальной целью было создание EXE-шника, который бы запускал подряд две MSI инсталляции. Для такой цели мог бы подойти архиватор, который поддерживает SFX архивы и возможность настроить запуск приложения после завершения распаковки. Самый распостраненный из них - 7zip. Но есть одна проблема - инсталляций несколько, а задать можно лишь один выполняемый файл. Это ограничение можно обойти несколькими путями:
- Написать bat-файл (или использовать любой другой скриптовый язык, который поддерживает Windows), из которого будет произведена нужная последовательность запусков инстялляций.
В случае bat-файла есть существенный недостаток - консольное окно. В случае скриптового сценария есть вероятность, что они в системе запрещены.
- Написать программу, которая выполнит последовательные запуски инстялляционных файлов.
- Использовать упаковщик, который поддерживает собственный язык сценариев.
Таким упаковщиком является NSIS. Об этом способе я расскажу подробнее, пожалуй.
NSIS MSI installations bundling
Предполагается, что NSIS уже установлен в системе. Я просто приведу пример файла MyBundle.nsi
, который собирает нужный EXE-шник:
# Our installation name Name 'MyInstallationsBundle' # Output exe-file name !ifndef OUTPUT_FILE !error "You must define OUTPUT_FILE" !endif # Path to the first MSI file !ifndef INSTALLATION1_MSI !error "You must define INSTALLATION1_MSI" !endif # Path to the second MSI file !ifndef INSTALLATION2_MSI !error "You must define INSTALLATION2_MSI" !endif OutFile "${OUTPUT_FILE}" # Vista UAC support RequestExecutionLevel admin AutoCloseWindow true # No GUI SilentInstall silent Section "" # Set current directory to TEMP SetOutPath $TEMP # Extract INSTALLATION?_MSI to TEMP and rename it to Install?.msi File /oname=Install1.msi "${INSTALLATION1_MSI}" File /oname=Install2.msi "${INSTALLATION2_MSI}" # Execute msiexec ExecWait 'msiexec /i "$TEMP\Install1.msi" /qr' ExecWait 'msiexec /i "$TEMP\Install2.msi"' SectionEnd
Для гибкости имя выходного файла и пути к инсталляциям не зашиты в скрипт, а передаются билд машиной.
Командная строка сборки выглядит следующим образом:
nsis.exe /NOCD -DOUTPUT_FILE="MyBundle.exe" -DINSTALLATION1_MSI="MyProduct1Install.msi" -DAUTOUPGRADE_MSI="MyProduct2Install.msi" MyBundle.nsi
How to join several MSI installations into one MSI
Первое, что приходит в голову, - запихнуть один MSI файл в другой и выполнить его запуск через Custom Action. Но, не судьба - A system-wide mutex protects the InstallExecuteSequence. The result of this is that only one installation per system can enter the execute sequence. So you cannot launch other installer packages from the execute sequence
. После этого сразу же приходит в голову засунуть этот Custom Action в InstallUISequence, но эта последовательность пропускается в случае тихой инсталляции
, без показа пользовательского интерфейса.
Погуглив на тему nested MSI installation я нашел документик How to create a nested .msi package. Оказывается, есть некий Custom action type 7 - Nested installation of a product residing in the installation package. То, что доктор прописал.
Для создания MSI файлов у нас используется WiX, который не поддерживает Custom action type 7. Вероятно это связано со следующим:
Concurrent Installations, also called Nested Installations, is a deprecated feature of the Windows Installer. Applications installed with concurrent installations can eventually fail because they are difficult for customers to service correctly. Do not use concurrent installations to install products that are intended to be released to the public. Concurrent installations can have limited applicability in controlled corporate environments when used to install applications that are not intended for public release. The concurrent installations documentation is provided for package authors that wish to use concurrent installations with applications that are not for public distribution.
Выхода три:
- Использовать Install Shield, который поддерживает Custom action type 7.
- Написать скрипт, который откроет Installation1.msi и выполнит действия, указанные в документе How to create a nested .msi package.
- Использовать первый подход (EXE-шник, который бы запускал подряд две MSI инсталляции) плюс некоторые хитрости. Дальше - о них.
How to run a nested MSI installation through msiexec
Напомню, что A system-wide mutex protects the InstallExecuteSequence
. Это значит, что нужно запустить Installation2.msi
после завершения Installation1.msi
. Сделать это можно многими способами, например через Asynchronous Custom Action. Основная проблема - дождаться освобождения блокировки и только после этого произвести запуск Installation2.msi
.
Получается, нужно написать программу (скрипт), которая подождет освобождения мьютекса _MSIExecute и запустит Installation2.msi
. Программа может попытаться открыть именованый мьютекс _MSIExecute и подождать его освобождения (не пробовал) либо подождать завершения процесса msiexec. В последнем случае через командную строку нужно передать PID (Process ID) msiexec. Windows Installer поддерживает свойство ClientProcessID, значение которого можно без проблем передать, как аргумент командной строки (использовать конструкцию [ClientProcessID] в командной строке запуска приложения).
5 коммент.:
Подскажите, пожалуйста, а как запихать один msi в другой?
Смысл вопроса непонятен. Если просто запихать - так же, как и любой другой файл. Или застримить в специальную таблицу, где хранятся dll-ки с вызываемыми функциями. Вариантов много, вопрос в цели запихивания?
Хм.. нам в продукте нужно инсталлить еще один доп. компонент по выбору пользователя. В последних требованиях пришло, что этот продукт должен удаляться отдельно от основного продукта, т.е. иметь отдельную Uninstall string. Первое, что приходит - отдельный инсталлятор и nested msi. Но много ограничений и неудобств. Причем есть требования - инсталлер не может быть ехе-шником (т.е. может вызываться с пом. MSI API), соответственно нельзя написать враппер и т.д.....
Не подскажете, может есть какие опции добавления сепаратных uninstall-ов для разных компонентов? Если еще через wix можно было бы...
спасибо :)
Если инсталляция с интерфейсом - то можно добавить Сustom Action в InstallUISequence. Блокирование mutex-а происходит только для InstallExecuteSequence. Этот Сustom Action должен, соответственно, достать MSI из MSI и запустить его.
Если речь идет о компонентах, то для этих целей есть Maintenance Mode. но запись в программах будет одна.
When some one searches for his vital thing, thus he/she needs to be available
that in detail, so that thing is maintained over here.
Also see my website - GFI Norte
Отправить комментарий