1

我在这里非常深入,所以请接受我的歉意,因为我不知道我在说什么。

我的目标是采用现有的 msi,对其进行一些更改,然后从中创建一个转换,使 msi 保持其原始状态。正如许多其他问题所建议的那样,我正在使用 DTF(WiX 的一部分)。

我的问题源于我需要两个数据库对象来创建转换;更改的数据库和参考。显然我不能从同一个文件创建两个对象,因为第一个对象锁定了它。最简单的选择是在临时目录中创建文件的副本并从新文件路径创建新对象。但是,除了保存转换之外,我真的想避免写入磁盘,因为该程序可能与不同的 VM、本地存储和网络存储混合使用。

根据我的收集,DTF 确实允许您从句柄创建数据库对象,因此我目前的方法是以某种方式在内存中使用句柄创建 msi 的副本,然后将其传递给数据库构造函数以创建一个临时对象我可以在创建转换之前对其进行更改。

不过,我不知道如何实现这一目标,我什至不确定这是否可能。MemoryMappedFile 似乎是一个不错的起点,但是当从文件创建一个文件时,它是持久的,我不知道如何基于文件创建非持久 mmf 或创建非持久 mmf 然后读取微星进去。

是否有任何可行的方法来创建磁盘上只有一个 msi 的转换?绝对欢迎任何想法/指导/呼吁接受写入磁盘,因为我显然超出了我的深度。

4

3 回答 3

0

这是我的做法。我将基本 MSI 复制到一个临时文件,对其进行修改,然后使用这两个文件生成转换。不知道为什么这一切都需要在内存中完成。

private void GenerateTransform(string baseMSI, string outputMST)
{
    string tempMSI = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), Guid.NewGuid().ToString() + ".msi");
    File.Copy(baseMSI, tempMSI, true);

    using (var baseDatabase = new Database(baseMSI, DatabaseOpenMode.ReadOnly))
    {
        using (var tempDatabase = new Database(tempMSI, DatabaseOpenMode.Direct))
        {
            // Do Stuff Here

            // Finally, Generate Transform
            tempDatabase.GenerateTransform(baseDatabase, outputMST);
            tempDatabase.CreateTransformSummaryInfo(baseDatabase, outputMST, TransformErrors.None, TransformValidations.None);
        }
    }

    File.Delete(tempMSI);
}
于 2013-03-18T14:16:47.233 回答
0

我尚未对其进行测试,但也许您可以使用以下方法创建您的 MSI 副本:

Handle copyOfMSI = CreateFile(..., dwShareMode=FILE_SHARE_WRITE, ..., dwFlagsAndAttributes=FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE)`

将您的 MSI 写入其中,不要关闭 copyOfMSI,从该文件开始工作,最后关闭 copyOfMSI。

于 2013-03-18T14:58:13.173 回答
0

我相信你可能会被困在这里。如果您打开 .msi 文件进行修改,底层的 Windows Installer 数据库 API 将锁定它。这将防止任何其他句柄被打开到 .msi 文件。

但是,有一件事要尝试。我不确定 DTF 是否可行(我知道如何在本机代码中尝试它)但是:

  1. 打开 .msi 文件进行编辑(您需要尝试直接和事务模式,因为其中一种可能在另一种不适用的情况下工作)。

  2. 创建一个字符串(是的,一个字符串),即"#" + the numeric value of the datbase handle. 在本机代码中,您基本上可以执行printf("#%u", hDatabase);. 使用对象的String.FormatDTF可能会得到相同的结果。IntPtr handleDatabase

  3. #HANDLENUMBER这次将字符串以只读方式传递给打开的数据库 API。

  4. 使用第一个句柄修改数据库。

  5. 尝试生成变换。

如果这不起作用,您可以尝试许多其他方法。首先,以只读方式打开原始句柄,然后在步骤 4 中以事务或直接方式打开数据库(基本上是切换它们)。如果这不起作用,请尝试在第 5 步之前提交数据库。但是,提交数据库可能需要写入磁盘(因此是临时文件)。

无论如何,如果上述方法不起作用,我非常确信使用可用的 API 无法实现您想要的。祝你好运!

于 2013-03-18T13:46:03.490 回答