Как изменить структуру папок при извлечении 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 для справки)

Конечно, было бы проще переместить файлы после извлечения. Вы можете скопировать базу данных во временный файл, открыть ее для редактирования и манипулировать таблицами, прежде чем открывать ее как пакет и извлекать. Вы также можете сделать это с помощью обновления таблиц (временных таблиц) в памяти без фиксации на диске.

Другие вопросы по тегам