1

私はここで非常に深いところにいるので、私が何について話しているのか本当にわからないことをお詫びします.

私の目的は、既存の msi を取得し、それにいくつかの変更を加えてから、msi を元の状態のままにして変換を作成することです。他の多くの質問で示唆されているように、私は DTF (WiX の一部) を使用しています。

私の問題は、変換を作成するために 2 つのデータベース オブジェクトが必要であることに起因しています。変更されたデータベースと参照。最初のオブジェクトがロックしているため、同じファイルから 2 つのオブジェクトを作成することはできません。単純なオプションは、一時ディレクトリにファイルのコピーを作成し、新しいファイルパスから新しいオブジェクトを作成することです。ただし、プログラムは VM、ローカル ストレージ、およびネットワーク ストレージのさまざまな組み合わせで使用される可能性があるため、変換を保存する場合を除き、ディスクへの書き込みは避けたいと考えています。

私が収集したことによると、DTF ではハンドルからデータベース オブジェクトを作成できます。そのため、私の現在のアプローチは、何らかの方法でハンドルを使用してメモリ内に msi のコピーを作成し、それをデータベース コンストラクターに渡して一時オブジェクトを作成することです。変換を作成する前に変更を加えることができます。

ただし、これを達成する方法がわかりません。それが可能かどうかさえわかりません。MemoryMappedFile は開始するのに適した場所のように思えましたが、ファイルから作成する場合は永続的であり、ファイルに基づいて非永続的な mmf を作成する方法や、非永続的な mmf を作成してから読み取る方法がわかりません。それにmsi。

ディスク上に msi が 1 つしかないトランスフォームを作成する実行可能な方法はありますか? 私は明らかに私の深みから外れているので、ディスクへの書き込みを受け入れるだけのアイデア/ガイダンス/アピールを絶対に受け入れてください。

4

3 に答える 3

0

Here is how I do it. I copy the base MSI to a temp file, modify it and then generate the transform using the two files. Not sure why this would all need to be done in memory.

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

ここで立ち往生している可能性があると思います。基になる Windows インストーラー データベース API は、変更のために .msi ファイルを開くと、ファイルをロックします。これにより、他のハンドルが .msi ファイルに対して開かれなくなります。

ただし、試すことが 1 つあります。これが DTF で可能かどうかはわかりません (ネイティブ コードでそれを試みる方法は知っています) が、:

  1. .msi ファイルを編集用に開きます (直接モードとトランザクション モードの両方を試してみてください。一方は機能しませんが、他方は機能しません)。

  2. である文字列 (はい、文字列) を作成します"#" + the numeric value of the datbase handle。ネイティブ コードでは、基本的にprintf("#%u", hDatabase);. オブジェクトの DTF を使用すると、同じ結果が得られる場合がありString.FormatますIntPtr handleDatabase

  3. #HANDLENUMBER今回は、文字列を読み取り専用としてオープン データベース API に渡します。

  4. 最初のハンドルでデータベースを変更します。

  5. 変換を生成してみてください。

それでもうまくいかない場合は、他にもいくつか試してみることができます。最初に、元のハンドルを読み取り専用として開き、手順 4 でデータベースをトランザクションまたはダイレクトとして開きます (基本的にそれらを切り替えます)。それでもうまくいかない場合は、ステップ 5 の前にデータベースをコミットしてみてください。

いずれにせよ、上記が機能しない場合、利用可能な API で目的を達成することは不可能であると私は確信しています。幸運を!

于 2013-03-18T13:46:03.490 に答える
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 に答える