Доступ к содержимому упакованного файла XML в настраиваемом действии на этапе пользовательского интерфейса установщика - PullRequest
0 голосов
/ 31 марта 2020

Я поддерживаю установщик WiX, у которого уже есть работающий пользовательский интерфейс и который выполняет несколько пользовательских действий на этапе пользовательского интерфейса. Текущее и рабочее состояние зависит от количества значений свойств, жестко закодированных в файле .wxs. Я хотел бы изменить это: вместо жесткого кодирования значений, которые я хотел бы собирать динамически во время установки.

Мне нужно, чтобы это происходило уже во время отображения пользовательского интерфейса, поскольку значения свойств влияют на логику пользовательского интерфейса. c. Теперь проблема в том, что фрагменты значений свойств должны поступать из файла XML, который упакован внутри установщика. Файл XML будет также установлен на целевом компьютере после завершения этапа пользовательского интерфейса.

На данный момент я нашел единственный способ получить доступ к файлу, упакованному в установщике, из пользовательского действия: получая его путь с Session.GetTargetPath(), как показано в следующем фрагменте C#:

[CustomAction]
public static ActionResult GetInfoFromXml(Session session)
{
    string xmlFolderPath = session.GetTargetPath("XmlFolder");

    [...]  // deserialize and process the file
}

Это происходит со следующим сообщением в журнале установщика:

Exception thrown by custom action:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: The directory name is invalid. XmlFolder
   at Microsoft.Deployment.WindowsInstaller.Session.GetTargetPath(String directory)

После некоторых размышлений ошибка кажется предсказуемой: пользовательское действие выполняется в фазе пользовательского интерфейса установщика, поэтому ничего еще не установлено и поэтому GetTargetPath не может вернуть ничего полезного.

Итак, вопрос: как я могу получить доступ к содержимому файл XML из моего настраиваемого действия, выполняемого на этапе пользовательского интерфейса установщика?

Если я смогу достичь своей цели, дважды упаковав файл XML, скажем, один раз для его установки на цель машина, и второй раз только для того, чтобы обработать его пользовательским действием, это было бы хорошо. Я не знаю, как это сделать, или, если это вообще возможно, я все еще слишком большой новичок в WiX.

Примечание: я также изучал "сбор" содержимого XML файл во время сборки, т. е. как сгенерировать фрагмент .wxs из файла XML во время сборки, но, похоже, в WiX нет простого способа сделать это.

1 Ответ

0 голосов
/ 02 апреля 2020

Решением моей проблемы было

  1. Добавьте файл XML в двоичную таблицу установщика.
  2. Получите данные из двоичной таблицы в пользовательском действии, преобразовать данные в строку, а затем десериализовать из этой строки.

Вот запись двоичной таблицы из .wxs:

<Binary Id="XmlFile" SourceFile="foo.xml" />

Это часть настраиваемого действия:

[CustomAction]
public static ActionResult GetInfoFromXml(Session session)
{
    string xmlFileContent = GetStringDataFromBinaryTable(
        session,
        "XmlFile");

    [...]  // deserialize and process the XML file content
}

А вот обобщенный c метод многократного использования, который я написал, который извлекает строковые данные из двоичной таблицы:

using Microsoft.Deployment.WindowsInstaller;
using System.IO;

public static string GetStringDataFromBinaryTable(Session session, string binaryTableEntryId)
{
  const string BinaryTableName = "Binary";
  const string NameColumnName = "Name";
  const string DataColumnName = "Data";

  Database db = session.Database;

  string selectQuery = string.Format(
    "SELECT `{2}` FROM `{0}` WHERE `{0}`.`{1}` = '{3}'",
    BinaryTableName,
    NameColumnName,
    DataColumnName,
    binaryTableEntryId);
  View view = db.OpenView(selectQuery);
  view.Execute();

  Record record = view.Fetch();

  Stream stream = record.GetStream(DataColumnName);
  StreamReader streamReader = new StreamReader(stream);
  string dataAsString = streamReader.ReadToEnd();

  view.Close();

  return dataAsString;
}
...