Программное построение MSI
Я хотел бы создать программу на C#, которая создает MSI на основе ряда параметров. Например, в зависимости от пользовательских настроек будут включены определенные файлы или заданы параметры времени выполнения.
Может ли кто-нибудь указать мне какую-либо документацию, которая может помочь, или дать мне представление, с чего я мог бы начать с чего-то подобного?
4 ответа
Если вы действительно хотите сделать это в коде, вам нужно взглянуть на API установщика Windows. Тем не менее, Wix создал хороший набор управляемых инструментов, который значительно упростит разработку MSI с использованием языка XML. Они также обернули многие API-интерфейсы установщика Windows в управляемые оболочки, но чтобы получить полную мощность установщика Windows, вам нужно ознакомиться с документацией по API.
Я использовал WixSharp (WiX#) только по причинам, которые вы описываете. Я нашел установщик, управляемый XML, слишком уродливым и неинтуитивным, чтобы иметь дело с ним, т. Е. Редактировать файлы XML как способ создания установщика. Я копался в C# на основе WiX # в качестве более доступной альтернативы. В моем случае мне нужно было создать MSI для установки DLL-библиотеки.NET (не в GAC) на сервер, а затем зарегистрировать ее для COM Interop.
Дополнительная информация на домашней странице CodePlex для Wix#: http://wixsharp.codeplex.com/
Для типа установки, который описывает OP, может показаться применимой концепция MSI/WiX "Функции", например, когда пользователь может установить флажок для установки или пропустить определенные функции ("функция" может быть набором файлов / программы, набор записей реестра и т. д.)
В установщике WiX # вы объявляете "Feature" с "ID", например, двоичные файлы, документы, registryEntries и т. Д. В верхней части кода установщика C#, а затем ссылаетесь на этот Feature Feature при объявлении дополнительных компонентов установщика. (см. код Wix# "AllInOne" в папке "Samples", которая поставляется вместе с установкой Wix#),
Feature binaries = new Feature("MyApp Binaries");
Feature docs = new Feature("MyApp Documentation");
...
new File(binaries, @"AppFiles\MyApp.exe",
new FileShortcut(binaries, "MyApp", @"%ProgramMenu%\My Company\My Product"),
new FileShortcut(binaries, "MyApp", @"%Desktop%")),
Обратите внимание, что идентификатор компонента "двоичные файлы" является первым параметром в объявлении компонентов File и FileShortcut, т. Е. "Новый файл (binaries, ...)", и связывает эти компоненты для включения в идентификатор функции "двоичные файлы".
Кроме того, установщики MSI позволяют указывать идентификаторы функций в командной строке, например,
msiexec / i install.msi ADDLOCAL = двоичные файлы
Также см. Этот пост: WIX: Как выбрать функции из командной строки
Хотя у WiX есть способы взглянуть на целевую систему и определить, что устанавливать, я не видел примеров Wix#, которые кажутся интуитивно понятными, за исключением возможного использования пользовательских действий (которые поддерживает Wix#). Один из способов адаптировать поведение установщика для целевой системы будет использоваться Custom Actions для установки свойства, как в примере Wix#, "Условная установка" в развертывании Wix#.
//setting property to be used in install condition
new Property("INSTALLDESKTOPSHORTCUT", "no"),
new ManagedAction(@"MyAction", Return.ignore, When.Before, Step.LaunchConditions, Condition.NOT_Installed, Sequence.InstallUISequence));
Который ссылается на этот код ранее в установщике Wix#:
new Dir(@"%Desktop%",
new ExeFileShortcut("MyApp", "[INSTALLDIR]MyApp.exe", "")
{
Condition = new Condition("INSTALLDESKTOPSHORTCUT=\"yes\"") //property based condition
}),
Обратите внимание, что "Условие" в фигурных скобках установлено для проверки свойства "INSTALLDESKTOPSHORTCUT" на значение "да", которое устанавливается в результате пользовательского действия. Код C# для настраиваемого действия выглядит следующим образом.
public class CustomActions
{
[CustomAction]
public static ActionResult MyAction(Session session)
{
if (DialogResult.Yes == MessageBox.Show("Do you want to install desktop shortcut", "Installation", MessageBoxButtons.YesNo))
session["INSTALLDESKTOPSHORTCUT"] = "yes";
return ActionResult.Success;
}
}
Другой способ, для набора навыков C#, состоит в том, чтобы запустить программу установки msi с помощью программы C#, которая делает что-то вроде этого:
- Посмотрите на настройки пользователя целевой системы, определите, какие функции подходят для установки в этой системе.
- Соберите и отформатируйте командную строку msiexec и параметры объектов для выбранных объектов.
- Выполните командную строку MSIExec.
Возможно, есть и другие "более аккуратные" способы сделать это, например, с помощью пользовательских действий и т. Д. Однако, исходя из набора навыков C#, этот способ доступен и может помочь с кривой обучения Windows Installer/WiX. Что я нашел, так как работал над установщиками Wix#, так это то, что это помогло мне постепенно освоить некоторые программы установки WiX и Windows. Я часто ищу, как выполнить определенную задачу развертывания в WiX, а затем работаю над переводом Wix-пути в Wix#, чтобы заставить Wix# генерировать нужный XML в создаваемом им файле.wxs.
В тех случаях, когда я не могу понять, как заставить Wix# выполнить определенную задачу развертывания, я часто могу использовать опору простого включения операторов WiX XML в файл.wxs, сгенерированный Wix#, например, путем ручного редактирования файл.wxs.
Например, WiX и Wix#, способ предоставления определенного диска и пути, который не является одним из "поддерживаемых" мест назначения, не является интуитивно понятным. Я обнаружил, что добавление этого фрагмента xml в сгенерированный файл.wxs из Wix#, а затем ручной запуск Candle и затем Light сделали свое дело.
Я вспоминаю, что в процессе выполнения было несколько примеров того, как заставить код Wix# C# программно включать XML в операторы.wxs, а затем скомпилировать.wxs для генерации msi. Я обновлю этот ответ, если снова найду пример Wix#.
Обновление Я нашел пример кода... есть пара в примерах кода Wix# в папке примеров Wix#, включенной в Wix#. Однако... они работали не так, как я хотел, и включали дополнительные классы Wix# и объекты, с которыми я еще не был знаком. Я хотел работать с выводом Wix# в виде текста XML, используя "стандартные" наборы инструментов XML C#, а не классы, специфичные для Wix#. Итак, я попытался выполнить синтаксический анализ XML-документа.wxs и не смог использовать XPath для перехода туда, куда я хотел вставить дополнительные операторы WiX XML. (Может быть, я напишу так вопрос для помощи с этим). Тем не менее, я выполнил то, что хотел, используя текстовую подстановку WiX XML, которая рассматривается как текстовая строка. Ниже то, что я получил, чтобы успешно работать.
Код выполняет назначение делегата событию Compiler.WixSourceSaved, и это событие запускается как часть того, что происходит, когда метод "Compiler.BuildMsi" вызывается в коде Wix#. После прочтения файла.wxs, который создается (но до того, как файл MSI был создан из wxs), я обновляю текст в файле, чтобы он содержал строки XML, которые я хочу включить.
Основная последовательность событий Wix# затем продолжается и встраивает измененные wxs в окончательный MSI.
// ...
internal class Script
static string myWIX_SET_DIRECTORY_STATEMENT = " <SetDirectory Id=\"INSTALLDIR\" Value=\"D:\\Program Files\\DOL\\WA.DOL.HQSYS.ExecECL\" />";
static string myWIX_INSERT_AFTER_TEXT = " <InstallExecuteSequence >";
public static void Main()
{
// ... (your other Wix# code goes here...)
// Hook an event to Wix# save of .wxs file to post-process the .wxs
Compiler.WixSourceSaved += PostProcessWxsXMLOutput;
// Trigger the MSI file build
Compiler.BuildMsi(project);
}
/// <summary>
/// Post-process the Wix .wxs file before compiling it into an MSI
/// </summary>
/// <param name="wxsFileName"></param>
private static void PostProcessWxsXMLOutput(string wxsFileName)
{
StreamReader sr = new StreamReader(wxsFileName);
string myWixDocument = sr.ReadToEnd();
sr.Close();
string myProcessedWixDocument = WiXHelpers.InsertFragmentInWiXDocument(myWixDocument, myWIX_INSERT_AFTER_TEXT, myWIX_SET_DIRECTORY_STATEMENT);
StreamWriter sw = new StreamWriter(wxsFileName);
sw.Write(myProcessedWixDocument);
sw.Close();
}
Примечание. Файл.wxs удаляется после завершения BuildMsi. Чтобы принудительно сохранить полученный файл.wxs, вам необходимо добавить строку в код Wix# после строки Compiler.BuildMsi следующим образом:
Compiler.BuildWxs(Project)
На самом деле это перезапускает событие WixSourceSaved, которое затем вызывает мой делегат PostProcessXMLOutput, который генерирует новую, идентичную содержимому копию файла.wxs. На этот раз файл wxs не удаляется автоматически. Полученный файл wxs также будет иметь более позднюю временную метку, чем соответствующий файл MSI из сборки.
Проверьте WixSharp - набор библиотек C#, который позволяет выразить вашу установку в коде C#. Затем он превращается в файл WiX (XML), который по очереди компилируется и связывается для создания стандартного файла MSI (установщика Windows).
Я бы проверил WiX. У него довольно крутая кривая обучения, но он будет генерировать msi как часть цикла сборки вашего проекта.