Как изменить структуру папок при извлечении MSI с помощью WiX DTF
Мне нужно извлечь файлы из MSI в папку, но изменить структуру каталогов файлов, все из приложения C# (то есть: не путем установки администратора или любой другой установки MSI). Концептуально я хочу "разархивировать" встроенную кабину MSI в папку по своему выбору. Для извлечения я использую библиотеки WiX 3.6 DTF, но не могу определить, как изменить структуру папок.
Так, например, если бы я запустил установщик MSI, целевой папкой для "Component1" было бы c:\Program Files(x86)\Company Name\Demo Product Installer\Component1\
, но во время выполнения в моем приложении экстрактора, я хотел бы поставить изменить это на c:\SomeOtherPlace\Demo Product Installer\Component1\
предпочтительно путем изменения APPLICATIONFOLDER
путь к каталогу (см. ниже).
Для MSI я определил структуру каталогов следующим образом:
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONFOLDER" Name="Company Name">
<Directory Id="ProductFolder" Name="Demo Product Installer">
<Directory Id="Cmp1Folder" Name="Component1" />
<Directory Id="Cmp2Folder" Name="Component2" />
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
Затем в коде, который должен извлечь файлы, я сделал это:
var msiFilePath = "myInstallerFile.msi";
var targetFolder = @"c:\SomeOtherPlace\";
using (var msiPackage = new InstallPackage(msiFilePath, DatabaseOpenMode.ReadOnly))
{
msiPackage.WorkingDirectory = targetFolder;
var dirMapping = msiPackage.Directories;
if (dirMapping.ContainsKey("APPLICATIONFOLDER"))
{
//This doesn't work, but represents what I hope to do:
var oldInstallPath = dirMapping["APPLICATIONFOLDER"];
oldInstallPath.TargetPath = targetFolder;
}
msiPackage.UpdateDirectories();
msiPackage.ExtractFiles();
msiPackage.Close();
}
Есть ли способ изменить структуру папок, как это во время выполнения, используя объекты DTF? Я знаю, что могу просто переместить файлы после факта, но если бы я мог сделать это таким образом, это было бы намного чище.
2 ответа
Основываясь на подсказке ("Вы можете сделать это в обновлениях памяти таблиц...") из ответа Киртофера, я смог найти рабочее решение:
var msiFilePath = "myInstallerFile.msi";
var targetFolder = @"c:\SomeOtherPlace\";
using (var msiPackage = new InstallPackage(msiFilePath, DatabaseOpenMode.Transact))
{
msiPackage.WorkingDirectory = targetFolder;
var dirMapping = msiPackage.Directories;
if (dirMapping.ContainsKey("APPLICATIONFOLDER"))
{
//**** Modified code starts here ***//
// Changed the "APPLICATIONFOLDER" entry from "Company Name" to ".",
// which is a special value to denote the extracted folder.
var record = new Record(".", "APPLICATIONFOLDER");
msiPackage.Execute("UPDATE `Directory` SET `DefaultDir` = ? WHERE `Directory` = ?", record);
//**** Modified code ends here ***//
}
msiPackage.UpdateDirectories();
msiPackage.ExtractFiles();
//Close **without** calling Commit() to ensure changes are not persisted
msiPackage.Close();
}
Обратите внимание, что я также изменил DatabaseOpenMode на Transact.
Конечно, если вы хотите сделать более сложные изменения в структуре папок, вам придется изменить / вставить / удалить дополнительные записи из таблицы Directory. (см. http://msdn.microsoft.com/en-us/library/windows/desktop/aa368295%28v=vs.85%29.aspx для справки)
Конечно, было бы проще переместить файлы после извлечения. Вы можете скопировать базу данных во временный файл, открыть ее для редактирования и манипулировать таблицами, прежде чем открывать ее как пакет и извлекать. Вы также можете сделать это с помощью обновления таблиц (временных таблиц) в памяти без фиксации на диске.