将msi复制到内存,然后从中创建Database对象

时间:2013-03-18 07:31:23

标签: c# windows-installer dtf

我非常喜欢这里,所以请接受我的道歉,因为我不知道自己在做什么。

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

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

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

但是,我不知道如何实现这一点,我甚至不确定它是否可行。 MemoryMappedFile似乎是一个很好的起点,但是当从文件创建一个它是持久的时候我无法弄清楚如何基于文件创建非持久性mmf或者创建非持久性mmf然后阅读msi进入它。

有没有可行的方法来创建磁盘上只有一个msi的转换?完全接受任何想法/指导/上诉,只接受写入磁盘,因为我显然不在我的深处。

3 个答案:

答案 0 :(得分:0)

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

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

  1. 打开.msi文件进行编辑(您需要尝试直接和事务处理模式,因为一个可能在另一个没有的情况下工作)。

  2. 创建一个"#" + the numeric value of the datbase handle的字符串(是的,一个字符串)。在本机代码中,您基本上可以执行printf("#%u", hDatabase);。使用String.Format对象的DTF IntPtr handle的{​​{1}}可能会让您一样。

  3. 这次将Database字符串以只读方式传递给开放数据库API。

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

  5. 尝试生成转换。

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

    无论如何,如果上述方法不起作用,我相信使用可用的API无法实现您的目标。祝你好运!

答案 1 :(得分: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);
}

答案 2 :(得分:0)

我还没有测试过,但也许您可以使用以下方法创建MSI的副本:

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

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