Migrate PInvoke out of Core to Core.Native
Rob Mensching committed
Mar 16, 2021 at 10:49 UTC
60f75abcd1fe49052c118a2597ac59a82c372b64
42 files changed
+104
-5086
src/WixToolset.Core.Burn/Bundles/BurnCommon.cs
+12
-13
@@ -111,7 +111,7 @@ namespace WixToolset.Core.Burn.Bundles
111
/// <param name="fileExe">File to modify in-place.</param>
112
public BurnCommon(IMessaging messaging, string fileExe)
113
{
114
- this.messaging = messaging;
114
+ this.Messaging = messaging;
115
this.fileExe = fileExe;
116
}
117
@@ -130,7 +130,7 @@ namespace WixToolset.Core.Burn.Bundles
130
public UInt32 AttachedContainerAddress { get; protected set; }
131
public UInt32 AttachedContainerSize { get; protected set; }
132
133
- protected IMessaging messaging { get; }
133
+ protected IMessaging Messaging { get; }
134
135
public void Dispose()
136
{
@@ -147,12 +147,11 @@ namespace WixToolset.Core.Burn.Bundles
147
/// <param name="size">Optional count of bytes to copy. 0 indicates whole input stream from current should be copied.</param>
148
protected static int CopyStream(Stream input, Stream output, int size)
149
{
150
- byte[] bytes = new byte[4096];
151
- int total = 0;
152
- int read = 0;
150
+ var bytes = new byte[4096];
151
+ var total = 0;
152
do
153
{
155
- read = Math.Min(bytes.Length, size - total);
154
+ var read = Math.Min(bytes.Length, size - total);
155
read = input.Read(bytes, 0, read);
156
if (0 == read)
157
{
@@ -185,21 +184,21 @@ namespace WixToolset.Core.Burn.Bundles
184
uint32 = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_MAGIC);
185
if (BURN_SECTION_MAGIC != uint32)
186
{
188
- this.messaging.Write(ErrorMessages.InvalidBundle(this.fileExe));
187
+ this.Messaging.Write(ErrorMessages.InvalidBundle(this.fileExe));
188
return false;
189
}
190
191
this.Version = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_VERSION);
192
if (BURN_SECTION_VERSION != this.Version)
193
{
195
- this.messaging.Write(ErrorMessages.BundleTooNew(this.fileExe, this.Version));
194
+ this.Messaging.Write(ErrorMessages.BundleTooNew(this.fileExe, this.Version));
195
return false;
196
}
197
198
uint32 = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_FORMAT); // We only know how to deal with CABs right now
199
if (1 != uint32)
200
{
202
- this.messaging.Write(ErrorMessages.InvalidBundle(this.fileExe));
201
+ this.Messaging.Write(ErrorMessages.InvalidBundle(this.fileExe));
202
return false;
203
}
204
@@ -266,7 +265,7 @@ namespace WixToolset.Core.Burn.Bundles
265
266
if (UInt32.MaxValue == wixburnSectionOffset)
267
{
269
- this.messaging.Write(ErrorMessages.StubMissingWixburnSection(this.fileExe));
268
+ this.Messaging.Write(ErrorMessages.StubMissingWixburnSection(this.fileExe));
269
return false;
270
}
271
@@ -274,7 +273,7 @@ namespace WixToolset.Core.Burn.Bundles
273
// the smallest alignment (512 bytes), but just to be paranoid...
274
if (BURN_SECTION_SIZE > BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_SIZEOFRAWDATA))
275
{
277
- this.messaging.Write(ErrorMessages.StubWixburnSectionTooSmall(this.fileExe));
276
+ this.Messaging.Write(ErrorMessages.StubWixburnSectionTooSmall(this.fileExe));
277
return false;
278
}
279
@@ -303,7 +302,7 @@ namespace WixToolset.Core.Burn.Bundles
302
// Verify the NT signature...
303
if (IMAGE_NT_SIGNATURE != BurnCommon.ReadUInt32(bytes, IMAGE_NT_HEADER_OFFSET_SIGNATURE))
304
{
306
- this.messaging.Write(ErrorMessages.InvalidStubExe(this.fileExe));
305
+ this.Messaging.Write(ErrorMessages.InvalidStubExe(this.fileExe));
306
return false;
307
}
308
@@ -338,7 +337,7 @@ namespace WixToolset.Core.Burn.Bundles
337
// Verify the DOS 'MZ' signature.
338
if (IMAGE_DOS_SIGNATURE != BurnCommon.ReadUInt16(bytes, IMAGE_DOS_HEADER_OFFSET_MAGIC))
339
{
341
- this.messaging.Write(ErrorMessages.InvalidStubExe(this.fileExe));
340
+ this.Messaging.Write(ErrorMessages.InvalidStubExe(this.fileExe));
341
return false;
342
}
343
src/WixToolset.Core.Burn/Bundles/BurnReader.cs
+6
-15
@@ -27,7 +27,7 @@ namespace WixToolset.Core.Burn.Bundles
27
28
private bool invalidBundle;
29
private BinaryReader binaryReader;
30
- private List<DictionaryEntry> attachedContainerPayloadNames;
30
+ private readonly List<DictionaryEntry> attachedContainerPayloadNames;
31
32
/// <summary>
33
/// Creates a BurnReader for reading a PE file.
@@ -43,13 +43,7 @@ namespace WixToolset.Core.Burn.Bundles
43
/// <summary>
44
/// Gets the underlying stream.
45
/// </summary>
46
- public Stream Stream
47
- {
48
- get
49
- {
50
- return (null != this.binaryReader) ? this.binaryReader.BaseStream : null;
51
- }
52
- }
46
+ public Stream Stream => this.binaryReader?.BaseStream;
47
48
internal static BurnReader Open(object inputFilePath)
49
{
@@ -64,7 +58,7 @@ namespace WixToolset.Core.Burn.Bundles
58
/// <returns>Burn reader.</returns>
59
public static BurnReader Open(IMessaging messaging, string fileExe)
60
{
67
- BurnReader reader = new BurnReader(messaging, fileExe);
61
+ var reader = new BurnReader(messaging, fileExe);
62
63
reader.binaryReader = new BinaryReader(File.Open(fileExe, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete));
64
if (!reader.Initialize(reader.binaryReader))
@@ -109,8 +103,7 @@ namespace WixToolset.Core.Burn.Bundles
103
cabinet.Extract(outputDirectory);
104
105
Directory.CreateDirectory(Path.GetDirectoryName(manifestPath));
112
- File.Delete(manifestPath);
113
- File.Move(manifestOriginalPath, manifestPath);
106
+ FileSystem.MoveFile(manifestOriginalPath, manifestPath);
107
108
XmlDocument document = new XmlDocument();
109
document.Load(manifestPath);
@@ -128,8 +121,7 @@ namespace WixToolset.Core.Burn.Bundles
121
string destinationPath = Path.Combine(outputDirectory, filePathNode.Value);
122
123
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
131
- File.Delete(destinationPath);
132
- File.Move(sourcePath, destinationPath);
124
+ FileSystem.MoveFile(sourcePath, destinationPath);
125
}
126
127
foreach (XmlNode payload in payloads)
@@ -193,8 +185,7 @@ namespace WixToolset.Core.Burn.Bundles
185
string destinationPath = Path.Combine(outputDirectory, (string)entry.Value);
186
187
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
196
- File.Delete(destinationPath);
197
- File.Move(sourcePath, destinationPath);
188
+ FileSystem.MoveFile(sourcePath, destinationPath);
189
}
190
191
return true;
src/WixToolset.Core.Burn/Bundles/BurnWriter.cs
+1
-1
@@ -80,7 +80,7 @@ namespace WixToolset.Core.Burn.Bundles
80
this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_MAGIC, BURN_SECTION_MAGIC);
81
this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_VERSION, BURN_SECTION_VERSION);
82
83
- this.messaging.Write(VerboseMessages.BundleGuid(bundleId));
83
+ this.Messaging.Write(VerboseMessages.BundleGuid(bundleId));
84
this.binaryWriter.BaseStream.Seek(this.wixburnDataOffset + BURN_SECTION_OFFSET_BUNDLEGUID, SeekOrigin.Begin);
85
this.binaryWriter.Write(bundleGuid.ToByteArray());
86
src/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs
+2
-1
@@ -8,6 +8,7 @@ namespace WixToolset.Core.Burn.Bundles
8
using System.Reflection;
9
using System.Text;
10
using System.Xml;
11
+ using WixToolset.Core.Native;
12
using WixToolset.Data;
13
using WixToolset.Data.Burn;
14
using WixToolset.Data.Symbols;
@@ -72,7 +73,7 @@ namespace WixToolset.Core.Burn.Bundles
73
74
this.Transfer = this.BackendHelper.CreateFileTransfer(bundleTempPath, this.OutputPath, true, this.BundleSymbol.SourceLineNumbers);
75
75
- File.Copy(stubFile, bundleTempPath, true);
76
+ FileSystem.CopyFile(stubFile, bundleTempPath, allowHardlink: false);
77
File.SetAttributes(bundleTempPath, FileAttributes.Normal);
78
79
var windowsAssemblyVersion = GetWindowsAssemblyVersion(this.BundleSymbol);
src/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs
+8
-13
@@ -1,10 +1,10 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3
namespace WixToolset.Core.Burn.Inscribe
4
{
5
using System.IO;
6
using WixToolset.Core.Burn.Bundles;
7
- using WixToolset.Extensibility;
7
+ using WixToolset.Core.Native;
8
using WixToolset.Extensibility.Data;
9
using WixToolset.Extensibility.Services;
10
@@ -23,19 +23,19 @@ namespace WixToolset.Core.Burn.Inscribe
23
24
public bool Execute()
25
{
26
- bool inscribed = false;
27
- string tempFile = Path.Combine(this.Context.IntermediateFolder, "bundle_engine_signed.exe");
26
+ var inscribed = false;
27
+ var tempFile = Path.Combine(this.Context.IntermediateFolder, "bundle_engine_signed.exe");
28
29
- using (BurnReader reader = BurnReader.Open(this.Context.InputFilePath))
29
+ using (var reader = BurnReader.Open(this.Context.InputFilePath))
30
{
31
- File.Copy(this.Context.SignedEngineFile, tempFile, true);
31
+ FileSystem.CopyFile(this.Context.SignedEngineFile, tempFile, allowHardlink: false);
32
33
// If there was an attached container on the original (unsigned) bundle, put it back.
34
if (reader.AttachedContainerSize > 0)
35
{
36
reader.Stream.Seek(reader.AttachedContainerAddress, SeekOrigin.Begin);
37
38
- using (BurnWriter writer = BurnWriter.Open(this.Messaging, tempFile))
38
+ using (var writer = BurnWriter.Open(this.Messaging, tempFile))
39
{
40
writer.RememberThenResetSignature();
41
writer.AppendContainer(reader.Stream, reader.AttachedContainerSize, BurnCommon.Container.Attached);
@@ -45,13 +45,8 @@ namespace WixToolset.Core.Burn.Inscribe
45
}
46
47
Directory.CreateDirectory(Path.GetDirectoryName(this.Context.OutputFile));
48
- if (File.Exists(this.Context.OutputFile))
49
- {
50
- File.Delete(this.Context.OutputFile);
51
- }
48
53
- File.Move(tempFile, this.Context.OutputFile);
54
- WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { this.Context.OutputFile }, 1);
49
+ FileSystem.MoveFile(tempFile, this.Context.OutputFile);
50
51
return inscribed;
52
}
src/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs
+18
-16
@@ -1,33 +1,40 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3
namespace WixToolset.Core.Burn.Inscribe
4
{
5
using System;
6
using System.IO;
7
using WixToolset.Core.Burn.Bundles;
8
+ using WixToolset.Core.Native;
9
using WixToolset.Extensibility.Data;
10
11
internal class InscribeBundleEngineCommand
12
{
13
public InscribeBundleEngineCommand(IInscribeContext context)
14
{
14
- this.Context = context;
15
+ this.IntermediateFolder = context.IntermediateFolder;
16
+ this.InputFilePath = context.InputFilePath;
17
+ this.OutputFile = context.OutputFile;
18
}
19
17
- private IInscribeContext Context { get; }
20
+ private string IntermediateFolder { get; }
21
+
22
+ private string InputFilePath { get; }
23
+
24
+ private string OutputFile { get; }
25
26
public bool Execute()
27
{
21
- string tempFile = Path.Combine(this.Context.IntermediateFolder, "bundle_engine_unsigned.exe");
28
+ var tempFile = Path.Combine(this.IntermediateFolder, "bundle_engine_unsigned.exe");
29
23
- using (BurnReader reader = BurnReader.Open(this.Context.InputFilePath))
24
- using (FileStream writer = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete))
30
+ using (var reader = BurnReader.Open(this.InputFilePath))
31
+ using (var writer = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete))
32
{
33
reader.Stream.Seek(0, SeekOrigin.Begin);
34
28
- byte[] buffer = new byte[4 * 1024];
29
- int total = 0;
30
- int read = 0;
35
+ var buffer = new byte[4 * 1024];
36
+ var total = 0;
37
+ var read = 0;
38
do
39
{
40
read = Math.Min(buffer.Length, (int)reader.EngineSize - total);
@@ -46,14 +53,9 @@ namespace WixToolset.Core.Burn.Inscribe
53
// TODO: update writer with detached container signatures.
54
}
55
49
- Directory.CreateDirectory(Path.GetDirectoryName(this.Context.OutputFile));
50
- if (File.Exists(this.Context.OutputFile))
51
- {
52
- File.Delete(this.Context.OutputFile);
53
- }
56
+ Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile));
57
55
- File.Move(tempFile, this.Context.OutputFile);
56
- WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { this.Context.OutputFile }, 1);
58
+ FileSystem.MoveFile(tempFile, this.OutputFile);
59
60
return true;
61
}
src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs
+1
-1
@@ -7,7 +7,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
7
using System.Globalization;
8
using System.Linq;
9
using System.Text.RegularExpressions;
10
- using WixToolset.Core.WindowsInstaller.Msi;
10
+ using WixToolset.Core.Native.Msi;
11
using WixToolset.Data;
12
using WixToolset.Data.Symbols;
13
using WixToolset.Data.WindowsInstaller;
src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
+1
-1
@@ -5,7 +5,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
5
using System;
6
using System.Globalization;
7
using System.IO;
8
- using WixToolset.Core.WindowsInstaller.Msi;
8
+ using WixToolset.Core.Native.Msi;
9
using WixToolset.Data;
10
using WixToolset.Data.Symbols;
11
using WixToolset.Data.WindowsInstaller;
src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs
deleted
-92
@@ -1,92 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Bind
4
-{
5
- using System;
6
- using System.Collections;
7
- using System.Globalization;
8
- using WixToolset.Core.Native;
9
- using WixToolset.Core.WindowsInstaller.Msi;
10
-
11
- /// <summary>
12
- /// Callback object for configurable merge modules.
13
- /// </summary>
14
- internal sealed class ConfigurationCallback : IMsmConfigureModule
15
- {
16
- private const int SOk = 0x0;
17
- private const int SFalse = 0x1;
18
- private Hashtable configurationData;
19
-
20
- /// <summary>
21
- /// Creates a ConfigurationCallback object.
22
- /// </summary>
23
- /// <param name="configData">String to break up into name/value pairs.</param>
24
- public ConfigurationCallback(string configData)
25
- {
26
- if (String.IsNullOrEmpty(configData))
27
- {
28
- throw new ArgumentNullException("configData");
29
- }
30
-
31
- string[] pairs = configData.Split(',');
32
- this.configurationData = new Hashtable(pairs.Length);
33
- for (int i = 0; i < pairs.Length; ++i)
34
- {
35
- string[] nameVal = pairs[i].Split('=');
36
- string name = nameVal[0];
37
- string value = nameVal[1];
38
-
39
- name = name.Replace("%2C", ",");
40
- name = name.Replace("%3D", "=");
41
- name = name.Replace("%25", "%");
42
-
43
- value = value.Replace("%2C", ",");
44
- value = value.Replace("%3D", "=");
45
- value = value.Replace("%25", "%");
46
-
47
- this.configurationData[name] = value;
48
- }
49
- }
50
-
51
- /// <summary>
52
- /// Returns text data based on name.
53
- /// </summary>
54
- /// <param name="name">Name of value to return.</param>
55
- /// <param name="configData">Out param to put configuration data into.</param>
56
- /// <returns>S_OK if value provided, S_FALSE if not.</returns>
57
- public int ProvideTextData(string name, out string configData)
58
- {
59
- if (this.configurationData.Contains(name))
60
- {
61
- configData = (string)this.configurationData[name];
62
- return SOk;
63
- }
64
- else
65
- {
66
- configData = null;
67
- return SFalse;
68
- }
69
- }
70
-
71
- /// <summary>
72
- /// Returns integer data based on name.
73
- /// </summary>
74
- /// <param name="name">Name of value to return.</param>
75
- /// <param name="configData">Out param to put configuration data into.</param>
76
- /// <returns>S_OK if value provided, S_FALSE if not.</returns>
77
- public int ProvideIntegerData(string name, out int configData)
78
- {
79
- if (this.configurationData.Contains(name))
80
- {
81
- string val = (string)this.configurationData[name];
82
- configData = Convert.ToInt32(val, CultureInfo.InvariantCulture);
83
- return SOk;
84
- }
85
- else
86
- {
87
- configData = 0;
88
- return SFalse;
89
- }
90
- }
91
- }
92
-}
src/WixToolset.Core.WindowsInstaller/Bind/CreateInstanceTransformsCommand.cs
+1
-1
@@ -5,7 +5,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
5
using System;
6
using System.Collections.Generic;
7
using System.Linq;
8
- using WixToolset.Core.WindowsInstaller.Msi;
8
+ using WixToolset.Core.Native.Msi;
9
using WixToolset.Data;
10
using WixToolset.Data.Symbols;
11
using WixToolset.Data.WindowsInstaller;
src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs
+1
-1
@@ -6,7 +6,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6
using System.Collections.Generic;
7
using System.IO;
8
using System.Linq;
9
- using WixToolset.Core.WindowsInstaller.Msi;
9
+ using WixToolset.Core.Native.Msi;
10
using WixToolset.Core.WindowsInstaller.Unbind;
11
using WixToolset.Data;
12
using WixToolset.Data.Symbols;
src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
+5
-5
@@ -9,12 +9,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
9
using System.IO;
10
using System.Linq;
11
using System.Runtime.InteropServices;
12
- using WixToolset.Data;
12
using WixToolset.Core.Native;
13
+ using WixToolset.Core.Native.Msi;
14
+ using WixToolset.Core.Native.Msm;
15
+ using WixToolset.Data;
16
using WixToolset.Data.Symbols;
15
- using WixToolset.Extensibility.Services;
16
- using WixToolset.Core.WindowsInstaller.Msi;
17
using WixToolset.Extensibility.Data;
18
+ using WixToolset.Extensibility.Services;
19
20
/// <summary>
21
/// Retrieve files information and extract them from merge modules.
@@ -52,8 +53,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
53
{
54
var mergeModulesFileFacades = new List<IFileFacade>();
55
55
- var interop = new MsmInterop();
56
- var merge = interop.GetMsmMerge();
56
+ var merge = MsmInterop.GetMsmMerge();
57
58
// Index all of the file rows to be able to detect collisions with files in the Merge Modules.
59
// It may seem a bit expensive to build up this index solely for the purpose of checking collisions
src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs
+2
-2
@@ -8,7 +8,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
8
using System.IO;
9
using System.Linq;
10
using System.Text;
11
- using WixToolset.Core.WindowsInstaller.Msi;
11
+ using WixToolset.Core.Native.Msi;
12
using WixToolset.Data;
13
using WixToolset.Data.WindowsInstaller;
14
using WixToolset.Extensibility.Data;
@@ -337,7 +337,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
337
}
338
339
// check for a stream name that is more than 62 characters long (the maximum allowed length)
340
- if (needStream && MsiInterop.MsiMaxStreamNameLength < streamName.Length)
340
+ if (needStream && Database.MsiMaxStreamNameLength < streamName.Length)
341
{
342
this.Messaging.Write(ErrorMessages.StreamNameTooLong(row.SourceLineNumbers, table.Name, streamName.ToString(), streamName.Length));
343
}
src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs
+1
-1
@@ -5,7 +5,7 @@ namespace WixToolset.Core.WindowsInstaller
5
using System;
6
using System.Collections.Generic;
7
using System.Globalization;
8
- using WixToolset.Core.WindowsInstaller.Msi;
8
+ using WixToolset.Core.Native.Msi;
9
using WixToolset.Data;
10
using WixToolset.Data.Symbols;
11
using WixToolset.Data.WindowsInstaller;
src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
+3
-4
@@ -9,8 +9,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
9
using System.Linq;
10
using System.Runtime.InteropServices;
11
using System.Text;
12
- using WixToolset.Core.Native;
13
- using WixToolset.Core.WindowsInstaller.Msi;
12
+ using WixToolset.Core.Native.Msi;
13
+ using WixToolset.Core.Native.Msm;
14
using WixToolset.Data;
15
using WixToolset.Data.Symbols;
16
using WixToolset.Data.WindowsInstaller;
@@ -60,8 +60,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
60
61
try
62
{
63
- var interop = new MsmInterop();
64
- merge = interop.GetMsmMerge();
63
+ merge = MsmInterop.GetMsmMerge();
64
65
merge.OpenLog(logPath);
66
logOpen = true;
src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
+1
-1
@@ -6,7 +6,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6
using System.Collections.Generic;
7
using System.IO;
8
using System.Linq;
9
- using WixToolset.Core.WindowsInstaller.Msi;
9
+ using WixToolset.Core.Native.Msi;
10
using WixToolset.Data;
11
using WixToolset.Data.Symbols;
12
using WixToolset.Extensibility.Data;
src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
+1
-1
@@ -8,7 +8,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
8
using System.Globalization;
9
using System.IO;
10
using System.Linq;
11
- using WixToolset.Core.WindowsInstaller.Msi;
11
+ using WixToolset.Core.Native.Msi;
12
using WixToolset.Data;
13
using WixToolset.Data.Symbols;
14
using WixToolset.Extensibility.Data;
src/WixToolset.Core.WindowsInstaller/Decompile/DecompileMsiOrMsmCommand.cs
+1
-1
@@ -7,7 +7,7 @@ namespace WixToolset.Core.WindowsInstaller.Decompile
7
using System.ComponentModel;
8
using System.IO;
9
using System.Linq;
10
- using WixToolset.Core.WindowsInstaller.Msi;
10
+ using WixToolset.Core.Native.Msi;
11
using WixToolset.Core.WindowsInstaller.Unbind;
12
using WixToolset.Data;
13
using WixToolset.Data.WindowsInstaller;
src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
+2
-2
@@ -8,8 +8,8 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
8
using System.IO;
9
using System.Runtime.InteropServices;
10
using System.Security.Cryptography.X509Certificates;
11
+ using WixToolset.Core.Native.Msi;
12
using WixToolset.Core.WindowsInstaller.Bind;
12
- using WixToolset.Core.WindowsInstaller.Msi;
13
using WixToolset.Data;
14
using WixToolset.Data.WindowsInstaller;
15
using WixToolset.Extensibility.Data;
@@ -150,7 +150,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
150
Row digitalSignatureRow = null;
151
152
var cabName = mediaRecord.GetString(4); // get the name of the cab
153
- // If there is no cabinet or it's an internal cab, skip it.
153
+ // If there is no cabinet or it's an internal cab, skip it.
154
if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal))
155
{
156
continue;
src/WixToolset.Core.WindowsInstaller/MergeMod/NativeMethods.cs
deleted
-508
@@ -1,508 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-#if false
3
-namespace WixToolset.MergeMod
4
-{
5
- using System;
6
- using System.Collections;
7
- using System.Runtime.CompilerServices;
8
- using System.Runtime.InteropServices;
9
-
10
- /// <summary>
11
- /// Errors returned by merge operations.
12
- /// </summary>
13
- [Guid("0ADDA825-2C26-11D2-AD65-00A0C9AF11A6")]
14
- internal enum MsmErrorType
15
- {
16
- /// <summary>
17
- /// A request was made to open a module with a language not supported by the module.
18
- /// No more general language is supported by the module.
19
- /// Adds msmErrorLanguageUnsupported to the Type property and the requested language
20
- /// to the Language Property (Error Object). All Error object properties are empty.
21
- /// The OpenModule function returns ERROR_INSTALL_LANGUAGE_UNSUPPORTED (as HRESULT).
22
- /// </summary>
23
- msmErrorLanguageUnsupported = 1,
24
-
25
- /// <summary>
26
- /// A request was made to open a module with a supported language but the module has
27
- /// an invalid language transform. Adds msmErrorLanguageFailed to the Type property
28
- /// and the applied transform's language to the Language Property of the Error object.
29
- /// This may not be the requested language if a more general language was used.
30
- /// All other properties of the Error object are empty. The OpenModule function
31
- /// returns ERROR_INSTALL_LANGUAGE_UNSUPPORTED (as HRESULT).
32
- /// </summary>
33
- msmErrorLanguageFailed = 2,
34
-
35
- /// <summary>
36
- /// The module cannot be merged because it excludes, or is excluded by, another module
37
- /// in the database. Adds msmErrorExclusion to the Type property of the Error object.
38
- /// The ModuleKeys property or DatabaseKeys property contains the primary keys of the
39
- /// excluded module's row in the ModuleExclusion table. If an existing module excludes
40
- /// the module being merged, the excluded module's ModuleSignature information is added
41
- /// to ModuleKeys. If the module being merged excludes an existing module, DatabaseKeys
42
- /// contains the excluded module's ModuleSignature information. All other properties
43
- /// are empty (or -1).
44
- /// </summary>
45
- msmErrorExclusion = 3,
46
-
47
- /// <summary>
48
- /// Merge conflict during merge. The value of the Type property is set to
49
- /// msmErrorTableMerge. The DatabaseTable property and DatabaseKeys property contain
50
- /// the table name and primary keys of the conflicting row in the database. The
51
- /// ModuleTable property and ModuleKeys property contain the table name and primary keys
52
- /// of the conflicting row in the module. The ModuleTable and ModuleKeys entries may be
53
- /// null if the row does not exist in the database. For example, if the conflict is in a
54
- /// generated FeatureComponents table entry. On Windows Installer version 2.0, when
55
- /// merging a configurable merge module, configuration may cause these properties to
56
- /// refer to rows that do not exist in the module.
57
- /// </summary>
58
- msmErrorTableMerge = 4,
59
-
60
- /// <summary>
61
- /// There was a problem resequencing a sequence table to contain the necessary merged
62
- /// actions. The Type property is set to msmErrorResequenceMerge. The DatabaseTable
63
- /// and DatabaseKeys properties contain the sequence table name and primary keys
64
- /// (action name) of the conflicting row. The ModuleTable and ModuleKeys properties
65
- /// contain the sequence table name and primary key (action name) of the conflicting row.
66
- /// On Windows Installer version 2.0, when merging a configurable merge module,
67
- /// configuration may cause these properties to refer to rows that do not exist in the module.
68
- /// </summary>
69
- msmErrorResequenceMerge = 5,
70
-
71
- /// <summary>
72
- /// Not used.
73
- /// </summary>
74
- msmErrorFileCreate = 6,
75
-
76
- /// <summary>
77
- /// There was a problem creating a directory to extract a file to disk. The Path property
78
- /// contains the directory that could not be created. All other properties are empty or -1.
79
- /// Not available with Windows Installer version 1.0.
80
- /// </summary>
81
- msmErrorDirCreate = 7,
82
-
83
- /// <summary>
84
- /// A feature name is required to complete the merge, but no feature name was provided.
85
- /// The Type property is set to msmErrorFeatureRequired. The DatabaseTable and DatabaseKeys
86
- /// contain the table name and primary keys of the conflicting row. The ModuleTable and
87
- /// ModuleKeys properties contain the table name and primary keys of the row cannot be merged.
88
- /// On Windows Installer version 2.0, when merging a configurable merge module, configuration
89
- /// may cause these properties to refer to rows that do not exist in the module.
90
- /// If the failure is in a generated FeatureComponents table, the DatabaseTable and
91
- /// DatabaseKeys properties are empty and the ModuleTable and ModuleKeys properties refer to
92
- /// the row in the Component table causing the failure.
93
- /// </summary>
94
- msmErrorFeatureRequired = 8,
95
-
96
- /// <summary>
97
- /// Available with Window Installer version 2.0. Substitution of a Null value into a
98
- /// non-nullable column. This enters msmErrorBadNullSubstitution in the Type property and
99
- /// enters "ModuleSubstitution" and the keys from the ModuleSubstitution table for this row
100
- /// into the ModuleTable property and ModuleKeys property. All other properties of the Error
101
- /// object are set to an empty string or -1. This error causes the immediate failure of the
102
- /// merge and the MergeEx function to return E_FAIL.
103
- /// </summary>
104
- msmErrorBadNullSubstitution = 9,
105
-
106
- /// <summary>
107
- /// Available with Window Installer version 2.0. Substitution of Text Format Type or Integer
108
- /// Format Type into a Binary Type data column. This type of error returns
109
- /// msmErrorBadSubstitutionType in the Type property and enters "ModuleSubstitution" and the
110
- /// keys from the ModuleSubstitution table for this row into the ModuleTable property.
111
- /// All other properties of the Error object are set to an empty string or -1. This error
112
- /// causes the immediate failure of the merge and the MergeEx function to return E_FAIL.
113
- /// </summary>
114
- msmErrorBadSubstitutionType = 10,
115
-
116
- /// <summary>
117
- /// Available with Window Installer Version 2.0. A row in the ModuleSubstitution table
118
- /// references a configuration item not defined in the ModuleConfiguration table.
119
- /// This type of error returns msmErrorMissingConfigItem in the Type property and enters
120
- /// "ModuleSubstitution" and the keys from the ModuleSubstitution table for this row into
121
- /// the ModuleTable property. All other properties of the Error object are set to an empty
122
- /// string or -1. This error causes the immediate failure of the merge and the MergeEx
123
- /// function to return E_FAIL.
124
- /// </summary>
125
- msmErrorMissingConfigItem = 11,
126
-
127
- /// <summary>
128
- /// Available with Window Installer version 2.0. The authoring tool has returned a Null
129
- /// value for an item marked with the msmConfigItemNonNullable attribute. An error of this
130
- /// type returns msmErrorBadNullResponse in the Type property and enters "ModuleSubstitution"
131
- /// and the keys from the ModuleSubstitution table for for the item into the ModuleTable property.
132
- /// All other properties of the Error object are set to an empty string or -1. This error
133
- /// causes the immediate failure of the merge and the MergeEx function to return E_FAIL.
134
- /// </summary>
135
- msmErrorBadNullResponse = 12,
136
-
137
- /// <summary>
138
- /// Available with Window Installer version 2.0. The authoring tool returned a failure code
139
- /// (not S_OK or S_FALSE) when asked for data. An error of this type will return
140
- /// msmErrorDataRequestFailed in the Type property and enters "ModuleSubstitution"
141
- /// and the keys from the ModuleSubstitution table for the item into the ModuleTable property.
142
- /// All other properties of the Error object are set to an empty string or -1. This error
143
- /// causes the immediate failure of the merge and the MergeEx function to return E_FAIL.
144
- /// </summary>
145
- msmErrorDataRequestFailed = 13,
146
-
147
- /// <summary>
148
- /// Available with Windows Installer 2.0 and later versions. Indicates that an attempt was
149
- /// made to merge a 64-bit module into a package that was not a 64-bit package. An error of
150
- /// this type returns msmErrorPlatformMismatch in the Type property. All other properties of
151
- /// the error object are set to an empty string or -1. This error causes the immediate failure
152
- /// of the merge and causes the Merge function or MergeEx function to return E_FAIL.
153
- /// </summary>
154
- msmErrorPlatformMismatch = 14,
155
- }
156
-
157
- /// <summary>
158
- /// IMsmMerge2 interface.
159
- /// </summary>
160
- [ComImport, Guid("351A72AB-21CB-47ab-B7AA-C4D7B02EA305")]
161
- internal interface IMsmMerge2
162
- {
163
- /// <summary>
164
- /// The OpenDatabase method of the Merge object opens a Windows Installer installation
165
- /// database, located at a specified path, that is to be merged with a module.
166
- /// </summary>
167
- /// <param name="path">Path to the database being opened.</param>
168
- void OpenDatabase(string path);
169
-
170
- /// <summary>
171
- /// The OpenModule method of the Merge object opens a Windows Installer merge module
172
- /// in read-only mode. A module must be opened before it can be merged with an installation database.
173
- /// </summary>
174
- /// <param name="fileName">Fully qualified file name pointing to a merge module.</param>
175
- /// <param name="language">A valid language identifier (LANGID).</param>
176
- void OpenModule(string fileName, short language);
177
-
178
- /// <summary>
179
- /// The CloseDatabase method of the Merge object closes the currently open Windows Installer database.
180
- /// </summary>
181
- /// <param name="commit">true if changes should be saved, false otherwise.</param>
182
- void CloseDatabase(bool commit);
183
-
184
- /// <summary>
185
- /// The CloseModule method of the Merge object closes the currently open Windows Installer merge module.
186
- /// </summary>
187
- void CloseModule();
188
-
189
- /// <summary>
190
- /// The OpenLog method of the Merge object opens a log file that receives progress and error messages.
191
- /// If the log file already exists, the installer appends new messages. If the log file does not exist,
192
- /// the installer creates a log file.
193
- /// </summary>
194
- /// <param name="fileName">Fully qualified filename pointing to a file to open or create.</param>
195
- void OpenLog(string fileName);
196
-
197
- /// <summary>
198
- /// The CloseLog method of the Merge object closes the current log file.
199
- /// </summary>
200
- void CloseLog();
201
-
202
- /// <summary>
203
- /// The Log method of the Merge object writes a text string to the currently open log file.
204
- /// </summary>
205
- /// <param name="message">The text string to display.</param>
206
- void Log(string message);
207
-
208
- /// <summary>
209
- /// Gets the errors from the last merge operation.
210
- /// </summary>
211
- /// <value>The errors from the last merge operation.</value>
212
- IMsmErrors Errors
213
- {
214
- get;
215
- }
216
-
217
- /// <summary>
218
- /// Gets a collection of Dependency objects that enumerates a set of unsatisfied dependencies for the current database.
219
- /// </summary>
220
- /// <value>A collection of Dependency objects that enumerates a set of unsatisfied dependencies for the current database.</value>
221
- object Dependencies
222
- {
223
- get;
224
- }
225
-
226
- /// <summary>
227
- /// The Merge method of the Merge object executes a merge of the current database and current
228
- /// module. The merge attaches the components in the module to the feature identified by Feature.
229
- /// The root of the module's directory tree is redirected to the location given by RedirectDir.
230
- /// </summary>
231
- /// <param name="feature">The name of a feature in the database.</param>
232
- /// <param name="redirectDir">The key of an entry in the Directory table of the database.
233
- /// This parameter may be NULL or an empty string.</param>
234
- void Merge(string feature, string redirectDir);
235
-
236
- /// <summary>
237
- /// The Connect method of the Merge object connects a module to an additional feature.
238
- /// The module must have already been merged into the database or will be merged into the database.
239
- /// The feature must exist before calling this function.
240
- /// </summary>
241
- /// <param name="feature">The name of a feature already existing in the database.</param>
242
- void Connect(string feature);
243
-
244
- /// <summary>
245
- /// The ExtractCAB method of the Merge object extracts the embedded .cab file from a module and
246
- /// saves it as the specified file. The installer creates this file if it does not already exist
247
- /// and overwritten if it does exist.
248
- /// </summary>
249
- /// <param name="fileName">The fully qualified destination file.</param>
250
- void ExtractCAB(string fileName);
251
-
252
- /// <summary>
253
- /// The ExtractFiles method of the Merge object extracts the embedded .cab file from a module
254
- /// and then writes those files to the destination directory.
255
- /// </summary>
256
- /// <param name="path">The fully qualified destination directory.</param>
257
- void ExtractFiles(string path);
258
-
259
- /// <summary>
260
- /// The MergeEx method of the Merge object is equivalent to the Merge function, except that it
261
- /// takes an extra argument. The Merge method executes a merge of the current database and
262
- /// current module. The merge attaches the components in the module to the feature identified
263
- /// by Feature. The root of the module's directory tree is redirected to the location given by RedirectDir.
264
- /// </summary>
265
- /// <param name="feature">The name of a feature in the database.</param>
266
- /// <param name="redirectDir">The key of an entry in the Directory table of the database. This parameter may
267
- /// be NULL or an empty string.</param>
268
- /// <param name="configuration">The pConfiguration argument is an interface implemented by the client. The argument may
269
- /// be NULL. The presence of this argument indicates that the client is capable of supporting the configuration
270
- /// functionality, but does not obligate the client to provide configuration data for any specific configurable item.</param>
271
- void MergeEx(string feature, string redirectDir, IMsmConfigureModule configuration);
272
-
273
- /// <summary>
274
- /// The ExtractFilesEx method of the Merge object extracts the embedded .cab file from a module and
275
- /// then writes those files to the destination directory.
276
- /// </summary>
277
- /// <param name="path">The fully qualified destination directory.</param>
278
- /// <param name="longFileNames">Set to specify using long file names for path segments and final file names.</param>
279
- /// <param name="filePaths">This is a list of fully-qualified paths for the files that were successfully extracted.
280
- /// The list is empty if no files can be extracted. This argument may be null. No list is provided if pFilePaths is null.</param>
281
- void ExtractFilesEx(string path, bool longFileNames, ref IntPtr filePaths);
282
-
283
- /// <summary>
284
- /// Gets a collection ConfigurableItem objects, each of which represents a single row from the ModuleConfiguration table.
285
- /// </summary>
286
- /// <value>A collection ConfigurableItem objects, each of which represents a single row from the ModuleConfiguration table.</value>
287
- /// <remarks>Semantically, each interface in the enumerator represents an item that can be configured by the module consumer.
288
- /// The collection is a read-only collection and implements the standard read-only collection interfaces of Item(), Count() and _NewEnum().
289
- /// The IEnumMsmConfigItems enumerator implements Next(), Skip(), Reset(), and Clone() with the standard semantics.</remarks>
290
- object ConfigurableItems
291
- {
292
- get;
293
- }
294
-
295
- /// <summary>
296
- /// The CreateSourceImage method of the Merge object allows the client to extract the files from a module to
297
- /// a source image on disk after a merge, taking into account changes to the module that might have been made
298
- /// during module configuration. The list of files to be extracted is taken from the file table of the module
299
- /// during the merge process. The list of files consists of every file successfully copied from the file table
300
- /// of the module to the target database. File table entries that were not copied due to primary key conflicts
301
- /// with existing rows in the database are not a part of this list. At image creation time, the directory for
302
- /// each of these files comes from the open (post-merge) database. The path specified in the Path parameter is
303
- /// the root of the source image for the install. fLongFileNames determines whether or not long file names are
304
- /// used for both path segments and final file names. The function fails if no database is open, no module is
305
- /// open, or no merge has been performed.
306
- /// </summary>
307
- /// <param name="path">The path of the root of the source image for the install.</param>
308
- /// <param name="longFileNames">Determines whether or not long file names are used for both path segments and final file names. </param>
309
- /// <param name="filePaths">This is a list of fully-qualified paths for the files that were successfully extracted.
310
- /// The list is empty if no files can be extracted. This argument may be null. No list is provided if pFilePaths is null.</param>
311
- void CreateSourceImage(string path, bool longFileNames, ref IntPtr filePaths);
312
-
313
- /// <summary>
314
- /// The get_ModuleFiles function implements the ModuleFiles property of the GetFiles object. This function
315
- /// returns the primary keys in the File table of the currently open module. The primary keys are returned
316
- /// as a collection of strings. The module must be opened by a call to the OpenModule function before calling get_ModuleFiles.
317
- /// </summary>
318
- IMsmStrings ModuleFiles
319
- {
320
- get;
321
- }
322
- }
323
-
324
- /// <summary>
325
- /// Collection of merge errors.
326
- /// </summary>
327
- [ComImport, Guid("0ADDA82A-2C26-11D2-AD65-00A0C9AF11A6")]
328
- internal interface IMsmErrors
329
- {
330
- /// <summary>
331
- /// Gets the IMsmError at the specified index.
332
- /// </summary>
333
- /// <param name="index">The one-based index of the IMsmError to get.</param>
334
- IMsmError this[int index]
335
- {
336
- get;
337
- }
338
-
339
- /// <summary>
340
- /// Gets the count of IMsmErrors in this collection.
341
- /// </summary>
342
- /// <value>The count of IMsmErrors in this collection.</value>
343
- int Count
344
- {
345
- get;
346
- }
347
- }
348
-
349
- /// <summary>
350
- /// A merge error.
351
- /// </summary>
352
- [ComImport, Guid("0ADDA828-2C26-11D2-AD65-00A0C9AF11A6")]
353
- internal interface IMsmError
354
- {
355
- /// <summary>
356
- /// Gets the type of merge error.
357
- /// </summary>
358
- /// <value>The type of merge error.</value>
359
- MsmErrorType Type
360
- {
361
- get;
362
- }
363
-
364
- /// <summary>
365
- /// Gets the path information from the merge error.
366
- /// </summary>
367
- /// <value>The path information from the merge error.</value>
368
- string Path
369
- {
370
- get;
371
- }
372
-
373
- /// <summary>
374
- /// Gets the language information from the merge error.
375
- /// </summary>
376
- /// <value>The language information from the merge error.</value>
377
- short Language
378
- {
379
- get;
380
- }
381
-
382
- /// <summary>
383
- /// Gets the database table from the merge error.
384
- /// </summary>
385
- /// <value>The database table from the merge error.</value>
386
- string DatabaseTable
387
- {
388
- get;
389
- }
390
-
391
- /// <summary>
392
- /// Gets the collection of database keys from the merge error.
393
- /// </summary>
394
- /// <value>The collection of database keys from the merge error.</value>
395
- IMsmStrings DatabaseKeys
396
- {
397
- get;
398
- }
399
-
400
- /// <summary>
401
- /// Gets the module table from the merge error.
402
- /// </summary>
403
- /// <value>The module table from the merge error.</value>
404
- string ModuleTable
405
- {
406
- get;
407
- }
408
-
409
- /// <summary>
410
- /// Gets the collection of module keys from the merge error.
411
- /// </summary>
412
- /// <value>The collection of module keys from the merge error.</value>
413
- IMsmStrings ModuleKeys
414
- {
415
- get;
416
- }
417
- }
418
-
419
- /// <summary>
420
- /// A collection of strings.
421
- /// </summary>
422
- [ComImport, Guid("0ADDA827-2C26-11D2-AD65-00A0C9AF11A6")]
423
- internal interface IMsmStrings
424
- {
425
- /// <summary>
426
- /// Gets the string at the specified index.
427
- /// </summary>
428
- /// <param name="index">The one-based index of the string to get.</param>
429
- string this[int index]
430
- {
431
- get;
432
- }
433
-
434
- /// <summary>
435
- /// Gets the count of strings in this collection.
436
- /// </summary>
437
- /// <value>The count of strings in this collection.</value>
438
- int Count
439
- {
440
- get;
441
- }
442
- }
443
-
444
- /// <summary>
445
- /// Callback for configurable merge modules.
446
- /// </summary>
447
- [ComImport, Guid("AC013209-18A7-4851-8A21-2353443D70A0"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
448
- internal interface IMsmConfigureModule
449
- {
450
- /// <summary>
451
- /// Callback to retrieve text data for configurable merge modules.
452
- /// </summary>
453
- /// <param name="name">Name of the data to be retrieved.</param>
454
- /// <param name="configData">The data corresponding to the name.</param>
455
- /// <returns>The error code (HRESULT).</returns>
456
- [PreserveSig]
457
- int ProvideTextData([In, MarshalAs(UnmanagedType.BStr)] string name, [MarshalAs(UnmanagedType.BStr)] out string configData);
458
-
459
- /// <summary>
460
- /// Callback to retrieve integer data for configurable merge modules.
461
- /// </summary>
462
- /// <param name="name">Name of the data to be retrieved.</param>
463
- /// <param name="configData">The data corresponding to the name.</param>
464
- /// <returns>The error code (HRESULT).</returns>
465
- [PreserveSig]
466
- int ProvideIntegerData([In, MarshalAs(UnmanagedType.BStr)] string name, out int configData);
467
- }
468
-
469
- /// <summary>
470
- /// Merge merge modules into an MSI file.
471
- /// </summary>
472
- [ComImport, Guid("F94985D5-29F9-4743-9805-99BC3F35B678")]
473
- internal class MsmMerge2
474
- {
475
- }
476
-
477
- /// <summary>
478
- /// Defines the standard COM IClassFactory interface.
479
- /// </summary>
480
- [ComImport, Guid("00000001-0000-0000-C000-000000000046")]
481
- [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
482
- internal interface IClassFactory
483
- {
484
- [return:MarshalAs(UnmanagedType.IUnknown)]
485
- object CreateInstance(IntPtr unkOuter, [MarshalAs(UnmanagedType.LPStruct)] Guid iid);
486
- }
487
-
488
- /// <summary>
489
- /// Contains native methods for merge operations.
490
- /// </summary>
491
- internal class NativeMethods
492
- {
493
- [DllImport("mergemod.dll", EntryPoint="DllGetClassObject", PreserveSig=false)]
494
- [return: MarshalAs(UnmanagedType.IUnknown)]
495
- private static extern object MergeModGetClassObject([MarshalAs(UnmanagedType.LPStruct)] Guid clsid, [MarshalAs(UnmanagedType.LPStruct)] Guid iid);
496
-
497
- /// <summary>
498
- /// Load the merge object directly from a local mergemod.dll without going through COM registration.
499
- /// </summary>
500
- /// <returns>Merge interface.</returns>
501
- internal static IMsmMerge2 GetMsmMerge()
502
- {
503
- IClassFactory classFactory = (IClassFactory) MergeModGetClassObject(typeof(MsmMerge2).GUID, typeof(IClassFactory).GUID);
504
- return (IMsmMerge2) classFactory.CreateInstance(IntPtr.Zero, typeof(IMsmMerge2).GUID);
505
- }
506
- }
507
-}
508
-#endif
\ No newline at end of file
src/WixToolset.Core.WindowsInstaller/Msi/Database.cs
deleted
-248
@@ -1,248 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.Globalization;
7
- using System.IO;
8
- using System.Threading;
9
-
10
- /// <summary>
11
- /// Wrapper class for managing MSI API database handles.
12
- /// </summary>
13
- internal sealed class Database : MsiHandle
14
- {
15
- private const int STG_E_LOCKVIOLATION = unchecked((int)0x80030021);
16
-
17
- /// <summary>
18
- /// Constructor that opens an MSI database.
19
- /// </summary>
20
- /// <param name="path">Path to the database to be opened.</param>
21
- /// <param name="type">Persist mode to use when opening the database.</param>
22
- public Database(string path, OpenDatabase type)
23
- {
24
- int error = MsiInterop.MsiOpenDatabase(path, new IntPtr((int)type), out var handle);
25
- if (0 != error)
26
- {
27
- throw new MsiException(error);
28
- }
29
- this.Handle = handle;
30
- }
31
-
32
- public void ApplyTransform(string transformFile)
33
- {
34
- // get the curret validation bits
35
- TransformErrorConditions conditions = TransformErrorConditions.None;
36
- using (SummaryInformation summaryInfo = new SummaryInformation(transformFile))
37
- {
38
- string value = summaryInfo.GetProperty((int)SummaryInformation.Transform.ValidationFlags);
39
- try
40
- {
41
- int validationFlags = Int32.Parse(value, CultureInfo.InvariantCulture);
42
- conditions = (TransformErrorConditions)(validationFlags & 0xffff);
43
- }
44
- catch (FormatException)
45
- {
46
- // fallback to default of None
47
- }
48
- }
49
-
50
- this.ApplyTransform(transformFile, conditions);
51
- }
52
-
53
- /// <summary>
54
- /// Applies a transform to this database.
55
- /// </summary>
56
- /// <param name="transformFile">Path to the transform file being applied.</param>
57
- /// <param name="errorConditions">Specifies the error conditions that are to be suppressed.</param>
58
- public void ApplyTransform(string transformFile, TransformErrorConditions errorConditions)
59
- {
60
- int error = MsiInterop.MsiDatabaseApplyTransform(this.Handle, transformFile, errorConditions);
61
- if (0 != error)
62
- {
63
- throw new MsiException(error);
64
- }
65
- }
66
-
67
- /// <summary>
68
- /// Commits changes made to the database.
69
- /// </summary>
70
- public void Commit()
71
- {
72
- // Retry this call 3 times to deal with an MSI internal locking problem.
73
- const int retryWait = 300;
74
- const int retryLimit = 3;
75
- int error = 0;
76
-
77
- for (int i = 1; i <= retryLimit; ++i)
78
- {
79
- error = MsiInterop.MsiDatabaseCommit(this.Handle);
80
-
81
- if (0 == error)
82
- {
83
- return;
84
- }
85
- else
86
- {
87
- MsiException exception = new MsiException(error);
88
-
89
- // We need to see if the error code is contained in any of the strings in ErrorInfo.
90
- // Join the array together and search for the error code to cover the string array.
91
- if (!String.Join(", ", exception.ErrorInfo).Contains(STG_E_LOCKVIOLATION.ToString()))
92
- {
93
- break;
94
- }
95
-
96
- Console.Error.WriteLine(String.Format("Failed to create the database. Info: {0}. Retrying ({1} of {2})", String.Join(", ", exception.ErrorInfo), i, retryLimit));
97
- Thread.Sleep(retryWait);
98
- }
99
- }
100
-
101
- throw new MsiException(error);
102
- }
103
-
104
- /// <summary>
105
- /// Creates and populates the summary information stream of an existing transform file.
106
- /// </summary>
107
- /// <param name="referenceDatabase">Required database that does not include the changes.</param>
108
- /// <param name="transformFile">The name of the generated transform file.</param>
109
- /// <param name="errorConditions">Required error conditions that should be suppressed when the transform is applied.</param>
110
- /// <param name="validations">Required when the transform is applied to a database;
111
- /// shows which properties should be validated to verify that this transform can be applied to the database.</param>
112
- public void CreateTransformSummaryInfo(Database referenceDatabase, string transformFile, TransformErrorConditions errorConditions, TransformValidations validations)
113
- {
114
- int error = MsiInterop.MsiCreateTransformSummaryInfo(this.Handle, referenceDatabase.Handle, transformFile, errorConditions, validations);
115
- if (0 != error)
116
- {
117
- throw new MsiException(error);
118
- }
119
- }
120
-
121
- /// <summary>
122
- /// Imports an installer text archive table (idt file) into an open database.
123
- /// </summary>
124
- /// <param name="idtPath">Specifies the path to the file to import.</param>
125
- /// <exception cref="WixInvalidIdtException">Attempted to import an IDT file with an invalid format or unsupported data.</exception>
126
- /// <exception cref="MsiException">Another error occured while importing the IDT file.</exception>
127
- public void Import(string idtPath)
128
- {
129
- string folderPath = Path.GetFullPath(Path.GetDirectoryName(idtPath));
130
- string fileName = Path.GetFileName(idtPath);
131
-
132
- int error = MsiInterop.MsiDatabaseImport(this.Handle, folderPath, fileName);
133
- if (1627 == error) // ERROR_FUNCTION_FAILED
134
- {
135
- throw new WixInvalidIdtException(idtPath);
136
- }
137
- else if (0 != error)
138
- {
139
- throw new MsiException(error);
140
- }
141
- }
142
-
143
- /// <summary>
144
- /// Exports an installer table from an open database to a text archive file (idt file).
145
- /// </summary>
146
- /// <param name="tableName">Specifies the name of the table to export.</param>
147
- /// <param name="folderPath">Specifies the name of the folder that contains archive files. If null or empty string, uses current directory.</param>
148
- /// <param name="fileName">Specifies the name of the exported table archive file.</param>
149
- public void Export(string tableName, string folderPath, string fileName)
150
- {
151
- if (String.IsNullOrEmpty(folderPath))
152
- {
153
- folderPath = Environment.CurrentDirectory;
154
- }
155
-
156
- int error = MsiInterop.MsiDatabaseExport(this.Handle, tableName, folderPath, fileName);
157
- if (0 != error)
158
- {
159
- throw new MsiException(error);
160
- }
161
- }
162
-
163
- /// <summary>
164
- /// Creates a transform that, when applied to the reference database, results in this database.
165
- /// </summary>
166
- /// <param name="referenceDatabase">Required database that does not include the changes.</param>
167
- /// <param name="transformFile">The name of the generated transform file. This is optional.</param>
168
- /// <returns>true if a transform is generated; false if a transform is not generated because
169
- /// there are no differences between the two databases.</returns>
170
- public bool GenerateTransform(Database referenceDatabase, string transformFile)
171
- {
172
- int error = MsiInterop.MsiDatabaseGenerateTransform(this.Handle, referenceDatabase.Handle, transformFile, 0, 0);
173
- if (0 != error && 0xE8 != error) // ERROR_NO_DATA(0xE8) means no differences were found
174
- {
175
- throw new MsiException(error);
176
- }
177
-
178
- return (0xE8 != error);
179
- }
180
-
181
- /// <summary>
182
- /// Merges two databases together.
183
- /// </summary>
184
- /// <param name="mergeDatabase">The database to merge into the base database.</param>
185
- /// <param name="tableName">The name of the table to receive merge conflict information.</param>
186
- public void Merge(Database mergeDatabase, string tableName)
187
- {
188
- int error = MsiInterop.MsiDatabaseMerge(this.Handle, mergeDatabase.Handle, tableName);
189
- if (0 != error)
190
- {
191
- throw new MsiException(error);
192
- }
193
- }
194
-
195
- /// <summary>
196
- /// Prepares a database query and creates a <see cref="View">View</see> object.
197
- /// </summary>
198
- /// <param name="query">Specifies a SQL query string for querying the database.</param>
199
- /// <returns>A view object is returned if the query was successful.</returns>
200
- public View OpenView(string query)
201
- {
202
- return new View(this, query);
203
- }
204
-
205
- /// <summary>
206
- /// Prepares and executes a database query and creates a <see cref="View">View</see> object.
207
- /// </summary>
208
- /// <param name="query">Specifies a SQL query string for querying the database.</param>
209
- /// <returns>A view object is returned if the query was successful.</returns>
210
- public View OpenExecuteView(string query)
211
- {
212
- View view = new View(this, query);
213
-
214
- view.Execute();
215
- return view;
216
- }
217
-
218
- /// <summary>
219
- /// Verifies the existence or absence of a table.
220
- /// </summary>
221
- /// <param name="tableName">Table name to to verify the existence of.</param>
222
- /// <returns>Returns true if the table exists, false if it does not.</returns>
223
- public bool TableExists(string tableName)
224
- {
225
- int result = MsiInterop.MsiDatabaseIsTablePersistent(this.Handle, tableName);
226
- return MsiInterop.MSICONDITIONTRUE == result;
227
- }
228
-
229
- /// <summary>
230
- /// Returns a <see cref="Record">Record</see> containing the names of all the primary
231
- /// key columns for a specified table.
232
- /// </summary>
233
- /// <param name="tableName">Specifies the name of the table from which to obtain
234
- /// primary key names.</param>
235
- /// <returns>Returns a <see cref="Record">Record</see> containing the names of all the
236
- /// primary key columns for a specified table.</returns>
237
- public Record PrimaryKeys(string tableName)
238
- {
239
- var error = MsiInterop.MsiDatabaseGetPrimaryKeys(this.Handle, tableName, out var recordHandle);
240
- if (error != 0)
241
- {
242
- throw new MsiException(error);
243
- }
244
-
245
- return new Record(recordHandle);
246
- }
247
- }
248
-}
src/WixToolset.Core.WindowsInstaller/Msi/Installer.cs
deleted
-363
@@ -1,363 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.Diagnostics;
7
- using System.Text;
8
- using WixToolset.Core.Native;
9
-
10
- /// <summary>
11
- /// Windows Installer message types.
12
- /// </summary>
13
- [Flags]
14
- internal enum InstallMessage
15
- {
16
- /// <summary>
17
- /// Premature termination, possibly fatal out of memory.
18
- /// </summary>
19
- FatalExit = 0x00000000,
20
-
21
- /// <summary>
22
- /// Formatted error message, [1] is message number in Error table.
23
- /// </summary>
24
- Error = 0x01000000,
25
-
26
- /// <summary>
27
- /// Formatted warning message, [1] is message number in Error table.
28
- /// </summary>
29
- Warning = 0x02000000,
30
-
31
- /// <summary>
32
- /// User request message, [1] is message number in Error table.
33
- /// </summary>
34
- User = 0x03000000,
35
-
36
- /// <summary>
37
- /// Informative message for log, not to be displayed.
38
- /// </summary>
39
- Info = 0x04000000,
40
-
41
- /// <summary>
42
- /// List of files in use that need to be replaced.
43
- /// </summary>
44
- FilesInUse = 0x05000000,
45
-
46
- /// <summary>
47
- /// Request to determine a valid source location.
48
- /// </summary>
49
- ResolveSource = 0x06000000,
50
-
51
- /// <summary>
52
- /// Insufficient disk space message.
53
- /// </summary>
54
- OutOfDiskSpace = 0x07000000,
55
-
56
- /// <summary>
57
- /// Progress: start of action, [1] action name, [2] description, [3] template for ACTIONDATA messages.
58
- /// </summary>
59
- ActionStart = 0x08000000,
60
-
61
- /// <summary>
62
- /// Action data. Record fields correspond to the template of ACTIONSTART message.
63
- /// </summary>
64
- ActionData = 0x09000000,
65
-
66
- /// <summary>
67
- /// Progress bar information. See the description of record fields below.
68
- /// </summary>
69
- Progress = 0x0A000000,
70
-
71
- /// <summary>
72
- /// To enable the Cancel button set [1] to 2 and [2] to 1. To disable the Cancel button set [1] to 2 and [2] to 0.
73
- /// </summary>
74
- CommonData = 0x0B000000,
75
-
76
- /// <summary>
77
- /// Sent prior to UI initialization, no string data.
78
- /// </summary>
79
- Initilize = 0x0C000000,
80
-
81
- /// <summary>
82
- /// Sent after UI termination, no string data.
83
- /// </summary>
84
- Terminate = 0x0D000000,
85
-
86
- /// <summary>
87
- /// Sent prior to display or authored dialog or wizard.
88
- /// </summary>
89
- ShowDialog = 0x0E000000
90
- }
91
-
92
- /// <summary>
93
- /// Windows Installer log modes.
94
- /// </summary>
95
- [Flags]
96
- internal enum InstallLogModes
97
- {
98
- /// <summary>
99
- /// Premature termination of installation.
100
- /// </summary>
101
- FatalExit = (1 << ((int)InstallMessage.FatalExit >> 24)),
102
-
103
- /// <summary>
104
- /// The error messages are logged.
105
- /// </summary>
106
- Error = (1 << ((int)InstallMessage.Error >> 24)),
107
-
108
- /// <summary>
109
- /// The warning messages are logged.
110
- /// </summary>
111
- Warning = (1 << ((int)InstallMessage.Warning >> 24)),
112
-
113
- /// <summary>
114
- /// The user requests are logged.
115
- /// </summary>
116
- User = (1 << ((int)InstallMessage.User >> 24)),
117
-
118
- /// <summary>
119
- /// The status messages that are not displayed are logged.
120
- /// </summary>
121
- Info = (1 << ((int)InstallMessage.Info >> 24)),
122
-
123
- /// <summary>
124
- /// Request to determine a valid source location.
125
- /// </summary>
126
- ResolveSource = (1 << ((int)InstallMessage.ResolveSource >> 24)),
127
-
128
- /// <summary>
129
- /// The was insufficient disk space.
130
- /// </summary>
131
- OutOfDiskSpace = (1 << ((int)InstallMessage.OutOfDiskSpace >> 24)),
132
-
133
- /// <summary>
134
- /// The start of new installation actions are logged.
135
- /// </summary>
136
- ActionStart = (1 << ((int)InstallMessage.ActionStart >> 24)),
137
-
138
- /// <summary>
139
- /// The data record with the installation action is logged.
140
- /// </summary>
141
- ActionData = (1 << ((int)InstallMessage.ActionData >> 24)),
142
-
143
- /// <summary>
144
- /// The parameters for user-interface initialization are logged.
145
- /// </summary>
146
- CommonData = (1 << ((int)InstallMessage.CommonData >> 24)),
147
-
148
- /// <summary>
149
- /// Logs the property values at termination.
150
- /// </summary>
151
- PropertyDump = (1 << ((int)InstallMessage.Progress >> 24)),
152
-
153
- /// <summary>
154
- /// Sends large amounts of information to a log file not generally useful to users.
155
- /// May be used for technical support.
156
- /// </summary>
157
- Verbose = (1 << ((int)InstallMessage.Initilize >> 24)),
158
-
159
- /// <summary>
160
- /// Sends extra debugging information, such as handle creation information, to the log file.
161
- /// </summary>
162
- ExtraDebug = (1 << ((int)InstallMessage.Terminate >> 24)),
163
-
164
- /// <summary>
165
- /// Progress bar information. This message includes information on units so far and total number of units.
166
- /// See MsiProcessMessage for an explanation of the message format.
167
- /// This message is only sent to an external user interface and is not logged.
168
- /// </summary>
169
- Progress = (1 << ((int)InstallMessage.Progress >> 24)),
170
-
171
- /// <summary>
172
- /// If this is not a quiet installation, then the basic UI has been initialized.
173
- /// If this is a full UI installation, the full UI is not yet initialized.
174
- /// This message is only sent to an external user interface and is not logged.
175
- /// </summary>
176
- Initialize = (1 << ((int)InstallMessage.Initilize >> 24)),
177
-
178
- /// <summary>
179
- /// If a full UI is being used, the full UI has ended.
180
- /// If this is not a quiet installation, the basic UI has not yet ended.
181
- /// This message is only sent to an external user interface and is not logged.
182
- /// </summary>
183
- Terminate = (1 << ((int)InstallMessage.Terminate >> 24)),
184
-
185
- /// <summary>
186
- /// Sent prior to display of the full UI dialog.
187
- /// This message is only sent to an external user interface and is not logged.
188
- /// </summary>
189
- ShowDialog = (1 << ((int)InstallMessage.ShowDialog >> 24)),
190
-
191
- /// <summary>
192
- /// Files in use information. When this message is received, a FilesInUse Dialog should be displayed.
193
- /// </summary>
194
- FilesInUse = (1 << ((int)InstallMessage.FilesInUse >> 24))
195
- }
196
-
197
- /// <summary>
198
- /// Windows Installer UI levels.
199
- /// </summary>
200
- [Flags]
201
- internal enum InstallUILevels
202
- {
203
- /// <summary>
204
- /// No change in the UI level. However, if phWnd is not Null, the parent window can change.
205
- /// </summary>
206
- NoChange = 0,
207
-
208
- /// <summary>
209
- /// The installer chooses an appropriate user interface level.
210
- /// </summary>
211
- Default = 1,
212
-
213
- /// <summary>
214
- /// Completely silent installation.
215
- /// </summary>
216
- None = 2,
217
-
218
- /// <summary>
219
- /// Simple progress and error handling.
220
- /// </summary>
221
- Basic = 3,
222
-
223
- /// <summary>
224
- /// Authored user interface with wizard dialog boxes suppressed.
225
- /// </summary>
226
- Reduced = 4,
227
-
228
- /// <summary>
229
- /// Authored user interface with wizards, progress, and errors.
230
- /// </summary>
231
- Full = 5,
232
-
233
- /// <summary>
234
- /// If combined with the Basic value, the installer shows simple progress dialog boxes but
235
- /// does not display a Cancel button on the dialog. This prevents users from canceling the install.
236
- /// Available with Windows Installer version 2.0.
237
- /// </summary>
238
- HideCancel = 0x20,
239
-
240
- /// <summary>
241
- /// If combined with the Basic value, the installer shows simple progress
242
- /// dialog boxes but does not display any modal dialog boxes or error dialog boxes.
243
- /// </summary>
244
- ProgressOnly = 0x40,
245
-
246
- /// <summary>
247
- /// If combined with any above value, the installer displays a modal dialog
248
- /// box at the end of a successful installation or if there has been an error.
249
- /// No dialog box is displayed if the user cancels.
250
- /// </summary>
251
- EndDialog = 0x80,
252
-
253
- /// <summary>
254
- /// If this value is combined with the None value, the installer displays only the dialog
255
- /// boxes used for source resolution. No other dialog boxes are shown. This value has no
256
- /// effect if the UI level is not INSTALLUILEVEL_NONE. It is used with an external user
257
- /// interface designed to handle all of the UI except for source resolution. In this case,
258
- /// the installer handles source resolution. This value is only available with Windows Installer 2.0 and later.
259
- /// </summary>
260
- SourceResOnly = 0x100
261
- }
262
-
263
- /// <summary>
264
- /// Represents the Windows Installer, provides wrappers to
265
- /// create the top-level objects and access their methods.
266
- /// </summary>
267
- internal sealed class Installer
268
- {
269
- /// <summary>
270
- /// Protect the constructor.
271
- /// </summary>
272
- private Installer()
273
- {
274
- }
275
-
276
- /// <summary>
277
- /// Takes the path to a file and returns a 128-bit hash of that file.
278
- /// </summary>
279
- /// <param name="filePath">Path to file that is to be hashed.</param>
280
- /// <param name="options">The value in this column must be 0. This parameter is reserved for future use.</param>
281
- /// <param name="hash">Int array that receives the returned file hash information.</param>
282
- internal static void GetFileHash(string filePath, int options, out int[] hash)
283
- {
284
- MSIFILEHASHINFO hashInterop = new MSIFILEHASHINFO();
285
- hashInterop.FileHashInfoSize = 20;
286
-
287
- int error = MsiInterop.MsiGetFileHash(filePath, Convert.ToUInt32(options), hashInterop);
288
- if (0 != error)
289
- {
290
- throw new MsiException(error);
291
- }
292
-
293
- Debug.Assert(20 == hashInterop.FileHashInfoSize);
294
-
295
- hash = new int[4];
296
- hash[0] = hashInterop.Data0;
297
- hash[1] = hashInterop.Data1;
298
- hash[2] = hashInterop.Data2;
299
- hash[3] = hashInterop.Data3;
300
- }
301
-
302
- /// <summary>
303
- /// Returns the version string and language string in the format that the installer
304
- /// expects to find them in the database. If you just want version information, set
305
- /// lpLangBuf and pcchLangBuf to zero. If you just want language information, set
306
- /// lpVersionBuf and pcchVersionBuf to zero.
307
- /// </summary>
308
- /// <param name="filePath">Specifies the path to the file.</param>
309
- /// <param name="version">Returns the file version. Set to 0 for language information only.</param>
310
- /// <param name="language">Returns the file language. Set to 0 for version information only.</param>
311
- internal static void GetFileVersion(string filePath, out string version, out string language)
312
- {
313
- int versionLength = 20;
314
- int languageLength = 20;
315
- StringBuilder versionBuffer = new StringBuilder(versionLength);
316
- StringBuilder languageBuffer = new StringBuilder(languageLength);
317
-
318
- int error = MsiInterop.MsiGetFileVersion(filePath, versionBuffer, ref versionLength, languageBuffer, ref languageLength);
319
- if (234 == error)
320
- {
321
- versionBuffer.EnsureCapacity(++versionLength);
322
- languageBuffer.EnsureCapacity(++languageLength);
323
- error = MsiInterop.MsiGetFileVersion(filePath, versionBuffer, ref versionLength, languageBuffer, ref languageLength);
324
- }
325
- else if (1006 == error)
326
- {
327
- // file has no version or language, so no error
328
- error = 0;
329
- }
330
-
331
- if (0 != error)
332
- {
333
- throw new MsiException(error);
334
- }
335
-
336
- version = versionBuffer.ToString();
337
- language = languageBuffer.ToString();
338
- }
339
-
340
- /// <summary>
341
- /// Enables an external user-interface handler.
342
- /// </summary>
343
- /// <param name="installUIHandler">Specifies a callback function.</param>
344
- /// <param name="messageFilter">Specifies which messages to handle using the external message handler.</param>
345
- /// <param name="context">Pointer to an application context that is passed to the callback function.</param>
346
- /// <returns>The return value is the previously set external handler, or null if there was no previously set handler.</returns>
347
- internal static InstallUIHandler SetExternalUI(InstallUIHandler installUIHandler, int messageFilter, IntPtr context)
348
- {
349
- return MsiInterop.MsiSetExternalUI(installUIHandler, messageFilter, context);
350
- }
351
-
352
- /// <summary>
353
- /// Enables the installer's internal user interface.
354
- /// </summary>
355
- /// <param name="uiLevel">Specifies the level of complexity of the user interface.</param>
356
- /// <param name="hwnd">Pointer to a window. This window becomes the owner of any user interface created.</param>
357
- /// <returns>The previous user interface level is returned. If an invalid dwUILevel is passed, then INSTALLUILEVEL_NOCHANGE is returned.</returns>
358
- internal static int SetInternalUI(int uiLevel, ref IntPtr hwnd)
359
- {
360
- return MsiInterop.MsiSetInternalUI(uiLevel, ref hwnd);
361
- }
362
- }
363
-}
src/WixToolset.Core.WindowsInstaller/Msi/MsiException.cs
deleted
-77
@@ -1,77 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.ComponentModel;
7
-
8
- /// <summary>
9
- /// Exception that wraps MsiGetLastError().
10
- /// </summary>
11
- [Serializable]
12
- public class MsiException : Win32Exception
13
- {
14
- /// <summary>
15
- /// Instantiate a new MsiException with a given error.
16
- /// </summary>
17
- /// <param name="error">The error code from the MsiXxx() function call.</param>
18
- public MsiException(int error) : base(error)
19
- {
20
- uint handle = MsiInterop.MsiGetLastErrorRecord();
21
- if (0 != handle)
22
- {
23
- using (Record record = new Record(handle))
24
- {
25
- this.MsiError = record.GetInteger(1);
26
-
27
- int errorInfoCount = record.GetFieldCount() - 1;
28
- this.ErrorInfo = new string[errorInfoCount];
29
- for (int i = 0; i < errorInfoCount; ++i)
30
- {
31
- this.ErrorInfo[i] = record.GetString(i + 2);
32
- }
33
- }
34
- }
35
- else
36
- {
37
- this.MsiError = 0;
38
- this.ErrorInfo = new string[0];
39
- }
40
-
41
- this.Error = error;
42
- }
43
-
44
- /// <summary>
45
- /// Gets the error number.
46
- /// </summary>
47
- public int Error { get; private set; }
48
-
49
- /// <summary>
50
- /// Gets the internal MSI error number.
51
- /// </summary>
52
- public int MsiError { get; private set; }
53
-
54
- /// <summary>
55
- /// Gets any additional the error information.
56
- /// </summary>
57
- public string[] ErrorInfo { get; private set; }
58
-
59
- /// <summary>
60
- /// Overrides Message property to return useful error message.
61
- /// </summary>
62
- public override string Message
63
- {
64
- get
65
- {
66
- if (0 == this.MsiError)
67
- {
68
- return base.Message;
69
- }
70
- else
71
- {
72
- return String.Format("Internal MSI failure. Win32 error: {0}, MSI error: {1}, detail: {2}", this.Error, this.MsiError, String.Join(", ", this.ErrorInfo));
73
- }
74
- }
75
- }
76
- }
77
-}
src/WixToolset.Core.WindowsInstaller/Msi/MsiHandle.cs
deleted
-117
@@ -1,117 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.ComponentModel;
7
-#if !DEBUG
8
- using System.Diagnostics;
9
-#endif
10
- using System.Threading;
11
-
12
- /// <summary>
13
- /// Wrapper class for MSI handle.
14
- /// </summary>
15
- public class MsiHandle : IDisposable
16
- {
17
- private bool disposed;
18
- private uint handle;
19
- private int owningThread;
20
-#if DEBUG
21
- private string creationStack;
22
-#endif
23
-
24
- /// <summary>
25
- /// MSI handle destructor.
26
- /// </summary>
27
- ~MsiHandle()
28
- {
29
- this.Dispose(false);
30
- }
31
-
32
- /// <summary>
33
- /// Gets or sets the MSI handle.
34
- /// </summary>
35
- /// <value>The MSI handle.</value>
36
- internal uint Handle
37
- {
38
- get
39
- {
40
- if (this.disposed)
41
- {
42
- throw new ObjectDisposedException("MsiHandle");
43
- }
44
-
45
- return this.handle;
46
- }
47
-
48
- set
49
- {
50
- if (this.disposed)
51
- {
52
- throw new ObjectDisposedException("MsiHandle");
53
- }
54
-
55
- this.handle = value;
56
- this.owningThread = Thread.CurrentThread.ManagedThreadId;
57
-#if DEBUG
58
- this.creationStack = Environment.StackTrace;
59
-#endif
60
- }
61
- }
62
-
63
- /// <summary>
64
- /// Close the MSI handle.
65
- /// </summary>
66
- public void Close()
67
- {
68
- this.Dispose();
69
- }
70
-
71
- /// <summary>
72
- /// Disposes the managed and unmanaged objects in this object.
73
- /// </summary>
74
- public void Dispose()
75
- {
76
- this.Dispose(true);
77
- GC.SuppressFinalize(this);
78
- }
79
-
80
- /// <summary>
81
- /// Disposes the managed and unmanaged objects in this object.
82
- /// </summary>
83
- /// <param name="disposing">true to dispose the managed objects.</param>
84
- protected virtual void Dispose(bool disposing)
85
- {
86
- if (!this.disposed)
87
- {
88
- if (0 != this.handle)
89
- {
90
- if (Thread.CurrentThread.ManagedThreadId == this.owningThread)
91
- {
92
- int error = MsiInterop.MsiCloseHandle(this.handle);
93
- if (0 != error)
94
- {
95
- throw new Win32Exception(error);
96
- }
97
- this.handle = 0;
98
- }
99
- else
100
- {
101
- // Don't try to close the handle on a different thread than it was opened.
102
- // This will occasionally cause MSI to AV.
103
- string message = String.Format("Leaked msi handle {0} created on thread {1} by type {2}. This handle cannot be closed on thread {3}",
104
- this.handle, this.owningThread, this.GetType(), Thread.CurrentThread.ManagedThreadId);
105
-#if DEBUG
106
- throw new InvalidOperationException(String.Format("{0}. Created {1}", message, this.creationStack));
107
-#else
108
- Debug.WriteLine(message);
109
-#endif
110
- }
111
- }
112
-
113
- this.disposed = true;
114
- }
115
- }
116
- }
117
-}
src/WixToolset.Core.WindowsInstaller/Msi/MsiInterop.cs
deleted
-571
@@ -1,571 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.Text;
7
- using System.Runtime.InteropServices;
8
- using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
9
- using WixToolset.Core.Native;
10
-
11
- /// <summary>
12
- /// A callback function that the installer calls for progress notification and error messages.
13
- /// </summary>
14
- /// <param name="context">Pointer to an application context.
15
- /// This parameter can be used for error checking.</param>
16
- /// <param name="messageType">Specifies a combination of one message box style,
17
- /// one message box icon type, one default button, and one installation message type.</param>
18
- /// <param name="message">Specifies the message text.</param>
19
- /// <returns>-1 for an error, 0 if no action was taken, 1 if OK, 3 to abort.</returns>
20
- public delegate int InstallUIHandler(IntPtr context, uint messageType, [MarshalAs(UnmanagedType.LPWStr)] string message);
21
-
22
- /// <summary>
23
- /// Enum of predefined persist modes used when opening a database.
24
- /// </summary>
25
- public enum OpenDatabase
26
- {
27
- /// <summary>
28
- /// Open a database read-only, no persistent changes.
29
- /// </summary>
30
- ReadOnly = 0,
31
-
32
- /// <summary>
33
- /// Open a database read/write in transaction mode.
34
- /// </summary>
35
- Transact = 1,
36
-
37
- /// <summary>
38
- /// Open a database direct read/write without transaction.
39
- /// </summary>
40
- Direct = 2,
41
-
42
- /// <summary>
43
- /// Create a new database, transact mode read/write.
44
- /// </summary>
45
- Create = 3,
46
-
47
- /// <summary>
48
- /// Create a new database, direct mode read/write.
49
- /// </summary>
50
- CreateDirect = 4,
51
-
52
- /// <summary>
53
- /// Indicates a patch file is being opened.
54
- /// </summary>
55
- OpenPatchFile = 32
56
- }
57
-
58
- /// <summary>
59
- /// The errors to suppress when applying a transform.
60
- /// </summary>
61
- [Flags]
62
- public enum TransformErrorConditions
63
- {
64
- /// <summary>
65
- /// None of the following conditions.
66
- /// </summary>
67
- None = 0x0,
68
-
69
- /// <summary>
70
- /// Suppress error when adding a row that exists.
71
- /// </summary>
72
- AddExistingRow = 0x1,
73
-
74
- /// <summary>
75
- /// Suppress error when deleting a row that does not exist.
76
- /// </summary>
77
- DeleteMissingRow = 0x2,
78
-
79
- /// <summary>
80
- /// Suppress error when adding a table that exists.
81
- /// </summary>
82
- AddExistingTable = 0x4,
83
-
84
- /// <summary>
85
- /// Suppress error when deleting a table that does not exist.
86
- /// </summary>
87
- DeleteMissingTable = 0x8,
88
-
89
- /// <summary>
90
- /// Suppress error when updating a row that does not exist.
91
- /// </summary>
92
- UpdateMissingRow = 0x10,
93
-
94
- /// <summary>
95
- /// Suppress error when transform and database code pages do not match, and their code pages are neutral.
96
- /// </summary>
97
- ChangeCodepage = 0x20,
98
-
99
- /// <summary>
100
- /// Create the temporary _TransformView table when applying a transform.
101
- /// </summary>
102
- ViewTransform = 0x100,
103
-
104
- /// <summary>
105
- /// Suppress all errors but the option to create the temporary _TransformView table.
106
- /// </summary>
107
- All = 0x3F
108
- }
109
-
110
- /// <summary>
111
- /// The validation to run while applying a transform.
112
- /// </summary>
113
- [Flags]
114
- public enum TransformValidations
115
- {
116
- /// <summary>
117
- /// Do not validate properties.
118
- /// </summary>
119
- None = 0x0,
120
-
121
- /// <summary>
122
- /// Default language must match base database.
123
- /// </summary>
124
- Language = 0x1,
125
-
126
- /// <summary>
127
- /// Product must match base database.
128
- /// </summary>
129
- Product = 0x2,
130
-
131
- /// <summary>
132
- /// Check major version only.
133
- /// </summary>
134
- MajorVersion = 0x8,
135
-
136
- /// <summary>
137
- /// Check major and minor versions only.
138
- /// </summary>
139
- MinorVersion = 0x10,
140
-
141
- /// <summary>
142
- /// Check major, minor, and update versions.
143
- /// </summary>
144
- UpdateVersion = 0x20,
145
-
146
- /// <summary>
147
- /// Installed version < base version.
148
- /// </summary>
149
- NewLessBaseVersion = 0x40,
150
-
151
- /// <summary>
152
- /// Installed version <= base version.
153
- /// </summary>
154
- NewLessEqualBaseVersion = 0x80,
155
-
156
- /// <summary>
157
- /// Installed version = base version.
158
- /// </summary>
159
- NewEqualBaseVersion = 0x100,
160
-
161
- /// <summary>
162
- /// Installed version >= base version.
163
- /// </summary>
164
- NewGreaterEqualBaseVersion = 0x200,
165
-
166
- /// <summary>
167
- /// Installed version > base version.
168
- /// </summary>
169
- NewGreaterBaseVersion = 0x400,
170
-
171
- /// <summary>
172
- /// UpgradeCode must match base database.
173
- /// </summary>
174
- UpgradeCode = 0x800
175
- }
176
-
177
- /// <summary>
178
- /// Class exposing static functions and structs from MSI API.
179
- /// </summary>
180
- internal sealed class MsiInterop
181
- {
182
- // Patching constants
183
- public const int MsiMaxStreamNameLength = 62; // http://msdn2.microsoft.com/library/aa370551.aspx
184
-
185
- public const int MSICONDITIONFALSE = 0; // The table is temporary.
186
- public const int MSICONDITIONTRUE = 1; // The table is persistent.
187
- public const int MSICONDITIONNONE = 2; // The table is unknown.
188
- public const int MSICONDITIONERROR = 3; // An invalid handle or invalid parameter was passed to the function.
189
- /*
190
- public const int MSIDBOPENREADONLY = 0;
191
- public const int MSIDBOPENTRANSACT = 1;
192
- public const int MSIDBOPENDIRECT = 2;
193
- public const int MSIDBOPENCREATE = 3;
194
- public const int MSIDBOPENCREATEDIRECT = 4;
195
- public const int MSIDBOPENPATCHFILE = 32;
196
-
197
- public const int MSIMODIFYSEEK = -1; // Refreshes the information in the supplied record without changing the position in the result set and without affecting subsequent fetch operations. The record may then be used for subsequent Update, Delete, and Refresh. All primary key columns of the table must be in the query and the record must have at least as many fields as the query. Seek cannot be used with multi-table queries. This mode cannot be used with a view containing joins. See also the remarks.
198
- public const int MSIMODIFYREFRESH = 0; // Refreshes the information in the record. Must first call MsiViewFetch with the same record. Fails for a deleted row. Works with read-write and read-only records.
199
- public const int MSIMODIFYINSERT = 1; // Inserts a record. Fails if a row with the same primary keys exists. Fails with a read-only database. This mode cannot be used with a view containing joins.
200
- public const int MSIMODIFYUPDATE = 2; // Updates an existing record. Nonprimary keys only. Must first call MsiViewFetch. Fails with a deleted record. Works only with read-write records.
201
- public const int MSIMODIFYASSIGN = 3; // Writes current data in the cursor to a table row. Updates record if the primary keys match an existing row and inserts if they do not match. Fails with a read-only database. This mode cannot be used with a view containing joins.
202
- public const int MSIMODIFYREPLACE = 4; // Updates or deletes and inserts a record into a table. Must first call MsiViewFetch with the same record. Updates record if the primary keys are unchanged. Deletes old row and inserts new if primary keys have changed. Fails with a read-only database. This mode cannot be used with a view containing joins.
203
- public const int MSIMODIFYMERGE = 5; // Inserts or validates a record in a table. Inserts if primary keys do not match any row and validates if there is a match. Fails if the record does not match the data in the table. Fails if there is a record with a duplicate key that is not identical. Works only with read-write records. This mode cannot be used with a view containing joins.
204
- public const int MSIMODIFYDELETE = 6; // Remove a row from the table. You must first call the MsiViewFetch function with the same record. Fails if the row has been deleted. Works only with read-write records. This mode cannot be used with a view containing joins.
205
- public const int MSIMODIFYINSERTTEMPORARY = 7; // Inserts a temporary record. The information is not persistent. Fails if a row with the same primary key exists. Works only with read-write records. This mode cannot be used with a view containing joins.
206
- public const int MSIMODIFYVALIDATE = 8; // Validates a record. Does not validate across joins. You must first call the MsiViewFetch function with the same record. Obtain validation errors with MsiViewGetError. Works with read-write and read-only records. This mode cannot be used with a view containing joins.
207
- public const int MSIMODIFYVALIDATENEW = 9; // Validate a new record. Does not validate across joins. Checks for duplicate keys. Obtain validation errors by calling MsiViewGetError. Works with read-write and read-only records. This mode cannot be used with a view containing joins.
208
- public const int MSIMODIFYVALIDATEFIELD = 10; // Validates fields of a fetched or new record. Can validate one or more fields of an incomplete record. Obtain validation errors by calling MsiViewGetError. Works with read-write and read-only records. This mode cannot be used with a view containing joins.
209
- public const int MSIMODIFYVALIDATEDELETE = 11; // Validates a record that will be deleted later. You must first call MsiViewFetch. Fails if another row refers to the primary keys of this row. Validation does not check for the existence of the primary keys of this row in properties or strings. Does not check if a column is a foreign key to multiple tables. Obtain validation errors by calling MsiViewGetError. Works with read-write and read-only records. This mode cannot be used with a view containing joins.
210
-
211
- public const uint VTI2 = 2;
212
- public const uint VTI4 = 3;
213
- public const uint VTLPWSTR = 30;
214
- public const uint VTFILETIME = 64;
215
- */
216
-
217
- public const int MSICOLINFONAMES = 0; // return column names
218
- public const int MSICOLINFOTYPES = 1; // return column definitions, datatype code followed by width
219
-
220
- /// <summary>
221
- /// Protect the constructor.
222
- /// </summary>
223
- private MsiInterop()
224
- {
225
- }
226
-
227
- /// <summary>
228
- /// PInvoke of MsiCloseHandle.
229
- /// </summary>
230
- /// <param name="database">Handle to a database.</param>
231
- /// <returns>Error code.</returns>
232
- [DllImport("msi.dll", EntryPoint = "MsiCloseHandle", CharSet = CharSet.Unicode, ExactSpelling = true)]
233
- public static extern int MsiCloseHandle(uint database);
234
-
235
- /// <summary>
236
- /// PInvoke of MsiCreateRecord
237
- /// </summary>
238
- /// <param name="parameters">Count of columns in the record.</param>
239
- /// <returns>Handle referencing the record.</returns>
240
- [DllImport("msi.dll", EntryPoint = "MsiCreateRecord", CharSet = CharSet.Unicode, ExactSpelling = true)]
241
- public static extern uint MsiCreateRecord(int parameters);
242
-
243
- /// <summary>
244
- /// Creates summary information of an existing transform to include validation and error conditions.
245
- /// </summary>
246
- /// <param name="database">The handle to the database that contains the new database summary information.</param>
247
- /// <param name="referenceDatabase">The handle to the database that contains the original summary information.</param>
248
- /// <param name="transformFile">The name of the transform to which the summary information is added.</param>
249
- /// <param name="errorConditions">The error conditions that should be suppressed when the transform is applied.</param>
250
- /// <param name="validations">Specifies the properties to be validated to verify that the transform can be applied to the database.</param>
251
- /// <returns>Error code.</returns>
252
- [DllImport("msi.dll", EntryPoint = "MsiCreateTransformSummaryInfoW", CharSet = CharSet.Unicode, ExactSpelling = true)]
253
- public static extern int MsiCreateTransformSummaryInfo(uint database, uint referenceDatabase, string transformFile, TransformErrorConditions errorConditions, TransformValidations validations);
254
-
255
- /// <summary>
256
- /// Applies a transform to a database.
257
- /// </summary>
258
- /// <param name="database">Handle to the database obtained from MsiOpenDatabase to transform.</param>
259
- /// <param name="transformFile">Specifies the name of the transform file to apply.</param>
260
- /// <param name="errorConditions">Error conditions that should be suppressed.</param>
261
- /// <returns>Error code.</returns>
262
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseApplyTransformW", CharSet = CharSet.Unicode, ExactSpelling = true)]
263
- public static extern int MsiDatabaseApplyTransform(uint database, string transformFile, TransformErrorConditions errorConditions);
264
-
265
- /// <summary>
266
- /// PInvoke of MsiDatabaseCommit.
267
- /// </summary>
268
- /// <param name="database">Handle to a databse.</param>
269
- /// <returns>Error code.</returns>
270
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseCommit", CharSet = CharSet.Unicode, ExactSpelling = true)]
271
- public static extern int MsiDatabaseCommit(uint database);
272
-
273
- /// <summary>
274
- /// PInvoke of MsiDatabaseExportW.
275
- /// </summary>
276
- /// <param name="database">Handle to a database.</param>
277
- /// <param name="tableName">Table name.</param>
278
- /// <param name="folderPath">Folder path.</param>
279
- /// <param name="fileName">File name.</param>
280
- /// <returns>Error code.</returns>
281
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseExportW", CharSet = CharSet.Unicode, ExactSpelling = true)]
282
- public static extern int MsiDatabaseExport(uint database, string tableName, string folderPath, string fileName);
283
-
284
- /// <summary>
285
- /// Generates a transform file of differences between two databases.
286
- /// </summary>
287
- /// <param name="database">Handle to the database obtained from MsiOpenDatabase that includes the changes.</param>
288
- /// <param name="databaseReference">Handle to the database obtained from MsiOpenDatabase that does not include the changes.</param>
289
- /// <param name="transformFile">A null-terminated string that specifies the name of the transform file being generated.
290
- /// This parameter can be null. If szTransformFile is null, you can use MsiDatabaseGenerateTransform to test whether two
291
- /// databases are identical without creating a transform. If the databases are identical, the function returns ERROR_NO_DATA.
292
- /// If the databases are different the function returns NOERROR.</param>
293
- /// <param name="reserved1">This is a reserved argument and must be set to 0.</param>
294
- /// <param name="reserved2">This is a reserved argument and must be set to 0.</param>
295
- /// <returns>Error code.</returns>
296
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseGenerateTransformW", CharSet = CharSet.Unicode, ExactSpelling = true)]
297
- public static extern int MsiDatabaseGenerateTransform(uint database, uint databaseReference, string transformFile, int reserved1, int reserved2);
298
-
299
- /// <summary>
300
- /// PInvoke of MsiDatabaseImportW.
301
- /// </summary>
302
- /// <param name="database">Handle to a database.</param>
303
- /// <param name="folderPath">Folder path.</param>
304
- /// <param name="fileName">File name.</param>
305
- /// <returns>Error code.</returns>
306
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseImportW", CharSet = CharSet.Unicode, ExactSpelling = true)]
307
- public static extern int MsiDatabaseImport(uint database, string folderPath, string fileName);
308
-
309
- /// <summary>
310
- /// PInvoke of MsiDatabaseMergeW.
311
- /// </summary>
312
- /// <param name="database">The handle to the database obtained from MsiOpenDatabase.</param>
313
- /// <param name="databaseMerge">The handle to the database obtained from MsiOpenDatabase to merge into the base database.</param>
314
- /// <param name="tableName">The name of the table to receive merge conflict information.</param>
315
- /// <returns>Error code.</returns>
316
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseMergeW", CharSet = CharSet.Unicode, ExactSpelling = true)]
317
- public static extern int MsiDatabaseMerge(uint database, uint databaseMerge, string tableName);
318
-
319
- /// <summary>
320
- /// PInvoke of MsiDatabaseOpenViewW.
321
- /// </summary>
322
- /// <param name="database">Handle to a database.</param>
323
- /// <param name="query">SQL query.</param>
324
- /// <param name="view">View handle.</param>
325
- /// <returns>Error code.</returns>
326
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseOpenViewW", CharSet = CharSet.Unicode, ExactSpelling = true)]
327
- public static extern int MsiDatabaseOpenView(uint database, string query, out uint view);
328
-
329
- /// <summary>
330
- /// PInvoke of MsiGetFileHashW.
331
- /// </summary>
332
- /// <param name="filePath">File path.</param>
333
- /// <param name="options">Hash options (must be 0).</param>
334
- /// <param name="hash">Buffer to recieve hash.</param>
335
- /// <returns>Error code.</returns>
336
- [DllImport("msi.dll", EntryPoint = "MsiGetFileHashW", CharSet = CharSet.Unicode, ExactSpelling = true)]
337
- public static extern int MsiGetFileHash(string filePath, uint options, MSIFILEHASHINFO hash);
338
-
339
- /// <summary>
340
- /// PInvoke of MsiGetFileVersionW.
341
- /// </summary>
342
- /// <param name="filePath">File path.</param>
343
- /// <param name="versionBuf">Buffer to receive version info.</param>
344
- /// <param name="versionBufSize">Size of version buffer.</param>
345
- /// <param name="langBuf">Buffer to recieve lang info.</param>
346
- /// <param name="langBufSize">Size of lang buffer.</param>
347
- /// <returns>Error code.</returns>
348
- [DllImport("msi.dll", EntryPoint = "MsiGetFileVersionW", CharSet = CharSet.Unicode, ExactSpelling = true)]
349
- public static extern int MsiGetFileVersion(string filePath, StringBuilder versionBuf, ref int versionBufSize, StringBuilder langBuf, ref int langBufSize);
350
-
351
- /// <summary>
352
- /// PInvoke of MsiGetLastErrorRecord.
353
- /// </summary>
354
- /// <returns>Handle to error record if one exists.</returns>
355
- [DllImport("msi.dll", EntryPoint = "MsiGetLastErrorRecord", CharSet = CharSet.Unicode, ExactSpelling = true)]
356
- public static extern uint MsiGetLastErrorRecord();
357
-
358
- /// <summary>
359
- /// PInvoke of MsiDatabaseGetPrimaryKeysW.
360
- /// </summary>
361
- /// <param name="database">Handle to a database.</param>
362
- /// <param name="tableName">Table name.</param>
363
- /// <param name="record">Handle to receive resulting record.</param>
364
- /// <returns>Error code.</returns>
365
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseGetPrimaryKeysW", CharSet = CharSet.Unicode, ExactSpelling = true)]
366
- public static extern int MsiDatabaseGetPrimaryKeys(uint database, string tableName, out uint record);
367
-
368
- /// <summary>
369
- /// PInvoke of MsiDoActionW.
370
- /// </summary>
371
- /// <param name="product">Handle to the installation provided to a DLL custom action or
372
- /// obtained through MsiOpenPackage, MsiOpenPackageEx, or MsiOpenProduct.</param>
373
- /// <param name="action">Specifies the action to execute.</param>
374
- /// <returns>Error code.</returns>
375
- [DllImport("msi.dll", EntryPoint = "MsiDoActionW", CharSet = CharSet.Unicode, ExactSpelling = true)]
376
- public static extern int MsiDoAction(uint product, string action);
377
-
378
- /// <summary>
379
- /// PInvoke of MsiGetSummaryInformationW. Can use either database handle or database path as input.
380
- /// </summary>
381
- /// <param name="database">Handle to a database.</param>
382
- /// <param name="databasePath">Path to a database.</param>
383
- /// <param name="updateCount">Max number of updated values.</param>
384
- /// <param name="summaryInfo">Handle to summary information.</param>
385
- /// <returns>Error code.</returns>
386
- [DllImport("msi.dll", EntryPoint = "MsiGetSummaryInformationW", CharSet = CharSet.Unicode, ExactSpelling = true)]
387
- public static extern int MsiGetSummaryInformation(uint database, string databasePath, uint updateCount, ref uint summaryInfo);
388
-
389
- /// <summary>
390
- /// PInvoke of MsiDatabaseIsTablePersitentW.
391
- /// </summary>
392
- /// <param name="database">Handle to a database.</param>
393
- /// <param name="tableName">Table name.</param>
394
- /// <returns>MSICONDITION</returns>
395
- [DllImport("msi.dll", EntryPoint = "MsiDatabaseIsTablePersistentW", CharSet = CharSet.Unicode, ExactSpelling = true)]
396
- public static extern int MsiDatabaseIsTablePersistent(uint database, string tableName);
397
-
398
- /// <summary>
399
- /// PInvoke of MsiOpenDatabaseW.
400
- /// </summary>
401
- /// <param name="databasePath">Path to database.</param>
402
- /// <param name="persist">Persist mode.</param>
403
- /// <param name="database">Handle to database.</param>
404
- /// <returns>Error code.</returns>
405
- [DllImport("msi.dll", EntryPoint = "MsiOpenDatabaseW", CharSet = CharSet.Unicode, ExactSpelling = true)]
406
- public static extern int MsiOpenDatabase(string databasePath, IntPtr persist, out uint database);
407
-
408
- /// <summary>
409
- /// PInvoke of MsiOpenPackageW.
410
- /// </summary>
411
- /// <param name="packagePath">The path to the package.</param>
412
- /// <param name="product">A pointer to a variable that receives the product handle.</param>
413
- /// <returns>Error code.</returns>
414
- [DllImport("msi.dll", EntryPoint = "MsiOpenPackageW", CharSet = CharSet.Unicode, ExactSpelling = true)]
415
- public static extern int MsiOpenPackage(string packagePath, out uint product);
416
-
417
- /// <summary>
418
- /// PInvoke of MsiRecordIsNull.
419
- /// </summary>
420
- /// <param name="record">MSI Record handle.</param>
421
- /// <param name="field">Index of field to check for null value.</param>
422
- /// <returns>true if the field is null, false if not, and an error code for any error.</returns>
423
- [DllImport("msi.dll", EntryPoint = "MsiRecordIsNull", CharSet = CharSet.Unicode, ExactSpelling = true)]
424
- public static extern int MsiRecordIsNull(uint record, int field);
425
-
426
- /// <summary>
427
- /// PInvoke of MsiRecordGetInteger.
428
- /// </summary>
429
- /// <param name="record">MSI Record handle.</param>
430
- /// <param name="field">Index of field to retrieve integer from.</param>
431
- /// <returns>Integer value.</returns>
432
- [DllImport("msi.dll", EntryPoint = "MsiRecordGetInteger", CharSet = CharSet.Unicode, ExactSpelling = true)]
433
- public static extern int MsiRecordGetInteger(uint record, int field);
434
-
435
- /// <summary>
436
- /// PInvoke of MsiRectordSetInteger.
437
- /// </summary>
438
- /// <param name="record">MSI Record handle.</param>
439
- /// <param name="field">Index of field to set integer value in.</param>
440
- /// <param name="value">Value to set field to.</param>
441
- /// <returns>Error code.</returns>
442
- [DllImport("msi.dll", EntryPoint = "MsiRecordSetInteger", CharSet = CharSet.Unicode, ExactSpelling = true)]
443
- public static extern int MsiRecordSetInteger(uint record, int field, int value);
444
-
445
- /// <summary>
446
- /// PInvoke of MsiRecordGetStringW.
447
- /// </summary>
448
- /// <param name="record">MSI Record handle.</param>
449
- /// <param name="field">Index of field to get string value from.</param>
450
- /// <param name="valueBuf">Buffer to recieve value.</param>
451
- /// <param name="valueBufSize">Size of buffer.</param>
452
- /// <returns>Error code.</returns>
453
- [DllImport("msi.dll", EntryPoint = "MsiRecordGetStringW", CharSet = CharSet.Unicode, ExactSpelling = true)]
454
- public static extern int MsiRecordGetString(uint record, int field, StringBuilder valueBuf, ref int valueBufSize);
455
-
456
- /// <summary>
457
- /// PInvoke of MsiRecordSetStringW.
458
- /// </summary>
459
- /// <param name="record">MSI Record handle.</param>
460
- /// <param name="field">Index of field to set string value in.</param>
461
- /// <param name="value">String value.</param>
462
- /// <returns>Error code.</returns>
463
- [DllImport("msi.dll", EntryPoint = "MsiRecordSetStringW", CharSet = CharSet.Unicode, ExactSpelling = true)]
464
- public static extern int MsiRecordSetString(uint record, int field, string value);
465
-
466
- /// <summary>
467
- /// PInvoke of MsiRecordSetStreamW.
468
- /// </summary>
469
- /// <param name="record">MSI Record handle.</param>
470
- /// <param name="field">Index of field to set stream value in.</param>
471
- /// <param name="filePath">Path to file to set stream value to.</param>
472
- /// <returns>Error code.</returns>
473
- [DllImport("msi.dll", EntryPoint = "MsiRecordSetStreamW", CharSet = CharSet.Unicode, ExactSpelling = true)]
474
- public static extern int MsiRecordSetStream(uint record, int field, string filePath);
475
-
476
- /// <summary>
477
- /// PInvoke of MsiRecordReadStreamW.
478
- /// </summary>
479
- /// <param name="record">MSI Record handle.</param>
480
- /// <param name="field">Index of field to read stream from.</param>
481
- /// <param name="dataBuf">Data buffer to recieve stream value.</param>
482
- /// <param name="dataBufSize">Size of data buffer.</param>
483
- /// <returns>Error code.</returns>
484
- [DllImport("msi.dll", EntryPoint = "MsiRecordReadStream", CharSet = CharSet.Unicode, ExactSpelling = true)]
485
- public static extern int MsiRecordReadStream(uint record, int field, byte[] dataBuf, ref int dataBufSize);
486
-
487
- /// <summary>
488
- /// PInvoke of MsiRecordGetFieldCount.
489
- /// </summary>
490
- /// <param name="record">MSI Record handle.</param>
491
- /// <returns>Count of fields in the record.</returns>
492
- [DllImport("msi.dll", EntryPoint = "MsiRecordGetFieldCount", CharSet = CharSet.Unicode, ExactSpelling = true)]
493
- public static extern int MsiRecordGetFieldCount(uint record);
494
-
495
- /// <summary>
496
- /// PInvoke of MsiSetExternalUIW.
497
- /// </summary>
498
- /// <param name="installUIHandler">Specifies a callback function that conforms to the INSTALLUI_HANDLER specification.</param>
499
- /// <param name="installLogMode">Specifies which messages to handle using the external message handler. If the external
500
- /// handler returns a non-zero result, then that message will not be sent to the UI, instead the message will be logged
501
- /// if logging has been enabled.</param>
502
- /// <param name="context">Pointer to an application context that is passed to the callback function.
503
- /// This parameter can be used for error checking.</param>
504
- /// <returns>The return value is the previously set external handler, or zero (0) if there was no previously set handler.</returns>
505
- [DllImport("msi.dll", EntryPoint = "MsiSetExternalUIW", CharSet = CharSet.Unicode, ExactSpelling = true)]
506
- public static extern InstallUIHandler MsiSetExternalUI(InstallUIHandler installUIHandler, int installLogMode, IntPtr context);
507
-
508
- /// <summary>
509
- /// PInvoke of MsiSetpublicUI.
510
- /// </summary>
511
- /// <param name="uiLevel">Specifies the level of complexity of the user interface.</param>
512
- /// <param name="hwnd">Pointer to a window. This window becomes the owner of any user interface created.
513
- /// A pointer to the previous owner of the user interface is returned.
514
- /// If this parameter is null, the owner of the user interface does not change.</param>
515
- /// <returns>The previous user interface level is returned. If an invalid dwUILevel is passed, then INSTALLUILEVEL_NOCHANGE is returned.</returns>
516
- [DllImport("msi.dll", EntryPoint = "MsiSetpublicUI", CharSet = CharSet.Unicode, ExactSpelling = true)]
517
- public static extern int MsiSetInternalUI(int uiLevel, ref IntPtr hwnd);
518
-
519
- /// <summary>
520
- /// PInvoke of MsiSummaryInfoGetPropertyW.
521
- /// </summary>
522
- /// <param name="summaryInfo">Handle to summary info.</param>
523
- /// <param name="property">Property to get value from.</param>
524
- /// <param name="dataType">Data type of property.</param>
525
- /// <param name="integerValue">Integer to receive integer value.</param>
526
- /// <param name="fileTimeValue">File time to receive file time value.</param>
527
- /// <param name="stringValueBuf">String buffer to receive string value.</param>
528
- /// <param name="stringValueBufSize">Size of string buffer.</param>
529
- /// <returns>Error code.</returns>
530
- [DllImport("msi.dll", EntryPoint = "MsiSummaryInfoGetPropertyW", CharSet = CharSet.Unicode, ExactSpelling = true)]
531
- public static extern int MsiSummaryInfoGetProperty(uint summaryInfo, int property, out uint dataType, out int integerValue, ref FILETIME fileTimeValue, StringBuilder stringValueBuf, ref int stringValueBufSize);
532
-
533
- /// <summary>
534
- /// PInvoke of MsiViewGetColumnInfo.
535
- /// </summary>
536
- /// <param name="view">Handle to view.</param>
537
- /// <param name="columnInfo">Column info.</param>
538
- /// <param name="record">Handle for returned record.</param>
539
- /// <returns>Error code.</returns>
540
- [DllImport("msi.dll", EntryPoint = "MsiViewGetColumnInfo", CharSet = CharSet.Unicode, ExactSpelling = true)]
541
- public static extern int MsiViewGetColumnInfo(uint view, int columnInfo, out uint record);
542
-
543
- /// <summary>
544
- /// PInvoke of MsiViewExecute.
545
- /// </summary>
546
- /// <param name="view">Handle of view to execute.</param>
547
- /// <param name="record">Handle to a record that supplies the parameters for the view.</param>
548
- /// <returns>Error code.</returns>
549
- [DllImport("msi.dll", EntryPoint = "MsiViewExecute", CharSet = CharSet.Unicode, ExactSpelling = true)]
550
- public static extern int MsiViewExecute(uint view, uint record);
551
-
552
- /// <summary>
553
- /// PInvoke of MsiViewFetch.
554
- /// </summary>
555
- /// <param name="view">Handle of view to fetch a row from.</param>
556
- /// <param name="record">Handle to receive record info.</param>
557
- /// <returns>Error code.</returns>
558
- [DllImport("msi.dll", EntryPoint = "MsiViewFetch", CharSet = CharSet.Unicode, ExactSpelling = true)]
559
- public static extern int MsiViewFetch(uint view, out uint record);
560
-
561
- /// <summary>
562
- /// PInvoke of MsiViewModify.
563
- /// </summary>
564
- /// <param name="view">Handle of view to modify.</param>
565
- /// <param name="modifyMode">Modify mode.</param>
566
- /// <param name="record">Handle of record.</param>
567
- /// <returns>Error code.</returns>
568
- [DllImport("msi.dll", EntryPoint = "MsiViewModify", CharSet = CharSet.Unicode, ExactSpelling = true)]
569
- public static extern int MsiViewModify(uint view, int modifyMode, uint record);
570
- }
571
-}
src/WixToolset.Core.WindowsInstaller/Msi/Record.cs
deleted
-181
@@ -1,181 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.ComponentModel;
7
- using System.Text;
8
-
9
- /// <summary>
10
- /// Wrapper class around msi.dll interop for a record.
11
- /// </summary>
12
- public sealed class Record : MsiHandle
13
- {
14
- /// <summary>
15
- /// Creates a record with the specified number of fields.
16
- /// </summary>
17
- /// <param name="fieldCount">Number of fields in record.</param>
18
- public Record(int fieldCount)
19
- {
20
- this.Handle = MsiInterop.MsiCreateRecord(fieldCount);
21
- if (0 == this.Handle)
22
- {
23
- throw new OutOfMemoryException();
24
- }
25
- }
26
-
27
- /// <summary>
28
- /// Creates a record from a handle.
29
- /// </summary>
30
- /// <param name="handle">Handle to create record from.</param>
31
- internal Record(uint handle)
32
- {
33
- this.Handle = handle;
34
- }
35
-
36
- /// <summary>
37
- /// Gets a string value at specified location.
38
- /// </summary>
39
- /// <param name="field">Index into record to get string.</param>
40
- public string this[int field]
41
- {
42
- get { return this.GetString(field); }
43
- set { this.SetString(field, (string)value); }
44
- }
45
-
46
- /// <summary>
47
- /// Determines if the value is null at the specified location.
48
- /// </summary>
49
- /// <param name="field">Index into record of the field to query.</param>
50
- /// <returns>true if the value is null, false otherwise.</returns>
51
- public bool IsNull(int field)
52
- {
53
- int error = MsiInterop.MsiRecordIsNull(this.Handle, field);
54
-
55
- switch (error)
56
- {
57
- case 0:
58
- return false;
59
- case 1:
60
- return true;
61
- default:
62
- throw new Win32Exception(error);
63
- }
64
- }
65
-
66
- /// <summary>
67
- /// Gets integer value at specified location.
68
- /// </summary>
69
- /// <param name="field">Index into record to get integer</param>
70
- /// <returns>Integer value</returns>
71
- public int GetInteger(int field)
72
- {
73
- return MsiInterop.MsiRecordGetInteger(this.Handle, field);
74
- }
75
-
76
- /// <summary>
77
- /// Sets integer value at specified location.
78
- /// </summary>
79
- /// <param name="field">Index into record to set integer.</param>
80
- /// <param name="value">Value to set into record.</param>
81
- public void SetInteger(int field, int value)
82
- {
83
- int error = MsiInterop.MsiRecordSetInteger(this.Handle, field, value);
84
- if (0 != error)
85
- {
86
- throw new Win32Exception(error);
87
- }
88
- }
89
-
90
- /// <summary>
91
- /// Gets string value at specified location.
92
- /// </summary>
93
- /// <param name="field">Index into record to get string.</param>
94
- /// <returns>String value</returns>
95
- public string GetString(int field)
96
- {
97
- int bufferSize = 255;
98
- StringBuilder buffer = new StringBuilder(bufferSize);
99
- int error = MsiInterop.MsiRecordGetString(this.Handle, field, buffer, ref bufferSize);
100
- if (234 == error)
101
- {
102
- buffer.EnsureCapacity(++bufferSize);
103
- error = MsiInterop.MsiRecordGetString(this.Handle, field, buffer, ref bufferSize);
104
- }
105
-
106
- if (0 != error)
107
- {
108
- throw new Win32Exception(error);
109
- }
110
-
111
- return (0 < buffer.Length ? buffer.ToString() : null);
112
- }
113
-
114
- /// <summary>
115
- /// Set string value at specified location
116
- /// </summary>
117
- /// <param name="field">Index into record to set string.</param>
118
- /// <param name="value">Value to set into record</param>
119
- public void SetString(int field, string value)
120
- {
121
- int error = MsiInterop.MsiRecordSetString(this.Handle, field, value);
122
- if (0 != error)
123
- {
124
- throw new Win32Exception(error);
125
- }
126
- }
127
-
128
- /// <summary>
129
- /// Get stream at specified location.
130
- /// </summary>
131
- /// <param name="field">Index into record to get stream.</param>
132
- /// <param name="buffer">buffer to receive bytes from stream.</param>
133
- /// <param name="requestedBufferSize">Buffer size to read.</param>
134
- /// <returns>Stream read into string.</returns>
135
- public int GetStream(int field, byte[] buffer, int requestedBufferSize)
136
- {
137
- int bufferSize = 255;
138
- if (requestedBufferSize > 0)
139
- {
140
- bufferSize = requestedBufferSize;
141
- }
142
-
143
- int error = MsiInterop.MsiRecordReadStream(this.Handle, field, buffer, ref bufferSize);
144
- if (0 != error)
145
- {
146
- throw new Win32Exception(error);
147
- }
148
-
149
- return bufferSize;
150
- }
151
-
152
- /// <summary>
153
- /// Sets a stream at a specified location.
154
- /// </summary>
155
- /// <param name="field">Index into record to set stream.</param>
156
- /// <param name="path">Path to file to read into stream.</param>
157
- public void SetStream(int field, string path)
158
- {
159
- int error = MsiInterop.MsiRecordSetStream(this.Handle, field, path);
160
- if (0 != error)
161
- {
162
- throw new Win32Exception(error);
163
- }
164
- }
165
-
166
- /// <summary>
167
- /// Gets the number of fields in record.
168
- /// </summary>
169
- /// <returns>Count of fields in record.</returns>
170
- public int GetFieldCount()
171
- {
172
- int size = MsiInterop.MsiRecordGetFieldCount(this.Handle);
173
- if (0 > size)
174
- {
175
- throw new Win32Exception();
176
- }
177
-
178
- return size;
179
- }
180
- }
181
-}
src/WixToolset.Core.WindowsInstaller/Msi/Session.cs
deleted
-43
@@ -1,43 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.Globalization;
7
-
8
- /// <summary>
9
- /// Controls the installation process.
10
- /// </summary>
11
- internal sealed class Session : MsiHandle
12
- {
13
- /// <summary>
14
- /// Instantiate a new Session.
15
- /// </summary>
16
- /// <param name="database">The database to open.</param>
17
- public Session(Database database)
18
- {
19
- string packagePath = String.Format(CultureInfo.InvariantCulture, "#{0}", (uint)database.Handle);
20
-
21
- uint handle = 0;
22
- int error = MsiInterop.MsiOpenPackage(packagePath, out handle);
23
- if (0 != error)
24
- {
25
- throw new MsiException(error);
26
- }
27
- this.Handle = handle;
28
- }
29
-
30
- /// <summary>
31
- /// Executes a built-in action, custom action, or user-interface wizard action.
32
- /// </summary>
33
- /// <param name="action">Specifies the action to execute.</param>
34
- public void DoAction(string action)
35
- {
36
- int error = MsiInterop.MsiDoAction(this.Handle, action);
37
- if (0 != error)
38
- {
39
- throw new MsiException(error);
40
- }
41
- }
42
- }
43
-}
src/WixToolset.Core.WindowsInstaller/Msi/SummaryInformation.cs
deleted
-244
@@ -1,244 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.Globalization;
7
- using System.Text;
8
- using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
9
-
10
- /// <summary>
11
- /// Summary information for the MSI files.
12
- /// </summary>
13
- internal sealed class SummaryInformation : MsiHandle
14
- {
15
- /// <summary>
16
- /// Summary information properties for transforms.
17
- /// </summary>
18
- public enum Transform
19
- {
20
- /// <summary>PID_CODEPAGE = code page for the summary information stream</summary>
21
- CodePage = 1,
22
-
23
- /// <summary>PID_TITLE = typically just "Transform"</summary>
24
- Title = 2,
25
-
26
- /// <summary>PID_SUBJECT = original subject of target</summary>
27
- TargetSubject = 3,
28
-
29
- /// <summary>PID_AUTHOR = original manufacturer of target</summary>
30
- TargetManufacturer = 4,
31
-
32
- /// <summary>PID_KEYWORDS = keywords for the transform, typically including at least "Installer"</summary>
33
- Keywords = 5,
34
-
35
- /// <summary>PID_COMMENTS = describes what this package does</summary>
36
- Comments = 6,
37
-
38
- /// <summary>PID_TEMPLATE = target platform;language</summary>
39
- TargetPlatformAndLanguage = 7,
40
-
41
- /// <summary>PID_LASTAUTHOR = updated platform;language</summary>
42
- UpdatedPlatformAndLanguage = 8,
43
-
44
- /// <summary>PID_REVNUMBER = {productcode}version;{newproductcode}newversion;upgradecode</summary>
45
- ProductCodes = 9,
46
-
47
- /// <summary>PID_LASTPRINTED should be null for transforms</summary>
48
- Reserved11 = 11,
49
-
50
- ///.<summary>PID_CREATE_DTM = the timestamp when the transform was created</summary>
51
- CreationTime = 12,
52
-
53
- /// <summary>PID_PAGECOUNT = minimum installer version</summary>
54
- InstallerRequirement = 14,
55
-
56
- /// <summary>PID_CHARCOUNT = validation and error flags</summary>
57
- ValidationFlags = 16,
58
-
59
- /// <summary>PID_APPNAME = the application that created the transform</summary>
60
- CreatingApplication = 18,
61
-
62
- /// <summary>PID_SECURITY = whether read-only is enforced; should always be 4 for transforms</summary>
63
- Security = 19,
64
- }
65
-
66
- /// <summary>
67
- /// Summary information properties for patches.
68
- /// </summary>
69
- public enum Patch
70
- {
71
- /// <summary>PID_CODEPAGE = code page of the summary information stream</summary>
72
- CodePage = 1,
73
-
74
- /// <summary>PID_TITLE = a brief description of the package type</summary>
75
- Title = 2,
76
-
77
- /// <summary>PID_SUBJECT = package name</summary>
78
- PackageName = 3,
79
-
80
- /// <summary>PID_AUTHOR = manufacturer of the patch package</summary>
81
- Manufacturer = 4,
82
-
83
- /// <summary>PID_KEYWORDS = alternate sources for the patch package</summary>
84
- Sources = 5,
85
-
86
- /// <summary>PID_COMMENTS = general purpose of the patch package</summary>
87
- Comments = 6,
88
-
89
- /// <summary>PID_TEMPLATE = semicolon delimited list of ProductCodes</summary>
90
- ProductCodes = 7,
91
-
92
- /// <summary>PID_LASTAUTHOR = semicolon delimited list of transform names</summary>
93
- TransformNames = 8,
94
-
95
- /// <summary>PID_REVNUMBER = GUID patch code</summary>
96
- PatchCode = 9,
97
-
98
- /// <summary>PID_LASTPRINTED should be null for patches</summary>
99
- Reserved11 = 11,
100
-
101
- /// <summary>PID_PAGECOUNT should be null for patches</summary>
102
- Reserved14 = 14,
103
-
104
- /// <summary>PID_WORDCOUNT = minimum installer version</summary>
105
- InstallerRequirement = 15,
106
-
107
- /// <summary>PID_CHARCOUNT should be null for patches</summary>
108
- Reserved16 = 16,
109
-
110
- /// <summary>PID_SECURITY = read-only attribute of the patch package</summary>
111
- Security = 19,
112
- }
113
-
114
- /// <summary>
115
- /// Summary information values for the InstallerRequirement property.
116
- /// </summary>
117
- public enum InstallerRequirement
118
- {
119
- /// <summary>Any version of the installer will do</summary>
120
- Version10 = 1,
121
-
122
- /// <summary>At least 1.2</summary>
123
- Version12 = 2,
124
-
125
- /// <summary>At least 2.0</summary>
126
- Version20 = 3,
127
-
128
- /// <summary>At least 3.0</summary>
129
- Version30 = 4,
130
-
131
- /// <summary>At least 3.1</summary>
132
- Version31 = 5,
133
- }
134
-
135
- /// <summary>
136
- /// Instantiate a new SummaryInformation class from an open database.
137
- /// </summary>
138
- /// <param name="db">Database to retrieve summary information from.</param>
139
- public SummaryInformation(Database db)
140
- {
141
- if (null == db)
142
- {
143
- throw new ArgumentNullException("db");
144
- }
145
-
146
- uint handle = 0;
147
- int error = MsiInterop.MsiGetSummaryInformation(db.Handle, null, 0, ref handle);
148
- if (0 != error)
149
- {
150
- throw new MsiException(error);
151
- }
152
- this.Handle = handle;
153
- }
154
-
155
- /// <summary>
156
- /// Instantiate a new SummaryInformation class from a database file.
157
- /// </summary>
158
- /// <param name="databaseFile">The database file.</param>
159
- public SummaryInformation(string databaseFile)
160
- {
161
- if (null == databaseFile)
162
- {
163
- throw new ArgumentNullException("databaseFile");
164
- }
165
-
166
- uint handle = 0;
167
- int error = MsiInterop.MsiGetSummaryInformation(0, databaseFile, 0, ref handle);
168
- if (0 != error)
169
- {
170
- throw new MsiException(error);
171
- }
172
- this.Handle = handle;
173
- }
174
-
175
- /// <summary>
176
- /// Variant types in the summary information table.
177
- /// </summary>
178
- private enum VT : uint
179
- {
180
- /// <summary>Variant has not been assigned.</summary>
181
- EMPTY = 0,
182
-
183
- /// <summary>Null variant type.</summary>
184
- NULL = 1,
185
-
186
- /// <summary>16-bit integer variant type.</summary>
187
- I2 = 2,
188
-
189
- /// <summary>32-bit integer variant type.</summary>
190
- I4 = 3,
191
-
192
- /// <summary>String variant type.</summary>
193
- LPSTR = 30,
194
-
195
- /// <summary>Date time (FILETIME, converted to Variant time) variant type.</summary>
196
- FILETIME = 64,
197
- }
198
-
199
- /// <summary>
200
- /// Gets a summary information property.
201
- /// </summary>
202
- /// <param name="index">Index of the summary information property.</param>
203
- /// <returns>The summary information property.</returns>
204
- public string GetProperty(int index)
205
- {
206
- uint dataType;
207
- StringBuilder stringValue = new StringBuilder("");
208
- int bufSize = 0;
209
- int intValue;
210
- FILETIME timeValue;
211
- timeValue.dwHighDateTime = 0;
212
- timeValue.dwLowDateTime = 0;
213
-
214
- int error = MsiInterop.MsiSummaryInfoGetProperty(this.Handle, index, out dataType, out intValue, ref timeValue, stringValue, ref bufSize);
215
- if (234 == error)
216
- {
217
- stringValue.EnsureCapacity(++bufSize);
218
- error = MsiInterop.MsiSummaryInfoGetProperty(this.Handle, index, out dataType, out intValue, ref timeValue, stringValue, ref bufSize);
219
- }
220
-
221
- if (0 != error)
222
- {
223
- throw new MsiException(error);
224
- }
225
-
226
- switch ((VT)dataType)
227
- {
228
- case VT.EMPTY:
229
- return String.Empty;
230
- case VT.LPSTR:
231
- return stringValue.ToString();
232
- case VT.I2:
233
- case VT.I4:
234
- return Convert.ToString(intValue, CultureInfo.InvariantCulture);
235
- case VT.FILETIME:
236
- long longFileTime = (((long)timeValue.dwHighDateTime) << 32) | unchecked((uint)timeValue.dwLowDateTime);
237
- DateTime dateTime = DateTime.FromFileTime(longFileTime);
238
- return dateTime.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
239
- default:
240
- throw new InvalidOperationException();
241
- }
242
- }
243
- }
244
-}
src/WixToolset.Core.WindowsInstaller/Msi/View.cs
deleted
-262
@@ -1,262 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using System.Collections;
7
- using System.Collections.Generic;
8
- using System.Globalization;
9
-
10
- /// <summary>
11
- /// Enumeration of different modify modes.
12
- /// </summary>
13
- public enum ModifyView
14
- {
15
- /// <summary>
16
- /// Writes current data in the cursor to a table row. Updates record if the primary
17
- /// keys match an existing row and inserts if they do not match. Fails with a read-only
18
- /// database. This mode cannot be used with a view containing joins.
19
- /// </summary>
20
- Assign = 3, // Writes current data in the cursor to a table row. Updates record if the primary keys match an existing row and inserts if they do not match. Fails with a read-only database. This mode cannot be used with a view containing joins.
21
-
22
- /// <summary>
23
- /// Remove a row from the table. You must first call the Fetch function with the same
24
- /// record. Fails if the row has been deleted. Works only with read-write records. This
25
- /// mode cannot be used with a view containing joins.
26
- /// </summary>
27
- Delete = 6, // Remove a row from the table. You must first call the MsiViewFetch function with the same record. Fails if the row has been deleted. Works only with read-write records. This mode cannot be used with a view containing joins.
28
-
29
- /// <summary>
30
- /// Inserts a record. Fails if a row with the same primary keys exists. Fails with a read-only
31
- /// database. This mode cannot be used with a view containing joins.
32
- /// </summary>
33
- Insert = 1, // Inserts a record. Fails if a row with the same primary keys exists. Fails with a read-only database. This mode cannot be used with a view containing joins.
34
-
35
- /// <summary>
36
- /// Inserts a temporary record. The information is not persistent. Fails if a row with the
37
- /// same primary key exists. Works only with read-write records. This mode cannot be
38
- /// used with a view containing joins.
39
- /// </summary>
40
- InsertTemporary = 7, // Inserts a temporary record. The information is not persistent. Fails if a row with the same primary key exists. Works only with read-write records. This mode cannot be used with a view containing joins.
41
-
42
- /// <summary>
43
- /// Inserts or validates a record in a table. Inserts if primary keys do not match any row
44
- /// and validates if there is a match. Fails if the record does not match the data in
45
- /// the table. Fails if there is a record with a duplicate key that is not identical.
46
- /// Works only with read-write records. This mode cannot be used with a view containing joins.
47
- /// </summary>
48
- Merge = 5, // Inserts or validates a record in a table. Inserts if primary keys do not match any row and validates if there is a match. Fails if the record does not match the data in the table. Fails if there is a record with a duplicate key that is not identical. Works only with read-write records. This mode cannot be used with a view containing joins.
49
-
50
- /// <summary>
51
- /// Refreshes the information in the record. Must first call Fetch with the
52
- /// same record. Fails for a deleted row. Works with read-write and read-only records.
53
- /// </summary>
54
- Refresh = 0, // Refreshes the information in the record. Must first call MsiViewFetch with the same record. Fails for a deleted row. Works with read-write and read-only records.
55
-
56
- /// <summary>
57
- /// Updates or deletes and inserts a record into a table. Must first call Fetch with
58
- /// the same record. Updates record if the primary keys are unchanged. Deletes old row and
59
- /// inserts new if primary keys have changed. Fails with a read-only database. This mode cannot
60
- /// be used with a view containing joins.
61
- /// </summary>
62
- Replace = 4, // Updates or deletes and inserts a record into a table. Must first call MsiViewFetch with the same record. Updates record if the primary keys are unchanged. Deletes old row and inserts new if primary keys have changed. Fails with a read-only database. This mode cannot be used with a view containing joins.
63
-
64
- /// <summary>
65
- /// Refreshes the information in the supplied record without changing the position in the
66
- /// result set and without affecting subsequent fetch operations. The record may then
67
- /// be used for subsequent Update, Delete, and Refresh. All primary key columns of the
68
- /// table must be in the query and the record must have at least as many fields as the
69
- /// query. Seek cannot be used with multi-table queries. This mode cannot be used with
70
- /// a view containing joins. See also the remarks.
71
- /// </summary>
72
- Seek = -1, // Refreshes the information in the supplied record without changing the position in the result set and without affecting subsequent fetch operations. The record may then be used for subsequent Update, Delete, and Refresh. All primary key columns of the table must be in the query and the record must have at least as many fields as the query. Seek cannot be used with multi-table queries. This mode cannot be used with a view containing joins. See also the remarks.
73
-
74
- /// <summary>
75
- /// Updates an existing record. Non-primary keys only. Must first call Fetch. Fails with a
76
- /// deleted record. Works only with read-write records.
77
- /// </summary>
78
- Update = 2, // Updates an existing record. Nonprimary keys only. Must first call MsiViewFetch. Fails with a deleted record. Works only with read-write records.
79
- }
80
-
81
- /// <summary>
82
- /// Wrapper class for MSI API views.
83
- /// </summary>
84
- internal sealed class View : MsiHandle
85
- {
86
- /// <summary>
87
- /// Constructor that creates a view given a database handle and a query.
88
- /// </summary>
89
- /// <param name="db">Handle to the database to run the query on.</param>
90
- /// <param name="query">Query to be executed.</param>
91
- public View(Database db, string query)
92
- {
93
- if (null == db)
94
- {
95
- throw new ArgumentNullException("db");
96
- }
97
-
98
- if (null == query)
99
- {
100
- throw new ArgumentNullException("query");
101
- }
102
-
103
- uint handle = 0;
104
-
105
- int error = MsiInterop.MsiDatabaseOpenView(db.Handle, query, out handle);
106
- if (0 != error)
107
- {
108
- throw new MsiException(error);
109
- }
110
-
111
- this.Handle = handle;
112
- }
113
-
114
- /// <summary>
115
- /// Enumerator that automatically disposes of the retrieved Records.
116
- /// </summary>
117
- public IEnumerable<Record> Records => new ViewEnumerable(this);
118
-
119
- /// <summary>
120
- /// Executes a view with no customizable parameters.
121
- /// </summary>
122
- public void Execute()
123
- {
124
- this.Execute(null);
125
- }
126
-
127
- /// <summary>
128
- /// Executes a query substituing the values from the records into the customizable parameters
129
- /// in the view.
130
- /// </summary>
131
- /// <param name="record">Record containing parameters to be substituded into the view.</param>
132
- public void Execute(Record record)
133
- {
134
- var error = MsiInterop.MsiViewExecute(this.Handle, null == record ? 0 : record.Handle);
135
- if (0 != error)
136
- {
137
- throw new MsiException(error);
138
- }
139
- }
140
-
141
- /// <summary>
142
- /// Fetches the next row in the view.
143
- /// </summary>
144
- /// <returns>Returns the fetched record; otherwise null.</returns>
145
- public Record Fetch()
146
- {
147
- var error = MsiInterop.MsiViewFetch(this.Handle, out var recordHandle);
148
- if (259 == error)
149
- {
150
- return null;
151
- }
152
- else if (0 != error)
153
- {
154
- throw new MsiException(error);
155
- }
156
-
157
- return new Record(recordHandle);
158
- }
159
-
160
- /// <summary>
161
- /// Updates a fetched record.
162
- /// </summary>
163
- /// <param name="type">Type of modification mode.</param>
164
- /// <param name="record">Record to be modified.</param>
165
- public void Modify(ModifyView type, Record record)
166
- {
167
- int error = MsiInterop.MsiViewModify(this.Handle, Convert.ToInt32(type, CultureInfo.InvariantCulture), record.Handle);
168
- if (0 != error)
169
- {
170
- throw new MsiException(error);
171
- }
172
- }
173
-
174
- /// <summary>
175
- /// Returns a record containing column names or definitions.
176
- /// </summary>
177
- /// <param name="columnType">Specifies a flag indicating what type of information is needed. Either MSICOLINFO_NAMES or MSICOLINFO_TYPES.</param>
178
- /// <returns>The record containing information about the column.</returns>
179
- public Record GetColumnInfo(int columnType)
180
- {
181
- uint recordHandle;
182
-
183
- int error = MsiInterop.MsiViewGetColumnInfo(this.Handle, columnType, out recordHandle);
184
- if (0 != error)
185
- {
186
- throw new MsiException(error);
187
- }
188
-
189
- return new Record(recordHandle);
190
- }
191
-
192
- private class ViewEnumerable : IEnumerable<Record>
193
- {
194
- private readonly View view;
195
-
196
- public ViewEnumerable(View view) => this.view = view;
197
-
198
- public IEnumerator<Record> GetEnumerator() => new ViewEnumerator(this.view);
199
-
200
- IEnumerator IEnumerable.GetEnumerator() => new ViewEnumerator(this.view);
201
- }
202
-
203
- private class ViewEnumerator : IEnumerator<Record>
204
- {
205
- private readonly View view;
206
- private readonly List<Record> records = new List<Record>();
207
- private int position = -1;
208
- private bool disposed;
209
-
210
- public ViewEnumerator(View view) => this.view = view;
211
-
212
- public Record Current => this.records[this.position];
213
-
214
- object IEnumerator.Current => this.records[this.position];
215
-
216
- public bool MoveNext()
217
- {
218
- if (this.position + 1 >= this.records.Count)
219
- {
220
- var record = this.view.Fetch();
221
-
222
- if (record == null)
223
- {
224
- return false;
225
- }
226
-
227
- this.records.Add(record);
228
- this.position = this.records.Count - 1;
229
- }
230
- else
231
- {
232
- ++this.position;
233
- }
234
-
235
- return true;
236
- }
237
-
238
- public void Reset() => this.position = -1;
239
-
240
- public void Dispose()
241
- {
242
- this.Dispose(true);
243
- }
244
-
245
- protected virtual void Dispose(bool disposing)
246
- {
247
- if (!this.disposed)
248
- {
249
- if (disposing)
250
- {
251
- foreach (var record in this.records)
252
- {
253
- record.Dispose();
254
- }
255
- }
256
-
257
- this.disposed = true;
258
- }
259
- }
260
- }
261
- }
262
-}
src/WixToolset.Core.WindowsInstaller/Msi/WixInvalidIdtException.cs
deleted
-33
@@ -1,33 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.WindowsInstaller.Msi
4
-{
5
- using System;
6
- using WixToolset.Data;
7
-
8
- /// <summary>
9
- /// WiX invalid idt exception.
10
- /// </summary>
11
- [Serializable]
12
- public sealed class WixInvalidIdtException : WixException
13
- {
14
- /// <summary>
15
- /// Instantiate a new WixInvalidIdtException.
16
- /// </summary>
17
- /// <param name="idtFile">The invalid idt file.</param>
18
- public WixInvalidIdtException(string idtFile) :
19
- base(ErrorMessages.InvalidIdt(new SourceLineNumber(idtFile), idtFile))
20
- {
21
- }
22
-
23
- /// <summary>
24
- /// Instantiate a new WixInvalidIdtException.
25
- /// </summary>
26
- /// <param name="idtFile">The invalid idt file.</param>
27
- /// <param name="tableName">The table name of the invalid idt file.</param>
28
- public WixInvalidIdtException(string idtFile, string tableName) :
29
- base(ErrorMessages.InvalidIdt(new SourceLineNumber(idtFile), idtFile, tableName))
30
- {
31
- }
32
- }
33
-}
src/WixToolset.Core.WindowsInstaller/MspBackend.cs
+1
-1
@@ -7,7 +7,7 @@ namespace WixToolset.Core.WindowsInstaller
7
using System.IO;
8
using System.Linq;
9
using WixToolset.Core.WindowsInstaller.Bind;
10
- using WixToolset.Core.WindowsInstaller.Msi;
10
+ using WixToolset.Core.Native.Msi;
11
using WixToolset.Core.WindowsInstaller.Unbind;
12
using WixToolset.Data;
13
using WixToolset.Data.Symbols;
src/WixToolset.Core.WindowsInstaller/Ole32/Storage.cs
deleted
-437
@@ -1,437 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Ole32
4
-{
5
- using System;
6
- using System.Runtime.InteropServices;
7
- using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
8
- using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
9
-
10
- /// <summary>
11
- /// Specifies the access mode to use when opening, creating, or deleting a storage object.
12
- /// </summary>
13
- internal enum StorageMode
14
- {
15
- /// <summary>
16
- /// Indicates that the object is read-only, meaning that modifications cannot be made.
17
- /// </summary>
18
- Read = 0x0,
19
-
20
- /// <summary>
21
- /// Enables you to save changes to the object, but does not permit access to its data.
22
- /// </summary>
23
- Write = 0x1,
24
-
25
- /// <summary>
26
- /// Enables access and modification of object data.
27
- /// </summary>
28
- ReadWrite = 0x2,
29
-
30
- /// <summary>
31
- /// Specifies that subsequent openings of the object are not denied read or write access.
32
- /// </summary>
33
- ShareDenyNone = 0x40,
34
-
35
- /// <summary>
36
- /// Prevents others from subsequently opening the object in Read mode.
37
- /// </summary>
38
- ShareDenyRead = 0x30,
39
-
40
- /// <summary>
41
- /// Prevents others from subsequently opening the object for Write or ReadWrite access.
42
- /// </summary>
43
- ShareDenyWrite = 0x20,
44
-
45
- /// <summary>
46
- /// Prevents others from subsequently opening the object in any mode.
47
- /// </summary>
48
- ShareExclusive = 0x10,
49
-
50
- /// <summary>
51
- /// Opens the storage object with exclusive access to the most recently committed version.
52
- /// </summary>
53
- Priority = 0x40000,
54
-
55
- /// <summary>
56
- /// Indicates that an existing storage object or stream should be removed before the new object replaces it.
57
- /// </summary>
58
- Create = 0x1000,
59
- }
60
-
61
- /// <summary>
62
- /// Wrapper for the compound storage file APIs.
63
- /// </summary>
64
- internal sealed class Storage : IDisposable
65
- {
66
- private readonly IStorage storage;
67
- private bool disposed;
68
-
69
- /// <summary>
70
- /// Instantiate a new Storage.
71
- /// </summary>
72
- /// <param name="storage">The native storage interface.</param>
73
- private Storage(IStorage storage)
74
- {
75
- this.storage = storage;
76
- }
77
-
78
- /// <summary>
79
- /// Storage destructor.
80
- /// </summary>
81
- ~Storage()
82
- {
83
- this.Dispose();
84
- }
85
-
86
- /// <summary>
87
- /// The IEnumSTATSTG interface enumerates an array of STATSTG structures.
88
- /// </summary>
89
- [ComImport, Guid("0000000d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
90
- public interface IEnumSTATSTG
91
- {
92
- /// <summary>
93
- /// Gets a specified number of STATSTG structures.
94
- /// </summary>
95
- /// <param name="celt">The number of STATSTG structures requested.</param>
96
- /// <param name="rgelt">An array of STATSTG structures returned.</param>
97
- /// <param name="pceltFetched">The number of STATSTG structures retrieved in the rgelt parameter.</param>
98
- /// <returns>The error code.</returns>
99
- [PreserveSig]
100
- uint Next(uint celt, [MarshalAs(UnmanagedType.LPArray), Out] STATSTG[] rgelt, out uint pceltFetched);
101
-
102
- /// <summary>
103
- /// Skips a specified number of STATSTG structures in the enumeration sequence.
104
- /// </summary>
105
- /// <param name="celt">The number of STATSTG structures to skip.</param>
106
- void Skip(uint celt);
107
-
108
- /// <summary>
109
- /// Resets the enumeration sequence to the beginning of the STATSTG structure array.
110
- /// </summary>
111
- void Reset();
112
-
113
- /// <summary>
114
- /// Creates a new enumerator that contains the same enumeration state as the current STATSTG structure enumerator.
115
- /// </summary>
116
- /// <returns>The cloned IEnumSTATSTG interface.</returns>
117
- [return: MarshalAs(UnmanagedType.Interface)]
118
- IEnumSTATSTG Clone();
119
- }
120
-
121
- /// <summary>
122
- /// The IStorage interface supports the creation and management of structured storage objects.
123
- /// </summary>
124
- [ComImport, Guid("0000000b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
125
- private interface IStorage
126
- {
127
- /// <summary>
128
- /// Creates and opens a stream object with the specified name contained in this storage object.
129
- /// </summary>
130
- /// <param name="pwcsName">The name of the newly created stream.</param>
131
- /// <param name="grfMode">Specifies the access mode to use when opening the newly created stream.</param>
132
- /// <param name="reserved1">Reserved for future use; must be zero.</param>
133
- /// <param name="reserved2">Reserved for future use; must be zero.</param>
134
- /// <param name="ppstm">On return, pointer to the location of the new IStream interface pointer.</param>
135
- void CreateStream(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStream ppstm);
136
-
137
- /// <summary>
138
- /// Opens an existing stream object within this storage object using the specified access permissions in grfMode.
139
- /// </summary>
140
- /// <param name="pwcsName">The name of the stream to open.</param>
141
- /// <param name="reserved1">Reserved for future use; must be NULL.</param>
142
- /// <param name="grfMode">Specifies the access mode to be assigned to the open stream.</param>
143
- /// <param name="reserved2">Reserved for future use; must be zero.</param>
144
- /// <param name="ppstm">A pointer to IStream pointer variable that receives the interface pointer to the newly opened stream object.</param>
145
- void OpenStream(string pwcsName, IntPtr reserved1, uint grfMode, uint reserved2, out IStream ppstm);
146
-
147
- /// <summary>
148
- /// Creates and opens a new storage object nested within this storage object with the specified name in the specified access mode.
149
- /// </summary>
150
- /// <param name="pwcsName">The name of the newly created storage object.</param>
151
- /// <param name="grfMode">A value that specifies the access mode to use when opening the newly created storage object.</param>
152
- /// <param name="reserved1">Reserved for future use; must be zero.</param>
153
- /// <param name="reserved2">Reserved for future use; must be zero.</param>
154
- /// <param name="ppstg">A pointer, when successful, to the location of the IStorage pointer to the newly created storage object.</param>
155
- void CreateStorage(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStorage ppstg);
156
-
157
- /// <summary>
158
- /// Opens an existing storage object with the specified name in the specified access mode.
159
- /// </summary>
160
- /// <param name="pwcsName">The name of the storage object to open.</param>
161
- /// <param name="pstgPriority">Must be NULL.</param>
162
- /// <param name="grfMode">Specifies the access mode to use when opening the storage object.</param>
163
- /// <param name="snbExclude">Must be NULL.</param>
164
- /// <param name="reserved">Reserved for future use; must be zero.</param>
165
- /// <param name="ppstg">When successful, pointer to the location of an IStorage pointer to the opened storage object.</param>
166
- void OpenStorage(string pwcsName, IStorage pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved, out IStorage ppstg);
167
-
168
- /// <summary>
169
- /// Copies the entire contents of an open storage object to another storage object.
170
- /// </summary>
171
- /// <param name="ciidExclude">The number of elements in the array pointed to by rgiidExclude.</param>
172
- /// <param name="rgiidExclude">An array of interface identifiers (IIDs) that either the caller knows about and does not want
173
- /// copied or that the storage object does not support, but whose state the caller will later explicitly copy.</param>
174
- /// <param name="snbExclude">A string name block (refer to SNB) that specifies a block of storage or stream objects that are not to be copied to the destination.</param>
175
- /// <param name="pstgDest">A pointer to the open storage object into which this storage object is to be copied.</param>
176
- void CopyTo(uint ciidExclude, IntPtr rgiidExclude, IntPtr snbExclude, IStorage pstgDest);
177
-
178
- /// <summary>
179
- /// Copies or moves a substorage or stream from this storage object to another storage object.
180
- /// </summary>
181
- /// <param name="pwcsName">The name of the element in this storage object to be moved or copied.</param>
182
- /// <param name="pstgDest">IStorage pointer to the destination storage object.</param>
183
- /// <param name="pwcsNewName">The new name for the element in its new storage object.</param>
184
- /// <param name="grfFlags">Specifies whether the operation should be a move (STGMOVE_MOVE) or a copy (STGMOVE_COPY).</param>
185
- void MoveElementTo(string pwcsName, IStorage pstgDest, string pwcsNewName, uint grfFlags);
186
-
187
- /// <summary>
188
- /// Reflects changes for a transacted storage object to the parent level.
189
- /// </summary>
190
- /// <param name="grfCommitFlags">Controls how the changes are committed to the storage object.</param>
191
- void Commit(uint grfCommitFlags);
192
-
193
- /// <summary>
194
- /// Discards all changes that have been made to the storage object since the last commit operation.
195
- /// </summary>
196
- void Revert();
197
-
198
- /// <summary>
199
- /// Returns an enumerator object that can be used to enumerate the storage and stream objects contained within this storage object.
200
- /// </summary>
201
- /// <param name="reserved1">Reserved for future use; must be zero.</param>
202
- /// <param name="reserved2">Reserved for future use; must be NULL.</param>
203
- /// <param name="reserved3">Reserved for future use; must be zero.</param>
204
- /// <param name="ppenum">Pointer to IEnumSTATSTG* pointer variable that receives the interface pointer to the new enumerator object.</param>
205
- void EnumElements(uint reserved1, IntPtr reserved2, uint reserved3, out IEnumSTATSTG ppenum);
206
-
207
- /// <summary>
208
- /// Removes the specified storage or stream from this storage object.
209
- /// </summary>
210
- /// <param name="pwcsName">The name of the storage or stream to be removed.</param>
211
- void DestroyElement(string pwcsName);
212
-
213
- /// <summary>
214
- /// Renames the specified storage or stream in this storage object.
215
- /// </summary>
216
- /// <param name="pwcsOldName">The name of the substorage or stream to be changed.</param>
217
- /// <param name="pwcsNewName">The new name for the specified substorage or stream.</param>
218
- void RenameElement(string pwcsOldName, string pwcsNewName);
219
-
220
- /// <summary>
221
- /// Sets the modification, access, and creation times of the indicated storage element, if supported by the underlying file system.
222
- /// </summary>
223
- /// <param name="pwcsName">The name of the storage object element whose times are to be modified.</param>
224
- /// <param name="pctime">Either the new creation time for the element or NULL if the creation time is not to be modified.</param>
225
- /// <param name="patime">Either the new access time for the element or NULL if the access time is not to be modified.</param>
226
- /// <param name="pmtime">Either the new modification time for the element or NULL if the modification time is not to be modified.</param>
227
- void SetElementTimes(string pwcsName, FILETIME pctime, FILETIME patime, FILETIME pmtime);
228
-
229
- /// <summary>
230
- /// Assigns the specified CLSID to this storage object.
231
- /// </summary>
232
- /// <param name="clsid">The CLSID that is to be associated with the storage object.</param>
233
- void SetClass(Guid clsid);
234
-
235
- /// <summary>
236
- /// Stores up to 32 bits of state information in this storage object.
237
- /// </summary>
238
- /// <param name="grfStateBits">Specifies the new values of the bits to set.</param>
239
- /// <param name="grfMask">A binary mask indicating which bits in grfStateBits are significant in this call.</param>
240
- void SetStateBits(uint grfStateBits, uint grfMask);
241
-
242
- /// <summary>
243
- /// Returns the STATSTG structure for this open storage object.
244
- /// </summary>
245
- /// <param name="pstatstg">On return, pointer to a STATSTG structure where this method places information about the open storage object.</param>
246
- /// <param name="grfStatFlag">Specifies that some of the members in the STATSTG structure are not returned, thus saving a memory allocation operation.</param>
247
- void Stat(out STATSTG pstatstg, uint grfStatFlag);
248
- }
249
-
250
- /// <summary>
251
- /// The IStream interface lets you read and write data to stream objects.
252
- /// </summary>
253
- [ComImport, Guid("0000000c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
254
- private interface IStream
255
- {
256
- /// <summary>
257
- /// Reads a specified number of bytes from the stream object into memory starting at the current seek pointer.
258
- /// </summary>
259
- /// <param name="pv">A pointer to the buffer which the stream data is read into.</param>
260
- /// <param name="cb">The number of bytes of data to read from the stream object.</param>
261
- /// <param name="pcbRead">A pointer to a ULONG variable that receives the actual number of bytes read from the stream object.</param>
262
- void Read([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbRead);
263
-
264
- /// <summary>
265
- /// Writes a specified number of bytes into the stream object starting at the current seek pointer.
266
- /// </summary>
267
- /// <param name="pv">A pointer to the buffer that contains the data that is to be written to the stream.</param>
268
- /// <param name="cb">The number of bytes of data to attempt to write into the stream.</param>
269
- /// <param name="pcbWritten">A pointer to a ULONG variable where this method writes the actual number of bytes written to the stream object.</param>
270
- void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbWritten);
271
-
272
- /// <summary>
273
- /// Changes the seek pointer to a new location relative to the beginning of the stream, the end of the stream, or the current seek pointer.
274
- /// </summary>
275
- /// <param name="dlibMove">The displacement to be added to the location indicated by the dwOrigin parameter.</param>
276
- /// <param name="dwOrigin">The origin for the displacement specified in dlibMove.</param>
277
- /// <param name="plibNewPosition">A pointer to the location where this method writes the value of the new seek pointer from the beginning of the stream.</param>
278
- void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition);
279
-
280
- /// <summary>
281
- /// Changes the size of the stream object.
282
- /// </summary>
283
- /// <param name="libNewSize">Specifies the new size of the stream as a number of bytes.</param>
284
- void SetSize(long libNewSize);
285
-
286
- /// <summary>
287
- /// Copies a specified number of bytes from the current seek pointer in the stream to the current seek pointer in another stream.
288
- /// </summary>
289
- /// <param name="pstm">A pointer to the destination stream.</param>
290
- /// <param name="cb">The number of bytes to copy from the source stream.</param>
291
- /// <param name="pcbRead">A pointer to the location where this method writes the actual number of bytes read from the source.</param>
292
- /// <param name="pcbWritten">A pointer to the location where this method writes the actual number of bytes written to the destination.</param>
293
- void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);
294
-
295
- /// <summary>
296
- /// Ensures that any changes made to a stream object open in transacted mode are reflected in the parent storage object.
297
- /// </summary>
298
- /// <param name="grfCommitFlags">Controls how the changes for the stream object are committed.</param>
299
- void Commit(int grfCommitFlags);
300
-
301
- /// <summary>
302
- /// Discards all changes that have been made to a transacted stream since the last call to IStream::Commit.
303
- /// </summary>
304
- void Revert();
305
-
306
- /// <summary>
307
- /// Restricts access to a specified range of bytes in the stream.
308
- /// </summary>
309
- /// <param name="libOffset">Integer that specifies the byte offset for the beginning of the range.</param>
310
- /// <param name="cb">Integer that specifies the length of the range, in bytes, to be restricted.</param>
311
- /// <param name="dwLockType">Specifies the restrictions being requested on accessing the range.</param>
312
- void LockRegion(long libOffset, long cb, int dwLockType);
313
-
314
- /// <summary>
315
- /// Removes the access restriction on a range of bytes previously restricted with IStream::LockRegion.
316
- /// </summary>
317
- /// <param name="libOffset">Specifies the byte offset for the beginning of the range.</param>
318
- /// <param name="cb">Specifies, in bytes, the length of the range to be restricted.</param>
319
- /// <param name="dwLockType">Specifies the access restrictions previously placed on the range.</param>
320
- void UnlockRegion(long libOffset, long cb, int dwLockType);
321
-
322
- /// <summary>
323
- /// Retrieves the STATSTG structure for this stream.
324
- /// </summary>
325
- /// <param name="pstatstg">Pointer to a STATSTG structure where this method places information about this stream object.</param>
326
- /// <param name="grfStatFlag">Specifies that this method does not return some of the members in the STATSTG structure, thus saving a memory allocation operation.</param>
327
- void Stat(out STATSTG pstatstg, int grfStatFlag);
328
-
329
- /// <summary>
330
- /// Creates a new stream object that references the same bytes as the original stream but provides a separate seek pointer to those bytes.
331
- /// </summary>
332
- /// <param name="ppstm">When successful, pointer to the location of an IStream pointer to the new stream object.</param>
333
- void Clone(out IStream ppstm);
334
- }
335
-
336
- /// <summary>
337
- /// Creates a new compound file storage object.
338
- /// </summary>
339
- /// <param name="storageFile">The compound file being created.</param>
340
- /// <param name="mode">Specifies the access mode to use when opening the new storage object.</param>
341
- /// <returns>The created Storage object.</returns>
342
- public static Storage CreateDocFile(string storageFile, StorageMode mode)
343
- {
344
- IStorage storage = NativeMethods.StgCreateDocfile(storageFile, (uint)mode, 0);
345
-
346
- return new Storage(storage);
347
- }
348
-
349
- /// <summary>
350
- /// Opens an existing root storage object in the file system.
351
- /// </summary>
352
- /// <param name="storageFile">The file that contains the storage object to open.</param>
353
- /// <param name="mode">Specifies the access mode to use to open the storage object.</param>
354
- /// <returns>The created Storage object.</returns>
355
- public static Storage Open(string storageFile, StorageMode mode)
356
- {
357
- IStorage storage = NativeMethods.StgOpenStorage(storageFile, IntPtr.Zero, (uint)mode, IntPtr.Zero, 0);
358
-
359
- return new Storage(storage);
360
- }
361
-
362
- /// <summary>
363
- /// Copies the entire contents of this open storage object into another Storage object.
364
- /// </summary>
365
- /// <param name="destinationStorage">The destination Storage object.</param>
366
- public void CopyTo(Storage destinationStorage)
367
- {
368
- this.storage.CopyTo(0, IntPtr.Zero, IntPtr.Zero, destinationStorage.storage);
369
- }
370
-
371
- /// <summary>
372
- /// Opens an existing Storage object with the specified name according to the specified access mode.
373
- /// </summary>
374
- /// <param name="name">The name of the Storage object.</param>
375
- /// <returns>The opened Storage object.</returns>
376
- public Storage OpenStorage(string name)
377
- {
378
- IStorage subStorage;
379
-
380
- this.storage.OpenStorage(name, null, (uint)(StorageMode.Read | StorageMode.ShareExclusive), IntPtr.Zero, 0, out subStorage);
381
-
382
- return new Storage(subStorage);
383
- }
384
-
385
- /// <summary>
386
- /// Disposes the managed and unmanaged objects in this object.
387
- /// </summary>
388
- public void Dispose()
389
- {
390
- if (!this.disposed)
391
- {
392
- Marshal.ReleaseComObject(this.storage);
393
-
394
- this.disposed = true;
395
- }
396
-
397
- GC.SuppressFinalize(this);
398
- }
399
-
400
- /// <summary>
401
- /// The native methods.
402
- /// </summary>
403
- private sealed class NativeMethods
404
- {
405
- /// <summary>
406
- /// Protect the constructor since this class only contains static methods.
407
- /// </summary>
408
- private NativeMethods()
409
- {
410
- }
411
-
412
- /// <summary>
413
- /// Creates a new compound file storage object.
414
- /// </summary>
415
- /// <param name="pwcsName">The name for the compound file being created.</param>
416
- /// <param name="grfMode">Specifies the access mode to use when opening the new storage object.</param>
417
- /// <param name="reserved">Reserved for future use; must be zero.</param>
418
- /// <returns>A pointer to the location of the IStorage pointer to the new storage object.</returns>
419
- [DllImport("ole32.dll", PreserveSig = false)]
420
- [return: MarshalAs(UnmanagedType.Interface)]
421
- internal static extern IStorage StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, uint grfMode, uint reserved);
422
-
423
- /// <summary>
424
- /// Opens an existing root storage object in the file system.
425
- /// </summary>
426
- /// <param name="pwcsName">The file that contains the storage object to open.</param>
427
- /// <param name="pstgPriority">Most often NULL.</param>
428
- /// <param name="grfMode">Specifies the access mode to use to open the storage object.</param>
429
- /// <param name="snbExclude">If not NULL, pointer to a block of elements in the storage to be excluded as the storage object is opened.</param>
430
- /// <param name="reserved">Indicates reserved for future use; must be zero.</param>
431
- /// <returns>A pointer to a IStorage* pointer variable that receives the interface pointer to the opened storage.</returns>
432
- [DllImport("ole32.dll", PreserveSig = false)]
433
- [return: MarshalAs(UnmanagedType.Interface)]
434
- internal static extern IStorage StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, IntPtr pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved);
435
- }
436
- }
437
-}
src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs
deleted
-989
@@ -1,989 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.PatchAPI
4
-{
5
- using System;
6
- using System.Collections.Generic;
7
- using System.Diagnostics.CodeAnalysis;
8
- using System.Globalization;
9
- using System.Runtime.InteropServices;
10
- using WixToolset.Data.Symbols;
11
-
12
- /// <summary>
13
- /// Interop class for the mspatchc.dll.
14
- /// </summary>
15
- internal static class PatchInterop
16
- {
17
- // From WinError.h in the Platform SDK
18
- internal const ushort FACILITY_WIN32 = 7;
19
-
20
- /// <summary>
21
- /// Parse a number from text in either hex or decimal.
22
- /// </summary>
23
- /// <param name="source">Source value. Treated as hex if it starts 0x (or 0X), decimal otherwise.</param>
24
- /// <returns>Numeric value that source represents.</returns>
25
- static internal UInt32 ParseHexOrDecimal(string source)
26
- {
27
- string value = source.Trim();
28
- if (String.Equals(value.Substring(0, 2), "0x", StringComparison.OrdinalIgnoreCase))
29
- {
30
- return UInt32.Parse(value.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture.NumberFormat);
31
- }
32
- else
33
- {
34
- return UInt32.Parse(value, CultureInfo.InvariantCulture.NumberFormat);
35
- }
36
- }
37
-
38
- /// <summary>
39
- /// Create a binary delta file.
40
- /// </summary>
41
- /// <param name="deltaFile">Name of the delta file to create.</param>
42
- /// <param name="targetFile">Name of updated file.</param>
43
- /// <param name="targetSymbolPath">Optional paths to updated file's symbols.</param>
44
- /// <param name="targetRetainOffsets">Optional offsets to the delta retain sections in the updated file.</param>
45
- /// <param name="basisFiles">Optional array of target files.</param>
46
- /// <param name="basisSymbolPaths">Optional array of target files' symbol paths (must match basisFiles array).</param>
47
- /// <param name="basisIgnoreLengths">Optional array of target files' delta ignore section lengths (must match basisFiles array)(each entry must match basisIgnoreOffsets entries).</param>
48
- /// <param name="basisIgnoreOffsets">Optional array of target files' delta ignore section offsets (must match basisFiles array)(each entry must match basisIgnoreLengths entries).</param>
49
- /// <param name="basisRetainLengths">Optional array of target files' delta protect section lengths (must match basisFiles array)(each entry must match basisRetainOffsets and targetRetainOffsets entries).</param>
50
- /// <param name="basisRetainOffsets">Optional array of target files' delta protect section offsets (must match basisFiles array)(each entry must match basisRetainLengths and targetRetainOffsets entries).</param>
51
- /// <param name="apiPatchingSymbolFlags">ApiPatchingSymbolFlags value.</param>
52
- /// <param name="optimizePatchSizeForLargeFiles">OptimizePatchSizeForLargeFiles value.</param>
53
- /// <param name="retainRangesIgnored">Flag to indicate retain ranges were ignored due to mismatch.</param>
54
- /// <returns>true if delta file was created, false if whole file should be used instead.</returns>
55
- static public bool CreateDelta(
56
- string deltaFile,
57
- string targetFile,
58
- string targetSymbolPath,
59
- string targetRetainOffsets,
60
- string[] basisFiles,
61
- string[] basisSymbolPaths,
62
- string[] basisIgnoreLengths,
63
- string[] basisIgnoreOffsets,
64
- string[] basisRetainLengths,
65
- string[] basisRetainOffsets,
66
- PatchSymbolFlags apiPatchingSymbolFlags,
67
- bool optimizePatchSizeForLargeFiles,
68
- out bool retainRangesIgnored
69
- )
70
- {
71
- retainRangesIgnored = false;
72
- if (0 != (apiPatchingSymbolFlags & ~(PatchSymbolFlags.PatchSymbolNoImagehlp | PatchSymbolFlags.PatchSymbolNoFailures | PatchSymbolFlags.PatchSymbolUndecoratedToo)))
73
- {
74
- throw new ArgumentOutOfRangeException("apiPatchingSymbolFlags");
75
- }
76
-
77
- if (null == deltaFile || 0 == deltaFile.Length)
78
- {
79
- throw new ArgumentNullException("deltaFile");
80
- }
81
-
82
- if (null == targetFile || 0 == targetFile.Length)
83
- {
84
- throw new ArgumentNullException("targetFile");
85
- }
86
-
87
- if (null == basisFiles || 0 == basisFiles.Length)
88
- {
89
- return false;
90
- }
91
- uint countOldFiles = (uint)basisFiles.Length;
92
-
93
- if (null != basisSymbolPaths)
94
- {
95
- if (0 != basisSymbolPaths.Length)
96
- {
97
- if ((uint)basisSymbolPaths.Length != countOldFiles)
98
- {
99
- throw new ArgumentOutOfRangeException("basisSymbolPaths");
100
- }
101
- }
102
- }
103
- // a null basisSymbolPaths is allowed.
104
-
105
- if (null != basisIgnoreLengths)
106
- {
107
- if (0 != basisIgnoreLengths.Length)
108
- {
109
- if ((uint)basisIgnoreLengths.Length != countOldFiles)
110
- {
111
- throw new ArgumentOutOfRangeException("basisIgnoreLengths");
112
- }
113
- }
114
- }
115
- else
116
- {
117
- basisIgnoreLengths = new string[countOldFiles];
118
- }
119
-
120
- if (null != basisIgnoreOffsets)
121
- {
122
- if (0 != basisIgnoreOffsets.Length)
123
- {
124
- if ((uint)basisIgnoreOffsets.Length != countOldFiles)
125
- {
126
- throw new ArgumentOutOfRangeException("basisIgnoreOffsets");
127
- }
128
- }
129
- }
130
- else
131
- {
132
- basisIgnoreOffsets = new string[countOldFiles];
133
- }
134
-
135
- if (null != basisRetainLengths)
136
- {
137
- if (0 != basisRetainLengths.Length)
138
- {
139
- if ((uint)basisRetainLengths.Length != countOldFiles)
140
- {
141
- throw new ArgumentOutOfRangeException("basisRetainLengths");
142
- }
143
- }
144
- }
145
- else
146
- {
147
- basisRetainLengths = new string[countOldFiles];
148
- }
149
-
150
- if (null != basisRetainOffsets)
151
- {
152
- if (0 != basisRetainOffsets.Length)
153
- {
154
- if ((uint)basisRetainOffsets.Length != countOldFiles)
155
- {
156
- throw new ArgumentOutOfRangeException("basisRetainOffsets");
157
- }
158
- }
159
- }
160
- else
161
- {
162
- basisRetainOffsets = new string[countOldFiles];
163
- }
164
-
165
- PatchOptionData pod = new PatchOptionData();
166
- pod.symbolOptionFlags = apiPatchingSymbolFlags;
167
- pod.newFileSymbolPath = targetSymbolPath;
168
- pod.oldFileSymbolPathArray = basisSymbolPaths;
169
- pod.extendedOptionFlags = 0;
170
- PatchOldFileInfoW[] oldFileInfoArray = new PatchOldFileInfoW[countOldFiles];
171
- string[] newRetainOffsetArray = ((null == targetRetainOffsets) ? new string[0] : targetRetainOffsets.Split(','));
172
- for (uint i = 0; i < countOldFiles; ++i)
173
- {
174
- PatchOldFileInfoW ofi = new PatchOldFileInfoW();
175
- ofi.oldFileName = basisFiles[i];
176
- string[] ignoreLengthArray = ((null == basisIgnoreLengths[i]) ? new string[0] : basisIgnoreLengths[i].Split(','));
177
- string[] ignoreOffsetArray = ((null == basisIgnoreOffsets[i]) ? new string[0] : basisIgnoreOffsets[i].Split(','));
178
- string[] retainLengthArray = ((null == basisRetainLengths[i]) ? new string[0] : basisRetainLengths[i].Split(','));
179
- string[] retainOffsetArray = ((null == basisRetainOffsets[i]) ? new string[0] : basisRetainOffsets[i].Split(','));
180
- // Validate inputs
181
- if (ignoreLengthArray.Length != ignoreOffsetArray.Length)
182
- {
183
- throw new ArgumentOutOfRangeException("basisIgnoreLengths");
184
- }
185
-
186
- if (retainLengthArray.Length != retainOffsetArray.Length)
187
- {
188
- throw new ArgumentOutOfRangeException("basisRetainLengths");
189
- }
190
-
191
- if (newRetainOffsetArray.Length != retainOffsetArray.Length)
192
- {
193
- // remove all retain range information
194
- retainRangesIgnored = true;
195
- for (uint j = 0; j < countOldFiles; ++j)
196
- {
197
- basisRetainLengths[j] = null;
198
- basisRetainOffsets[j] = null;
199
- }
200
- retainLengthArray = new string[0];
201
- retainOffsetArray = new string[0];
202
- newRetainOffsetArray = new string[0];
203
- for (uint j = 0; j < oldFileInfoArray.Length; ++j)
204
- {
205
- oldFileInfoArray[j].retainRange = null;
206
- }
207
- }
208
-
209
- // Populate IgnoreRange structure
210
- PatchIgnoreRange[] ignoreArray = null;
211
- if (0 != ignoreLengthArray.Length)
212
- {
213
- ignoreArray = new PatchIgnoreRange[ignoreLengthArray.Length];
214
- for (int j = 0; j < ignoreLengthArray.Length; ++j)
215
- {
216
- PatchIgnoreRange ignoreRange = new PatchIgnoreRange();
217
- ignoreRange.offsetInOldFile = ParseHexOrDecimal(ignoreOffsetArray[j]);
218
- ignoreRange.lengthInBytes = ParseHexOrDecimal(ignoreLengthArray[j]);
219
- ignoreArray[j] = ignoreRange;
220
- }
221
- ofi.ignoreRange = ignoreArray;
222
- }
223
-
224
- PatchRetainRange[] retainArray = null;
225
- if (0 != newRetainOffsetArray.Length)
226
- {
227
- retainArray = new PatchRetainRange[retainLengthArray.Length];
228
- for (int j = 0; j < newRetainOffsetArray.Length; ++j)
229
- {
230
- PatchRetainRange retainRange = new PatchRetainRange();
231
- retainRange.offsetInOldFile = ParseHexOrDecimal(retainOffsetArray[j]);
232
- retainRange.lengthInBytes = ParseHexOrDecimal(retainLengthArray[j]);
233
- retainRange.offsetInNewFile = ParseHexOrDecimal(newRetainOffsetArray[j]);
234
- retainArray[j] = retainRange;
235
- }
236
- ofi.retainRange = retainArray;
237
- }
238
- oldFileInfoArray[i] = ofi;
239
- }
240
-
241
- if (CreatePatchFileExW(
242
- countOldFiles,
243
- oldFileInfoArray,
244
- targetFile,
245
- deltaFile,
246
- PatchOptionFlags(optimizePatchSizeForLargeFiles),
247
- pod,
248
- null,
249
- IntPtr.Zero))
250
- {
251
- return true;
252
- }
253
-
254
- // determine if this is an error or a need to use whole file.
255
- int err = Marshal.GetLastWin32Error();
256
- switch (err)
257
- {
258
- case unchecked((int)ERROR_PATCH_BIGGER_THAN_COMPRESSED):
259
- break;
260
-
261
- // too late to exclude this file -- should have been caught before
262
- case unchecked((int)ERROR_PATCH_SAME_FILE):
263
- default:
264
- throw new System.ComponentModel.Win32Exception(err);
265
- }
266
- return false;
267
- }
268
-
269
- /// <summary>
270
- /// Extract the delta header.
271
- /// </summary>
272
- /// <param name="delta">Name of delta file.</param>
273
- /// <param name="deltaHeader">Name of file to create with the delta's header.</param>
274
- static public void ExtractDeltaHeader(string delta, string deltaHeader)
275
- {
276
- if (!ExtractPatchHeaderToFileW(delta, deltaHeader))
277
- {
278
- throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
279
- }
280
- }
281
-
282
- /// <summary>
283
- /// Returns the PatchOptionFlags to use.
284
- /// </summary>
285
- /// <param name="optimizeForLargeFiles">True if optimizing for large files.</param>
286
- /// <returns>PATCH_OPTION_FLAG values</returns>
287
- static private UInt32 PatchOptionFlags(bool optimizeForLargeFiles)
288
- {
289
- UInt32 flags = PATCH_OPTION_FAIL_IF_SAME_FILE | PATCH_OPTION_FAIL_IF_BIGGER | PATCH_OPTION_USE_LZX_BEST;
290
- if (optimizeForLargeFiles)
291
- {
292
- flags |= PATCH_OPTION_USE_LZX_LARGE;
293
- }
294
- return flags;
295
- }
296
-
297
- //---------------------------------------------------------------------
298
- // From PatchApi.h
299
- //---------------------------------------------------------------------
300
-
301
- //
302
- // The following contants can be combined and used as the OptionFlags
303
- // parameter in the patch creation apis.
304
-
305
- internal const uint PATCH_OPTION_USE_BEST = 0x00000000; // auto choose best (slower)
306
-
307
- internal const uint PATCH_OPTION_USE_LZX_BEST = 0x00000003; // auto choose best of LXZ A/B (but not large)
308
- internal const uint PATCH_OPTION_USE_LZX_A = 0x00000001; // normal
309
- internal const uint PATCH_OPTION_USE_LXZ_B = 0x00000002; // better on some x86 binaries
310
- internal const uint PATCH_OPTION_USE_LZX_LARGE = 0x00000004; // better support for large files (requires 5.1 or higher applyer)
311
-
312
- internal const uint PATCH_OPTION_NO_BINDFIX = 0x00010000; // PE bound imports
313
- internal const uint PATCH_OPTION_NO_LOCKFIX = 0x00020000; // PE smashed locks
314
- internal const uint PATCH_OPTION_NO_REBASE = 0x00040000; // PE rebased image
315
- internal const uint PATCH_OPTION_FAIL_IF_SAME_FILE = 0x00080000; // don't create if same
316
- internal const uint PATCH_OPTION_FAIL_IF_BIGGER = 0x00100000; // fail if patch is larger than simply compressing new file (slower)
317
- internal const uint PATCH_OPTION_NO_CHECKSUM = 0x00200000; // PE checksum zero
318
- internal const uint PATCH_OPTION_NO_RESTIMEFIX = 0x00400000; // PE resource timestamps
319
- internal const uint PATCH_OPTION_NO_TIMESTAMP = 0x00800000; // don't store new file timestamp in patch
320
- internal const uint PATCH_OPTION_SIGNATURE_MD5 = 0x01000000; // use MD5 instead of CRC (reserved for future support)
321
- internal const uint PATCH_OPTION_INTERLEAVE_FILES = 0x40000000; // better support for large files (requires 5.2 or higher applyer)
322
- internal const uint PATCH_OPTION_RESERVED1 = 0x80000000; // (used internally)
323
-
324
- internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007;
325
-
326
- //
327
- // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags:
328
- //
329
-
330
- internal const uint PATCH_TRANSFORM_PE_RESOURCE_2 = 0x00000100; // better handling of PE resources (requires 5.2 or higher applyer)
331
- internal const uint PATCH_TRANSFORM_PE_IRELOC_2 = 0x00000200; // better handling of PE stripped relocs (requires 5.2 or higher applyer)
332
-
333
- //
334
- // In addition to the standard Win32 error codes, the following error codes may
335
- // be returned via GetLastError() when one of the patch APIs fails.
336
-
337
- internal const uint ERROR_PATCH_ENCODE_FAILURE = 0xC00E3101; // create
338
- internal const uint ERROR_PATCH_INVALID_OPTIONS = 0xC00E3102; // create
339
- internal const uint ERROR_PATCH_SAME_FILE = 0xC00E3103; // create
340
- internal const uint ERROR_PATCH_RETAIN_RANGES_DIFFER = 0xC00E3104; // create
341
- internal const uint ERROR_PATCH_BIGGER_THAN_COMPRESSED = 0xC00E3105; // create
342
- internal const uint ERROR_PATCH_IMAGEHLP_FALURE = 0xC00E3106; // create
343
-
344
- /// <summary>
345
- /// Delegate type that the PatchAPI calls for progress notification.
346
- /// </summary>
347
- /// <param name="context">.</param>
348
- /// <param name="currentPosition">.</param>
349
- /// <param name="maxPosition">.</param>
350
- /// <returns>True for success</returns>
351
- public delegate bool PatchProgressCallback(
352
- IntPtr context,
353
- uint currentPosition,
354
- uint maxPosition
355
- );
356
-
357
- /// <summary>
358
- /// Delegate type that the PatchAPI calls for patch symbol load information.
359
- /// </summary>
360
- /// <param name="whichFile">.</param>
361
- /// <param name="symbolFileName">.</param>
362
- /// <param name="symType">.</param>
363
- /// <param name="symbolFileCheckSum">.</param>
364
- /// <param name="symbolFileTimeDate">.</param>
365
- /// <param name="imageFileCheckSum">.</param>
366
- /// <param name="imageFileTimeDate">.</param>
367
- /// <param name="context">.</param>
368
- /// <returns>???</returns>
369
- public delegate bool PatchSymloadCallback(
370
- uint whichFile, // 0 for new file, 1 for first old file, etc
371
- [MarshalAs(UnmanagedType.LPStr)] string symbolFileName,
372
- uint symType, // see SYM_TYPE in imagehlp.h
373
- uint symbolFileCheckSum,
374
- uint symbolFileTimeDate,
375
- uint imageFileCheckSum,
376
- uint imageFileTimeDate,
377
- IntPtr context
378
- );
379
-
380
- /// <summary>
381
- /// Wraps PATCH_IGNORE_RANGE
382
- /// </summary>
383
- [StructLayout(LayoutKind.Sequential)]
384
- internal class PatchIgnoreRange
385
- {
386
- public uint offsetInOldFile;
387
- public uint lengthInBytes;
388
- }
389
-
390
- /// <summary>
391
- /// Wraps PATCH_RETAIN_RANGE
392
- /// </summary>
393
- [StructLayout(LayoutKind.Sequential)]
394
- internal class PatchRetainRange
395
- {
396
- public uint offsetInOldFile;
397
- public uint lengthInBytes;
398
- public uint offsetInNewFile;
399
- }
400
-
401
- /// <summary>
402
- /// Wraps PATCH_OLD_FILE_INFO (except for the OldFile~ portion)
403
- /// </summary>
404
- internal class PatchOldFileInfo
405
- {
406
- public PatchIgnoreRange[] ignoreRange;
407
- public PatchRetainRange[] retainRange;
408
- }
409
-
410
- /// <summary>
411
- /// Wraps PATCH_OLD_FILE_INFO_W
412
- /// </summary>
413
- internal class PatchOldFileInfoW : PatchOldFileInfo
414
- {
415
- public string oldFileName;
416
- }
417
-
418
- /// <summary>
419
- /// Wraps each PATCH_INTERLEAVE_MAP Range
420
- /// </summary>
421
- [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses"), StructLayout(LayoutKind.Sequential)]
422
- internal class PatchInterleaveMapRange
423
- {
424
- public uint oldOffset;
425
- public uint oldLength;
426
- public uint newLength;
427
- }
428
-
429
- /// <summary>
430
- /// Wraps PATCH_INTERLEAVE_MAP
431
- /// </summary>
432
- internal class PatchInterleaveMap
433
- {
434
- public PatchInterleaveMapRange[] ranges = null;
435
- }
436
-
437
-
438
- /// <summary>
439
- /// Wraps PATCH_OPTION_DATA
440
- /// </summary>
441
- [BestFitMapping(false, ThrowOnUnmappableChar = true)]
442
- internal class PatchOptionData
443
- {
444
- public PatchSymbolFlags symbolOptionFlags; // PATCH_SYMBOL_xxx flags
445
- [MarshalAs(UnmanagedType.LPStr)] public string newFileSymbolPath; // always ANSI, never Unicode
446
- [MarshalAs(UnmanagedType.LPStr)] public string[] oldFileSymbolPathArray; // array[ OldFileCount ]
447
- public uint extendedOptionFlags;
448
- public PatchSymloadCallback symLoadCallback = null;
449
- public IntPtr symLoadContext = IntPtr.Zero;
450
- public PatchInterleaveMap[] interleaveMapArray = null; // array[ OldFileCount ] (requires 5.2 or higher applyer)
451
- public uint maxLzxWindowSize = 0; // limit memory requirements (requires 5.2 or higher applyer)
452
- }
453
-
454
- //
455
- // Note that PATCH_OPTION_DATA contains LPCSTR paths, and no LPCWSTR (Unicode)
456
- // path argument is available, even when used with one of the Unicode APIs
457
- // such as CreatePatchFileW. This is because the unlerlying system services
458
- // for symbol file handling (IMAGEHLP.DLL) only support ANSI file/path names.
459
- //
460
-
461
- //
462
- // A note about PATCH_RETAIN_RANGE specifiers with multiple old files:
463
- //
464
- // Each old version file must have the same RetainRangeCount, and the same
465
- // retain range LengthInBytes and OffsetInNewFile values in the same order.
466
- // Only the OffsetInOldFile values can differ between old foles for retain
467
- // ranges.
468
- //
469
-
470
- //
471
- // The following prototypes are (some of the) interfaces for creating patches from files.
472
- //
473
-
474
- /// <summary>
475
- /// Creates a new delta.
476
- /// </summary>
477
- /// <param name="oldFileCount">Size of oldFileInfoArray.</param>
478
- /// <param name="oldFileInfoArray">Target file information.</param>
479
- /// <param name="newFileName">Name of updated file.</param>
480
- /// <param name="patchFileName">Name of delta to create.</param>
481
- /// <param name="optionFlags">PATCH_OPTION_xxx.</param>
482
- /// <param name="optionData">Optional PATCH_OPTION_DATA structure.</param>
483
- /// <param name="progressCallback">Delegate for progress callbacks.</param>
484
- /// <param name="context">Context for progress callback delegate.</param>
485
- /// <returns>true if successfull, sets Marshal.GetLastWin32Error() if not.</returns>
486
- [DllImport("mspatchc.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
487
- [return: MarshalAs(UnmanagedType.Bool)]
488
- internal static extern bool CreatePatchFileExW(
489
- uint oldFileCount, // maximum 255
490
- [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(PatchAPIMarshaler), MarshalCookie="PATCH_OLD_FILE_INFO_W")]
491
- PatchOldFileInfoW[] oldFileInfoArray,
492
- string newFileName, // input file (required)
493
- string patchFileName, // output file (required)
494
- uint optionFlags,
495
- [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(PatchAPIMarshaler), MarshalCookie="PATCH_OPTION_DATA")]
496
- PatchOptionData optionData,
497
- [MarshalAs (UnmanagedType.FunctionPtr)]
498
- PatchProgressCallback progressCallback,
499
- IntPtr context
500
- );
501
-
502
- /// <summary>
503
- /// Extracts delta header from delta.
504
- /// </summary>
505
- /// <param name="patchFileName">Name of delta file.</param>
506
- /// <param name="patchHeaderFileName">Name of file to create with delta header.</param>
507
- /// <returns>true if successfull, sets Marshal.GetLastWin32Error() if not.</returns>
508
- [DllImport("mspatchc.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
509
- [return: MarshalAs(UnmanagedType.Bool)]
510
- internal static extern bool ExtractPatchHeaderToFileW(
511
- string patchFileName, // input file
512
- string patchHeaderFileName // output file
513
- );
514
-
515
- // TODO: Add rest of APIs to enable custom binders to perform more exhaustive checks
516
-
517
- /// <summary>
518
- /// Marshals arguments for the CreatePatch~ APIs
519
- /// </summary>
520
- [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
521
- internal class PatchAPIMarshaler : ICustomMarshaler
522
- {
523
- internal static ICustomMarshaler GetInstance(string cookie)
524
- {
525
- return new PatchAPIMarshaler(cookie);
526
- }
527
-
528
- private enum MarshalType
529
- {
530
- PATCH_OPTION_DATA,
531
- PATCH_OLD_FILE_INFO_W
532
- };
533
- private PatchAPIMarshaler.MarshalType marshalType;
534
-
535
- private PatchAPIMarshaler(string cookie)
536
- {
537
- this.marshalType = (PatchAPIMarshaler.MarshalType)Enum.Parse(typeof(PatchAPIMarshaler.MarshalType), cookie);
538
- }
539
-
540
- //
541
- // Summary:
542
- // Returns the size of the native data to be marshaled.
543
- //
544
- // Returns:
545
- // The size in bytes of the native data.
546
- public int GetNativeDataSize()
547
- {
548
- return Marshal.SizeOf(typeof(IntPtr));
549
- }
550
-
551
- //
552
- // Summary:
553
- // Performs necessary cleanup of the managed data when it is no longer needed.
554
- //
555
- // Parameters:
556
- // ManagedObj:
557
- // The managed object to be destroyed.
558
- public void CleanUpManagedData(object ManagedObj)
559
- {
560
- }
561
-
562
- //
563
- // Summary:
564
- // Performs necessary cleanup of the unmanaged data when it is no longer needed.
565
- //
566
- // Parameters:
567
- // pNativeData:
568
- // A pointer to the unmanaged data to be destroyed.
569
- public void CleanUpNativeData(IntPtr pNativeData)
570
- {
571
- if (IntPtr.Zero == pNativeData)
572
- {
573
- return;
574
- }
575
-
576
- switch (this.marshalType)
577
- {
578
- case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
579
- this.CleanUpPOD(pNativeData);
580
- break;
581
- default:
582
- this.CleanUpPOFI_A(pNativeData);
583
- break;
584
- }
585
- }
586
-
587
- //
588
- // Summary:
589
- // Converts the managed data to unmanaged data.
590
- //
591
- // Parameters:
592
- // ManagedObj:
593
- // The managed object to be converted.
594
- //
595
- // Returns:
596
- // Returns the COM view of the managed object.
597
- public IntPtr MarshalManagedToNative(object ManagedObj)
598
- {
599
- if (null == ManagedObj)
600
- {
601
- return IntPtr.Zero;
602
- }
603
-
604
- switch (this.marshalType)
605
- {
606
- case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
607
- return this.MarshalPOD(ManagedObj as PatchOptionData);
608
- case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W:
609
- return this.MarshalPOFIW_A(ManagedObj as PatchOldFileInfoW[]);
610
- default:
611
- throw new InvalidOperationException();
612
- }
613
- }
614
-
615
-
616
- //
617
- // Summary:
618
- // Converts the unmanaged data to managed data.
619
- //
620
- // Parameters:
621
- // pNativeData:
622
- // A pointer to the unmanaged data to be wrapped.
623
- //
624
- // Returns:
625
- // Returns the managed view of the COM data.
626
- public object MarshalNativeToManaged(IntPtr pNativeData)
627
- {
628
- return null;
629
- }
630
-
631
- // Implementation *************************************************
632
-
633
- // PATCH_OPTION_DATA offsets
634
- private static readonly int symbolOptionFlagsOffset = Marshal.SizeOf(typeof(Int32));
635
- private static readonly int newFileSymbolPathOffset = 2 * Marshal.SizeOf(typeof(Int32));
636
- private static readonly int oldFileSymbolPathArrayOffset = 2 * Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
637
- private static readonly int extendedOptionFlagsOffset = 2 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
638
- private static readonly int symLoadCallbackOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
639
- private static readonly int symLoadContextOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 3 * Marshal.SizeOf(typeof(IntPtr));
640
- private static readonly int interleaveMapArrayOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 4 * Marshal.SizeOf(typeof(IntPtr));
641
- private static readonly int maxLzxWindowSizeOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 5 * Marshal.SizeOf(typeof(IntPtr));
642
- private static readonly int patchOptionDataSize = 4 * Marshal.SizeOf(typeof(Int32)) + 5 * Marshal.SizeOf(typeof(IntPtr));
643
-
644
- // PATCH_OLD_FILE_INFO offsets
645
- private static readonly int oldFileOffset = Marshal.SizeOf(typeof(Int32));
646
- private static readonly int ignoreRangeCountOffset = Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
647
- private static readonly int ignoreRangeArrayOffset = 2 * Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr));
648
- private static readonly int retainRangeCountOffset = 2 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
649
- private static readonly int retainRangeArrayOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr));
650
- private static readonly int patchOldFileInfoSize = 3 * Marshal.SizeOf(typeof(Int32)) + 3 * Marshal.SizeOf(typeof(IntPtr));
651
-
652
- // Methods and data used to preserve data needed for cleanup
653
-
654
- // This dictionary holds the quantity of items internal to each native structure that will need to be freed (the OldFileCount)
655
- private static readonly Dictionary<IntPtr, int> OldFileCounts = new Dictionary<IntPtr, int>();
656
- private static readonly object OldFileCountsLock = new object();
657
-
658
- private IntPtr CreateMainStruct(int oldFileCount)
659
- {
660
- int nativeSize;
661
- switch (this.marshalType)
662
- {
663
- case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA:
664
- nativeSize = patchOptionDataSize;
665
- break;
666
- case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W:
667
- nativeSize = oldFileCount * patchOldFileInfoSize;
668
- break;
669
- default:
670
- throw new InvalidOperationException();
671
- }
672
-
673
- IntPtr native = Marshal.AllocCoTaskMem(nativeSize);
674
-
675
- lock (PatchAPIMarshaler.OldFileCountsLock)
676
- {
677
- PatchAPIMarshaler.OldFileCounts.Add(native, oldFileCount);
678
- }
679
-
680
- return native;
681
- }
682
-
683
- private static void ReleaseMainStruct(IntPtr native)
684
- {
685
- lock (PatchAPIMarshaler.OldFileCountsLock)
686
- {
687
- PatchAPIMarshaler.OldFileCounts.Remove(native);
688
- }
689
- Marshal.FreeCoTaskMem(native);
690
- }
691
-
692
- private static int GetOldFileCount(IntPtr native)
693
- {
694
- lock (PatchAPIMarshaler.OldFileCountsLock)
695
- {
696
- return PatchAPIMarshaler.OldFileCounts[native];
697
- }
698
- }
699
-
700
- // Helper methods
701
-
702
- private static IntPtr OptionalAnsiString(string managed)
703
- {
704
- return (null == managed) ? IntPtr.Zero : Marshal.StringToCoTaskMemAnsi(managed);
705
- }
706
-
707
- private static IntPtr OptionalUnicodeString(string managed)
708
- {
709
- return (null == managed) ? IntPtr.Zero : Marshal.StringToCoTaskMemUni(managed);
710
- }
711
-
712
- // string array must be of the same length as the number of old files
713
- private static IntPtr CreateArrayOfStringA(string[] managed)
714
- {
715
- if (null == managed)
716
- {
717
- return IntPtr.Zero;
718
- }
719
-
720
- int size = managed.Length * Marshal.SizeOf(typeof(IntPtr));
721
- IntPtr native = Marshal.AllocCoTaskMem(size);
722
-
723
- for (int i = 0; i < managed.Length; ++i)
724
- {
725
- Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), OptionalAnsiString(managed[i]));
726
- }
727
-
728
- return native;
729
- }
730
-
731
- // string array must be of the same length as the number of old files
732
- private static IntPtr CreateArrayOfStringW(string[] managed)
733
- {
734
- if (null == managed)
735
- {
736
- return IntPtr.Zero;
737
- }
738
-
739
- int size = managed.Length * Marshal.SizeOf(typeof(IntPtr));
740
- IntPtr native = Marshal.AllocCoTaskMem(size);
741
-
742
- for (int i = 0; i < managed.Length; ++i)
743
- {
744
- Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), OptionalUnicodeString(managed[i]));
745
- }
746
-
747
- return native;
748
- }
749
-
750
- private static IntPtr CreateInterleaveMapRange(PatchInterleaveMap managed)
751
- {
752
- if (null == managed)
753
- {
754
- return IntPtr.Zero;
755
- }
756
-
757
- if (null == managed.ranges)
758
- {
759
- return IntPtr.Zero;
760
- }
761
-
762
- if (0 == managed.ranges.Length)
763
- {
764
- return IntPtr.Zero;
765
- }
766
-
767
- IntPtr native = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UInt32))
768
- + managed.ranges.Length * (Marshal.SizeOf(typeof(PatchInterleaveMap))));
769
- WriteUInt32(native, (uint)managed.ranges.Length);
770
-
771
- for (int i = 0; i < managed.ranges.Length; ++i)
772
- {
773
- Marshal.StructureToPtr(managed.ranges[i], (IntPtr)((Int64)native + i * Marshal.SizeOf(typeof(PatchInterleaveMap))), false);
774
- }
775
- return native;
776
- }
777
-
778
- private static IntPtr CreateInterleaveMap(PatchInterleaveMap[] managed)
779
- {
780
- if (null == managed)
781
- {
782
- return IntPtr.Zero;
783
- }
784
-
785
- IntPtr native = Marshal.AllocCoTaskMem(managed.Length * Marshal.SizeOf(typeof(IntPtr)));
786
-
787
- for (int i = 0; i < managed.Length; ++i)
788
- {
789
- Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), CreateInterleaveMapRange(managed[i]));
790
- }
791
-
792
- return native;
793
- }
794
-
795
- private static void WriteUInt32(IntPtr native, uint data)
796
- {
797
- Marshal.WriteInt32(native, unchecked((int)data));
798
- }
799
-
800
- private static void WriteUInt32(IntPtr native, int offset, uint data)
801
- {
802
- Marshal.WriteInt32(native, offset, unchecked((int)data));
803
- }
804
-
805
- // Marshal operations
806
-
807
- private IntPtr MarshalPOD(PatchOptionData managed)
808
- {
809
- if (null == managed)
810
- {
811
- throw new ArgumentNullException("managed");
812
- }
813
-
814
- IntPtr native = this.CreateMainStruct(managed.oldFileSymbolPathArray.Length);
815
- Marshal.WriteInt32(native, patchOptionDataSize); // SizeOfThisStruct
816
- WriteUInt32(native, symbolOptionFlagsOffset, (uint)managed.symbolOptionFlags);
817
- Marshal.WriteIntPtr(native, newFileSymbolPathOffset, PatchAPIMarshaler.OptionalAnsiString(managed.newFileSymbolPath));
818
- Marshal.WriteIntPtr(native, oldFileSymbolPathArrayOffset, PatchAPIMarshaler.CreateArrayOfStringA(managed.oldFileSymbolPathArray));
819
- WriteUInt32(native, extendedOptionFlagsOffset, managed.extendedOptionFlags);
820
-
821
- // GetFunctionPointerForDelegate() throws an ArgumentNullException if the delegate is null.
822
- if (null == managed.symLoadCallback)
823
- {
824
- Marshal.WriteIntPtr(native, symLoadCallbackOffset, IntPtr.Zero);
825
- }
826
- else
827
- {
828
- Marshal.WriteIntPtr(native, symLoadCallbackOffset, Marshal.GetFunctionPointerForDelegate(managed.symLoadCallback));
829
- }
830
-
831
- Marshal.WriteIntPtr(native, symLoadContextOffset, managed.symLoadContext);
832
- Marshal.WriteIntPtr(native, interleaveMapArrayOffset, PatchAPIMarshaler.CreateInterleaveMap(managed.interleaveMapArray));
833
- WriteUInt32(native, maxLzxWindowSizeOffset, managed.maxLzxWindowSize);
834
- return native;
835
- }
836
-
837
- private IntPtr MarshalPOFIW_A(PatchOldFileInfoW[] managed)
838
- {
839
- if (null == managed)
840
- {
841
- throw new ArgumentNullException("managed");
842
- }
843
-
844
- if (0 == managed.Length)
845
- {
846
- return IntPtr.Zero;
847
- }
848
-
849
- IntPtr native = this.CreateMainStruct(managed.Length);
850
-
851
- for (int i = 0; i < managed.Length; ++i)
852
- {
853
- PatchAPIMarshaler.MarshalPOFIW(managed[i], (IntPtr)((Int64)native + i * patchOldFileInfoSize));
854
- }
855
-
856
- return native;
857
- }
858
-
859
- private static void MarshalPOFIW(PatchOldFileInfoW managed, IntPtr native)
860
- {
861
- PatchAPIMarshaler.MarshalPOFI(managed, native);
862
- Marshal.WriteIntPtr(native, oldFileOffset, PatchAPIMarshaler.OptionalUnicodeString(managed.oldFileName)); // OldFileName
863
- }
864
-
865
- private static void MarshalPOFI(PatchOldFileInfo managed, IntPtr native)
866
- {
867
- Marshal.WriteInt32(native, patchOldFileInfoSize); // SizeOfThisStruct
868
- WriteUInt32(native, ignoreRangeCountOffset,
869
- (null == managed.ignoreRange) ? 0 : (uint)managed.ignoreRange.Length); // IgnoreRangeCount // maximum 255
870
- Marshal.WriteIntPtr(native, ignoreRangeArrayOffset, MarshalPIRArray(managed.ignoreRange)); // IgnoreRangeArray
871
- WriteUInt32(native, retainRangeCountOffset,
872
- (null == managed.retainRange) ? 0 : (uint)managed.retainRange.Length); // RetainRangeCount // maximum 255
873
- Marshal.WriteIntPtr(native, retainRangeArrayOffset, MarshalPRRArray(managed.retainRange)); // RetainRangeArray
874
- }
875
-
876
- private static IntPtr MarshalPIRArray(PatchIgnoreRange[] array)
877
- {
878
- if (null == array)
879
- {
880
- return IntPtr.Zero;
881
- }
882
-
883
- if (0 == array.Length)
884
- {
885
- return IntPtr.Zero;
886
- }
887
-
888
- IntPtr native = Marshal.AllocCoTaskMem(array.Length * Marshal.SizeOf(typeof(PatchIgnoreRange)));
889
-
890
- for (int i = 0; i < array.Length; ++i)
891
- {
892
- Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i * Marshal.SizeOf(typeof(PatchIgnoreRange)))), false);
893
- }
894
-
895
- return native;
896
- }
897
-
898
- private static IntPtr MarshalPRRArray(PatchRetainRange[] array)
899
- {
900
- if (null == array)
901
- {
902
- return IntPtr.Zero;
903
- }
904
-
905
- if (0 == array.Length)
906
- {
907
- return IntPtr.Zero;
908
- }
909
-
910
- IntPtr native = Marshal.AllocCoTaskMem(array.Length * Marshal.SizeOf(typeof(PatchRetainRange)));
911
-
912
- for (int i = 0; i < array.Length; ++i)
913
- {
914
- Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i * Marshal.SizeOf(typeof(PatchRetainRange)))), false);
915
- }
916
-
917
- return native;
918
- }
919
-
920
- // CleanUp operations
921
-
922
- private void CleanUpPOD(IntPtr native)
923
- {
924
- Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, newFileSymbolPathOffset));
925
-
926
- if (IntPtr.Zero != Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset))
927
- {
928
- for (int i = 0; i < GetOldFileCount(native); ++i)
929
- {
930
- Marshal.FreeCoTaskMem(
931
- Marshal.ReadIntPtr(
932
- Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset),
933
- i * Marshal.SizeOf(typeof(IntPtr))));
934
- }
935
-
936
- Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset));
937
- }
938
-
939
- if (IntPtr.Zero != Marshal.ReadIntPtr(native, interleaveMapArrayOffset))
940
- {
941
- for (int i = 0; i < GetOldFileCount(native); ++i)
942
- {
943
- Marshal.FreeCoTaskMem(
944
- Marshal.ReadIntPtr(
945
- Marshal.ReadIntPtr(native, interleaveMapArrayOffset),
946
- i * Marshal.SizeOf(typeof(IntPtr))));
947
- }
948
-
949
- Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, interleaveMapArrayOffset));
950
- }
951
-
952
- PatchAPIMarshaler.ReleaseMainStruct(native);
953
- }
954
-
955
- private void CleanUpPOFI_A(IntPtr native)
956
- {
957
- for (int i = 0; i < GetOldFileCount(native); ++i)
958
- {
959
- PatchAPIMarshaler.CleanUpPOFI((IntPtr)((Int64)native + i * patchOldFileInfoSize));
960
- }
961
-
962
- PatchAPIMarshaler.ReleaseMainStruct(native);
963
- }
964
-
965
- private static void CleanUpPOFI(IntPtr native)
966
- {
967
- if (IntPtr.Zero != Marshal.ReadIntPtr(native, oldFileOffset))
968
- {
969
- Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileOffset));
970
- }
971
-
972
- PatchAPIMarshaler.CleanUpPOFIH(native);
973
- }
974
-
975
- private static void CleanUpPOFIH(IntPtr native)
976
- {
977
- if (IntPtr.Zero != Marshal.ReadIntPtr(native, ignoreRangeArrayOffset))
978
- {
979
- Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, ignoreRangeArrayOffset));
980
- }
981
-
982
- if (IntPtr.Zero != Marshal.ReadIntPtr(native, retainRangeArrayOffset))
983
- {
984
- Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, retainRangeArrayOffset));
985
- }
986
- }
987
- }
988
- }
989
-}
src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs
+1
-1
@@ -9,7 +9,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
9
using System.IO;
10
using System.Linq;
11
using WixToolset.Core.Native;
12
- using WixToolset.Core.WindowsInstaller.Msi;
12
+ using WixToolset.Core.Native.Msi;
13
using WixToolset.Data;
14
using WixToolset.Data.WindowsInstaller;
15
using WixToolset.Data.WindowsInstaller.Rows;
src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
+3
-3
@@ -8,7 +8,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
8
using System.Globalization;
9
using System.IO;
10
using System.Text.RegularExpressions;
11
- using WixToolset.Core.WindowsInstaller.Msi;
11
+ using WixToolset.Core.Native.Msi;
12
using WixToolset.Data;
13
using WixToolset.Data.WindowsInstaller;
14
using WixToolset.Extensibility.Services;
@@ -288,8 +288,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
288
}
289
290
ColumnDefinition[] columns;
291
- using (Record columnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES),
292
- columnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES))
291
+ using (Record columnNameRecord = tableView.GetColumnNames(),
292
+ columnTypeRecord = tableView.GetColumnTypes())
293
{
294
// index the primary keys
295
var tablePrimaryKeys = new HashSet<string>();
src/WixToolset.Core.WindowsInstaller/Unbind/UnbindMsiOrMsmCommand.cs
+1
-1
@@ -6,7 +6,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
6
using System.ComponentModel;
7
using WixToolset.Data;
8
using WixToolset.Extensibility.Data;
9
- using WixToolset.Core.WindowsInstaller.Msi;
9
+ using WixToolset.Core.Native.Msi;
10
11
internal class UnbindMsiOrMsmCommand
12
{
src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs
+1
-1
@@ -9,8 +9,8 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
9
using System.Globalization;
10
using System.IO;
11
using System.Linq;
12
+ using WixToolset.Core.Native.Msi;
13
using WixToolset.Core.WindowsInstaller.Bind;
13
- using WixToolset.Core.WindowsInstaller.Msi;
14
using WixToolset.Data;
15
using WixToolset.Data.WindowsInstaller;
16
using WixToolset.Extensibility.Services;
src/WixToolset.Core.WindowsInstaller/ValidatorExtension.cs
deleted
-288
@@ -1,288 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Extensibility
4
-{
5
- using System;
6
- using System.Collections;
7
- using WixToolset.Data;
8
- using WixToolset.Data.WindowsInstaller;
9
- using WixToolset.Extensibility.Services;
10
-
11
- /// <summary>
12
- /// Base class for creating a validator extension. This default implementation
13
- /// will fire and event with the ICE name and description.
14
- /// </summary>
15
- public class ValidatorExtension
16
- {
17
- private string databaseFile;
18
- private Hashtable indexedSourceLineNumbers;
19
- private WindowsInstallerData output;
20
- private SourceLineNumber sourceLineNumbers;
21
- private readonly IMessaging messaging;
22
-
23
- /// <summary>
24
- /// Instantiate a new <see cref="ValidatorExtension"/>.
25
- /// </summary>
26
- public ValidatorExtension(IMessaging messaging)
27
- {
28
- this.messaging = messaging;
29
- }
30
-
31
- /// <summary>
32
- /// Gets or sets the path to the database to validate.
33
- /// </summary>
34
- /// <value>The path to the database to validate.</value>
35
- public string DatabaseFile
36
- {
37
- get { return this.databaseFile; }
38
- set { this.databaseFile = value; }
39
- }
40
-
41
- /// <summary>
42
- /// Gets or sets the <see cref="Output"/> for finding source line information.
43
- /// </summary>
44
- /// <value>The <see cref="Output"/> for finding source line information.</value>
45
- public WindowsInstallerData Output
46
- {
47
- get { return this.output; }
48
- set { this.output = value; }
49
- }
50
-
51
- /// <summary>
52
- /// Called at the beginning of the validation of a database file.
53
- /// </summary>
54
- /// <remarks>
55
- /// <para>The Validator will set
56
- /// <see cref="DatabaseFile"/> before calling InitializeValidator.</para>
57
- /// <para><b>Notes to Inheritors:</b> When overriding
58
- /// <b>InitializeValidator</b> in a derived class, be sure to call
59
- /// the base class's <b>InitializeValidator</b> to thoroughly
60
- /// initialize the extension.</para>
61
- /// </remarks>
62
- public virtual void InitializeValidator()
63
- {
64
- if (this.databaseFile != null)
65
- {
66
- this.sourceLineNumbers = new SourceLineNumber(this.databaseFile);
67
- }
68
- }
69
-
70
- /// <summary>
71
- /// Called at the end of the validation of a database file.
72
- /// </summary>
73
- /// <remarks>
74
- /// <para>The default implementation will nullify source lines.</para>
75
- /// <para><b>Notes to Inheritors:</b> When overriding
76
- /// <b>FinalizeValidator</b> in a derived class, be sure to call
77
- /// the base class's <b>FinalizeValidator</b> to thoroughly
78
- /// finalize the extension.</para>
79
- /// </remarks>
80
- public virtual void FinalizeValidator()
81
- {
82
- this.sourceLineNumbers = null;
83
- }
84
-
85
- /// <summary>
86
- /// Logs a message from the Validator.
87
- /// </summary>
88
- /// <param name="message">A <see cref="String"/> of tab-delmited tokens
89
- /// in the validation message.</param>
90
- public virtual void Log(string message)
91
- {
92
- this.Log(message, null);
93
- }
94
-
95
- /// <summary>
96
- /// Logs a message from the Validator.
97
- /// </summary>
98
- /// <param name="message">A <see cref="String"/> of tab-delmited tokens
99
- /// in the validation message.</param>
100
- /// <param name="action">The name of the action to which the message
101
- /// belongs.</param>
102
- /// <exception cref="ArgumentNullException">The message cannot be null.
103
- /// </exception>
104
- /// <exception cref="WixException">The message does not contain four (4)
105
- /// or more tab-delimited tokens.</exception>
106
- /// <remarks>
107
- /// <para><paramref name="message"/> a tab-delimited set of tokens,
108
- /// formatted according to Windows Installer guidelines for ICE
109
- /// message. The following table lists what each token by index
110
- /// should mean.</para>
111
- /// <para><paramref name="action"/> a name that represents the ICE
112
- /// action that was executed (e.g. 'ICE08').</para>
113
- /// <list type="table">
114
- /// <listheader>
115
- /// <term>Index</term>
116
- /// <description>Description</description>
117
- /// </listheader>
118
- /// <item>
119
- /// <term>0</term>
120
- /// <description>Name of the ICE.</description>
121
- /// </item>
122
- /// <item>
123
- /// <term>1</term>
124
- /// <description>Message type. See the following list.</description>
125
- /// </item>
126
- /// <item>
127
- /// <term>2</term>
128
- /// <description>Detailed description.</description>
129
- /// </item>
130
- /// <item>
131
- /// <term>3</term>
132
- /// <description>Help URL or location.</description>
133
- /// </item>
134
- /// <item>
135
- /// <term>4</term>
136
- /// <description>Table name.</description>
137
- /// </item>
138
- /// <item>
139
- /// <term>5</term>
140
- /// <description>Column name.</description>
141
- /// </item>
142
- /// <item>
143
- /// <term>6</term>
144
- /// <description>This and remaining fields are primary keys
145
- /// to identify a row.</description>
146
- /// </item>
147
- /// </list>
148
- /// <para>The message types are one of the following value.</para>
149
- /// <list type="table">
150
- /// <listheader>
151
- /// <term>Value</term>
152
- /// <description>Message Type</description>
153
- /// </listheader>
154
- /// <item>
155
- /// <term>0</term>
156
- /// <description>Failure message reporting the failure of the
157
- /// ICE custom action.</description>
158
- /// </item>
159
- /// <item>
160
- /// <term>1</term>
161
- /// <description>Error message reporting database authoring that
162
- /// case incorrect behavior.</description>
163
- /// </item>
164
- /// <item>
165
- /// <term>2</term>
166
- /// <description>Warning message reporting database authoring that
167
- /// causes incorrect behavior in certain cases. Warnings can also
168
- /// report unexpected side-effects of database authoring.
169
- /// </description>
170
- /// </item>
171
- /// <item>
172
- /// <term>3</term>
173
- /// <description>Informational message.</description>
174
- /// </item>
175
- /// </list>
176
- /// </remarks>
177
- public virtual void Log(string message, string action)
178
- {
179
- if (message == null)
180
- {
181
- throw new ArgumentNullException("message");
182
- }
183
-
184
- var messageParts = message.Split('\t');
185
- if (3 > messageParts.Length)
186
- {
187
- if (null == action)
188
- {
189
- throw new WixException(ErrorMessages.UnexpectedExternalUIMessage(message));
190
- }
191
- else
192
- {
193
- throw new WixException(ErrorMessages.UnexpectedExternalUIMessage(message, action));
194
- }
195
- }
196
-
197
- SourceLineNumber messageSourceLineNumbers;
198
- if (6 < messageParts.Length)
199
- {
200
- var primaryKeys = new string[messageParts.Length - 6];
201
-
202
- Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length);
203
-
204
- messageSourceLineNumbers = this.GetSourceLineNumbers(messageParts[4], primaryKeys);
205
- }
206
- else // use the file name as the source line information
207
- {
208
- messageSourceLineNumbers = this.sourceLineNumbers;
209
- }
210
-
211
- switch (messageParts[1])
212
- {
213
- case "0":
214
- case "1":
215
- this.messaging.Write(ErrorMessages.ValidationError(messageSourceLineNumbers, messageParts[0], messageParts[2]));
216
- break;
217
- case "2":
218
- this.messaging.Write(WarningMessages.ValidationWarning(messageSourceLineNumbers, messageParts[0], messageParts[2]));
219
- break;
220
- case "3":
221
- this.messaging.Write(VerboseMessages.ValidationInfo(messageParts[0], messageParts[2]));
222
- break;
223
- default:
224
- throw new WixException(ErrorMessages.InvalidValidatorMessageType(messageParts[1]));
225
- }
226
- }
227
-
228
- /// <summary>
229
- /// Gets the source line information (if available) for a row by its table name and primary key.
230
- /// </summary>
231
- /// <param name="tableName">The table name of the row.</param>
232
- /// <param name="primaryKeys">The primary keys of the row.</param>
233
- /// <returns>The source line number information if found; null otherwise.</returns>
234
- protected SourceLineNumber GetSourceLineNumbers(string tableName, string[] primaryKeys)
235
- {
236
- // source line information only exists if an output file was supplied
237
- if (null != this.output)
238
- {
239
- // index the source line information if it hasn't been indexed already
240
- if (null == this.indexedSourceLineNumbers)
241
- {
242
- this.indexedSourceLineNumbers = new Hashtable();
243
-
244
- // index each real table
245
- foreach (var table in this.output.Tables)
246
- {
247
- // skip unreal tables
248
- if (table.Definition.Unreal)
249
- {
250
- continue;
251
- }
252
-
253
- // index each row
254
- foreach (var row in table.Rows)
255
- {
256
- // skip rows that don't contain source line information
257
- if (null == row.SourceLineNumbers)
258
- {
259
- continue;
260
- }
261
-
262
- // index the row using its table name and primary key
263
- var primaryKey = row.GetPrimaryKey(';');
264
- if (null != primaryKey)
265
- {
266
- var key = String.Concat(table.Name, ":", primaryKey);
267
-
268
- if (this.indexedSourceLineNumbers.ContainsKey(key))
269
- {
270
- this.messaging.Write(WarningMessages.DuplicatePrimaryKey(row.SourceLineNumbers, primaryKey, table.Name));
271
- }
272
- else
273
- {
274
- this.indexedSourceLineNumbers.Add(key, row.SourceLineNumbers);
275
- }
276
- }
277
- }
278
- }
279
- }
280
-
281
- return (SourceLineNumber)this.indexedSourceLineNumbers[String.Concat(tableName, ":", String.Join(";", primaryKeys))];
282
- }
283
-
284
- // use the file name as the source line information
285
- return this.sourceLineNumbers;
286
- }
287
- }
288
-}
src/WixToolset.Core/Bind/FileSystem.cs
deleted
-86
@@ -1,86 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core.Bind
4
-{
5
- using System;
6
- using System.Collections.Generic;
7
- using System.IO;
8
- using System.Runtime.InteropServices;
9
- using WixToolset.Extensibility;
10
-
11
- internal class FileSystem
12
- {
13
- public FileSystem(IEnumerable<ILayoutExtension> extensions)
14
- {
15
- this.Extensions = extensions ?? Array.Empty<ILayoutExtension>();
16
- }
17
-
18
- private IEnumerable<ILayoutExtension> Extensions { get; }
19
-
20
- /// <summary>
21
- /// Copies a file.
22
- /// </summary>
23
- /// <param name="source">The file to copy.</param>
24
- /// <param name="destination">The destination file.</param>
25
- public bool CopyFile(string source, string destination)
26
- {
27
- foreach (var extension in this.Extensions)
28
- {
29
- if (extension.CopyFile(source, destination))
30
- {
31
- return true;
32
- }
33
- }
34
-
35
- if (File.Exists(destination))
36
- {
37
- File.Delete(destination);
38
- }
39
-
40
- if (!CreateHardLink(destination, source, IntPtr.Zero))
41
- {
42
-#if DEBUG
43
- int er = Marshal.GetLastWin32Error();
44
-#endif
45
-
46
- File.Copy(source, destination, true);
47
- }
48
-
49
- return true;
50
- }
51
-
52
- /// <summary>
53
- /// Moves a file.
54
- /// </summary>
55
- /// <param name="source">The file to move.</param>
56
- /// <param name="destination">The destination file.</param>
57
- public bool MoveFile(string source, string destination)
58
- {
59
- foreach (var extension in this.Extensions)
60
- {
61
- if (extension.MoveFile(source, destination))
62
- {
63
- return true;
64
- }
65
- }
66
-
67
- if (File.Exists(destination))
68
- {
69
- File.Delete(destination);
70
- }
71
-
72
- var directory = Path.GetDirectoryName(destination);
73
- if (!String.IsNullOrEmpty(directory))
74
- {
75
- Directory.CreateDirectory(directory);
76
- }
77
-
78
- File.Move(source, destination);
79
-
80
- return true;
81
- }
82
-
83
- [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
84
- private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
85
- }
86
-}
src/WixToolset.Core/Bind/TransferFilesCommand.cs
+29
-23
@@ -6,6 +6,7 @@ namespace WixToolset.Core.Bind
6
using System.Collections.Generic;
7
using System.IO;
8
using System.Security.AccessControl;
9
+ using WixToolset.Core.Native;
10
using WixToolset.Data;
11
using WixToolset.Extensibility;
12
using WixToolset.Extensibility.Data;
@@ -15,23 +16,23 @@ namespace WixToolset.Core.Bind
16
{
17
public TransferFilesCommand(IMessaging messaging, IEnumerable<ILayoutExtension> extensions, IEnumerable<IFileTransfer> fileTransfers, bool suppressAclReset)
18
{
18
- this.FileSystem = new FileSystem(extensions);
19
+ this.Extensions = extensions;
20
this.Messaging = messaging;
21
this.FileTransfers = fileTransfers;
22
this.SuppressAclReset = suppressAclReset;
23
}
24
24
- private FileSystem FileSystem { get; }
25
-
25
private IMessaging Messaging { get; }
26
27
+ private IEnumerable<ILayoutExtension> Extensions { get; }
28
+
29
private IEnumerable<IFileTransfer> FileTransfers { get; }
30
31
private bool SuppressAclReset { get; }
32
33
public void Execute()
34
{
34
- List<string> destinationFiles = new List<string>();
35
+ var destinationFiles = new List<string>();
36
37
foreach (var fileTransfer in this.FileTransfers)
38
{
@@ -42,7 +43,7 @@ namespace WixToolset.Core.Bind
43
continue;
44
}
45
45
- bool retry = false;
46
+ var retry = false;
47
do
48
{
49
try
@@ -50,12 +51,12 @@ namespace WixToolset.Core.Bind
51
if (fileTransfer.Move)
52
{
53
this.Messaging.Write(VerboseMessages.MoveFile(fileTransfer.Source, fileTransfer.Destination));
53
- this.TransferFile(true, fileTransfer.Source, fileTransfer.Destination);
54
+ this.MoveFile(fileTransfer.Source, fileTransfer.Destination);
55
}
56
else
57
{
58
this.Messaging.Write(VerboseMessages.CopyFile(fileTransfer.Source, fileTransfer.Destination));
58
- this.TransferFile(false, fileTransfer.Source, fileTransfer.Destination);
59
+ this.CopyFile(fileTransfer.Source, fileTransfer.Destination);
60
}
61
62
retry = false;
@@ -73,7 +74,7 @@ namespace WixToolset.Core.Bind
74
throw;
75
}
76
76
- string directory = Path.GetDirectoryName(fileTransfer.Destination);
77
+ var directory = Path.GetDirectoryName(fileTransfer.Destination);
78
this.Messaging.Write(VerboseMessages.CreateDirectory(directory));
79
Directory.CreateDirectory(directory);
80
retry = true;
@@ -91,7 +92,7 @@ namespace WixToolset.Core.Bind
92
this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination));
93
94
// try to ensure the file is not read-only
94
- FileAttributes attributes = File.GetAttributes(fileTransfer.Destination);
95
+ var attributes = File.GetAttributes(fileTransfer.Destination);
96
try
97
{
98
File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly);
@@ -131,7 +132,7 @@ namespace WixToolset.Core.Bind
132
this.Messaging.Write(VerboseMessages.RemoveDestinationFile(fileTransfer.Destination));
133
134
// ensure the file is not read-only, then delete it
134
- FileAttributes attributes = File.GetAttributes(fileTransfer.Destination);
135
+ var attributes = File.GetAttributes(fileTransfer.Destination);
136
File.SetAttributes(fileTransfer.Destination, attributes & ~FileAttributes.ReadOnly);
137
try
138
{
@@ -161,8 +162,6 @@ namespace WixToolset.Core.Bind
162
163
try
164
{
164
- //WixToolset.Core.Native.NativeMethods.ResetAcls(destinationFiles.ToArray(), (uint)destinationFiles.Count);
165
-
165
foreach (var file in destinationFiles)
166
{
167
new FileInfo(file).SetAccessControl(aclReset);
@@ -175,23 +174,30 @@ namespace WixToolset.Core.Bind
174
}
175
}
176
178
- private void TransferFile(bool move, string source, string destination)
177
+ private void CopyFile(string source, string destination)
178
{
180
- bool complete = false;
181
-
182
- if (move)
179
+ foreach (var extension in this.Extensions)
180
{
184
- complete = this.FileSystem.MoveFile(source, destination);
185
- }
186
- else
187
- {
188
- complete = this.FileSystem.CopyFile(source, destination);
181
+ if (extension.CopyFile(source, destination))
182
+ {
183
+ return;
184
+ }
185
}
186
191
- if (!complete)
187
+ FileSystem.CopyFile(source, destination, allowHardlink: true);
188
+ }
189
+
190
+ private void MoveFile(string source, string destination)
191
+ {
192
+ foreach (var extension in this.Extensions)
193
{
193
- throw new InvalidOperationException(); // TODO: something needs to be said here that none of the binder file managers returned a result.
194
+ if (extension.MoveFile(source, destination))
195
+ {
196
+ return;
197
+ }
198
}
199
+
200
+ FileSystem.MoveFile(source, destination);
201
}
202
}
203
}
src/WixToolset.Core/Inscriber.cs
deleted
-437
@@ -1,437 +0,0 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
-
3
-namespace WixToolset.Core
4
-{
5
- using System.IO;
6
- using WixToolset.Data;
7
-
8
- /// <summary>
9
- /// Converts a wixout representation of an MSM database into a ComponentGroup the form of WiX source.
10
- /// </summary>
11
- internal class Inscriber
12
- {
13
- // <summary>
14
- // Gets or sets the temp files collection.
15
- // </summary>
16
- // <value>The temp files collection.</value>
17
- // public TempFileCollection TempFiles
18
- // {
19
- // get { return this.tempFiles; }
20
- // set { this.tempFiles = value; }
21
- // }
22
-
23
- /// <summary>
24
- /// Gets or sets the path to the temp files location.
25
- /// </summary>
26
- /// <value>The path to the temp files location.</value>
27
- public string TempFilesLocation
28
- {
29
- get
30
- {
31
- // if (null == this.tempFiles)
32
- // {
33
- // return null;
34
- // }
35
- // else
36
- // {
37
- // return this.tempFiles.BasePath;
38
- // }
39
- return Path.GetTempPath();
40
- }
41
- // set
42
- // {
43
- // this.DeleteTempFiles();
44
-
45
- // if (null == value)
46
- // {
47
- // this.tempFiles = new TempFileCollection();
48
- // }
49
- // else
50
- // {
51
- // this.tempFiles = new TempFileCollection(value);
52
- // }
53
-
54
- // // ensure the base path exists
55
- // Directory.CreateDirectory(this.tempFiles.BasePath);
56
- // }
57
- }
58
-
59
- /// <summary>
60
- /// Extracts engine from attached container and updates engine with detached container signatures.
61
- /// </summary>
62
- /// <param name="bundleFile">Bundle with attached container.</param>
63
- /// <param name="outputFile">Bundle engine only.</param>
64
- /// <returns>True if bundle was updated.</returns>
65
- public bool InscribeBundleEngine(string bundleFile, string outputFile)
66
- {
67
- //string tempFile = Path.Combine(this.TempFilesLocation, "bundle_engine_unsigned.exe");
68
-
69
- //using (BurnReader reader = BurnReader.Open(bundleFile))
70
- //using (FileStream writer = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete))
71
- //{
72
- // reader.Stream.Seek(0, SeekOrigin.Begin);
73
-
74
- // byte[] buffer = new byte[4 * 1024];
75
- // int total = 0;
76
- // int read = 0;
77
- // do
78
- // {
79
- // read = Math.Min(buffer.Length, (int)reader.EngineSize - total);
80
-
81
- // read = reader.Stream.Read(buffer, 0, read);
82
- // writer.Write(buffer, 0, read);
83
-
84
- // total += read;
85
- // } while (total < reader.EngineSize && 0 < read);
86
-
87
- // if (total != reader.EngineSize)
88
- // {
89
- // throw new InvalidOperationException("Failed to copy engine out of bundle.");
90
- // }
91
-
92
- // // TODO: update writer with detached container signatures.
93
- //}
94
-
95
- //Directory.CreateDirectory(Path.GetDirectoryName(outputFile));
96
- //if (File.Exists(outputFile))
97
- //{
98
- // File.Delete(outputFile);
99
- //}
100
- //File.Move(tempFile, outputFile);
101
- //WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { outputFile }, 1);
102
-
103
- return true;
104
- }
105
-
106
- /// <summary>
107
- /// Updates engine with attached container information and adds attached container again.
108
- /// </summary>
109
- /// <param name="bundleFile">Bundle with attached container.</param>
110
- /// <param name="signedEngineFile">Signed bundle engine.</param>
111
- /// <param name="outputFile">Signed engine with attached container.</param>
112
- /// <returns>True if bundle was updated.</returns>
113
- public bool InscribeBundle(string bundleFile, string signedEngineFile, string outputFile)
114
- {
115
- //bool inscribed = false;
116
- //string tempFile = Path.Combine(this.TempFilesLocation, "bundle_engine_signed.exe");
117
-
118
- //using (BurnReader reader = BurnReader.Open(bundleFile))
119
- //{
120
- // File.Copy(signedEngineFile, tempFile, true);
121
-
122
- // // If there was an attached container on the original (unsigned) bundle, put it back.
123
- // if (reader.AttachedContainerSize > 0)
124
- // {
125
- // reader.Stream.Seek(reader.AttachedContainerAddress, SeekOrigin.Begin);
126
-
127
- // using (BurnWriter writer = BurnWriter.Open(tempFile))
128
- // {
129
- // writer.RememberThenResetSignature();
130
- // writer.AppendContainer(reader.Stream, reader.AttachedContainerSize, BurnCommon.Container.Attached);
131
- // inscribed = true;
132
- // }
133
- // }
134
- //}
135
-
136
- //Directory.CreateDirectory(Path.GetDirectoryName(outputFile));
137
- //if (File.Exists(outputFile))
138
- //{
139
- // File.Delete(outputFile);
140
- //}
141
- //File.Move(tempFile, outputFile);
142
- //WixToolset.Core.Native.NativeMethods.ResetAcls(new string[] { outputFile }, 1);
143
-
144
- //return inscribed;
145
- return false;
146
- }
147
-
148
- /// <summary>
149
- /// Updates database with signatures from external cabinets.
150
- /// </summary>
151
- /// <param name="databaseFile">Path to MSI database.</param>
152
- /// <param name="outputFile">Ouput for updated MSI database.</param>
153
- /// <param name="tidy">Clean up files.</param>
154
- /// <returns>True if database is updated.</returns>
155
- public bool InscribeDatabase(string databaseFile, string outputFile, bool tidy)
156
- {
157
- //// Keeps track of whether we've encountered at least one signed cab or not - we'll throw a warning if no signed cabs were encountered
158
- //bool foundUnsignedExternals = false;
159
- //bool shouldCommit = false;
160
-
161
- //FileAttributes attributes = File.GetAttributes(databaseFile);
162
- //if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly))
163
- //{
164
- // this.OnMessage(WixErrors.ReadOnlyOutputFile(databaseFile));
165
- // return shouldCommit;
166
- //}
167
-
168
- //using (Database database = new Database(databaseFile, OpenDatabase.Transact))
169
- //{
170
- // // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content
171
- // int codepage = 1252;
172
-
173
- // // list of certificates for this database (hash/identifier)
174
- // Dictionary<string, string> certificates = new Dictionary<string, string>();
175
-
176
- // // Reset the in-memory tables for this new database
177
- // Table digitalSignatureTable = new Table(null, this.tableDefinitions["MsiDigitalSignature"]);
178
- // Table digitalCertificateTable = new Table(null, this.tableDefinitions["MsiDigitalCertificate"]);
179
-
180
- // // If any digital signature records exist that are not of the media type, preserve them
181
- // if (database.TableExists("MsiDigitalSignature"))
182
- // {
183
- // using (View digitalSignatureView = database.OpenExecuteView("SELECT `Table`, `SignObject`, `DigitalCertificate_`, `Hash` FROM `MsiDigitalSignature` WHERE `Table` <> 'Media'"))
184
- // {
185
- // while (true)
186
- // {
187
- // using (Record digitalSignatureRecord = digitalSignatureView.Fetch())
188
- // {
189
- // if (null == digitalSignatureRecord)
190
- // {
191
- // break;
192
- // }
193
-
194
- // Row digitalSignatureRow = null;
195
- // digitalSignatureRow = digitalSignatureTable.CreateRow(null);
196
-
197
- // string table = digitalSignatureRecord.GetString(0);
198
- // string signObject = digitalSignatureRecord.GetString(1);
199
-
200
- // digitalSignatureRow[0] = table;
201
- // digitalSignatureRow[1] = signObject;
202
- // digitalSignatureRow[2] = digitalSignatureRecord.GetString(2);
203
-
204
- // if (false == digitalSignatureRecord.IsNull(3))
205
- // {
206
- // // Export to a file, because the MSI API's require us to provide a file path on disk
207
- // string hashPath = Path.Combine(this.TempFilesLocation, "MsiDigitalSignature");
208
- // string hashFileName = string.Concat(table, ".", signObject, ".bin");
209
-
210
- // Directory.CreateDirectory(hashPath);
211
- // hashPath = Path.Combine(hashPath, hashFileName);
212
-
213
- // using (FileStream fs = File.Create(hashPath))
214
- // {
215
- // int bytesRead;
216
- // byte[] buffer = new byte[1024 * 4];
217
-
218
- // while (0 != (bytesRead = digitalSignatureRecord.GetStream(3, buffer, buffer.Length)))
219
- // {
220
- // fs.Write(buffer, 0, bytesRead);
221
- // }
222
- // }
223
-
224
- // digitalSignatureRow[3] = hashFileName;
225
- // }
226
- // }
227
- // }
228
- // }
229
- // }
230
-
231
- // // If any digital certificates exist, extract and preserve them
232
- // if (database.TableExists("MsiDigitalCertificate"))
233
- // {
234
- // using (View digitalCertificateView = database.OpenExecuteView("SELECT * FROM `MsiDigitalCertificate`"))
235
- // {
236
- // while (true)
237
- // {
238
- // using (Record digitalCertificateRecord = digitalCertificateView.Fetch())
239
- // {
240
- // if (null == digitalCertificateRecord)
241
- // {
242
- // break;
243
- // }
244
-
245
- // string certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate
246
-
247
- // // Export to a file, because the MSI API's require us to provide a file path on disk
248
- // string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate");
249
- // Directory.CreateDirectory(certPath);
250
- // certPath = Path.Combine(certPath, string.Concat(certificateId, ".cer"));
251
-
252
- // using (FileStream fs = File.Create(certPath))
253
- // {
254
- // int bytesRead;
255
- // byte[] buffer = new byte[1024 * 4];
256
-
257
- // while (0 != (bytesRead = digitalCertificateRecord.GetStream(2, buffer, buffer.Length)))
258
- // {
259
- // fs.Write(buffer, 0, bytesRead);
260
- // }
261
- // }
262
-
263
- // // Add it to our "add to MsiDigitalCertificate" table dictionary
264
- // Row digitalCertificateRow = digitalCertificateTable.CreateRow(null);
265
- // digitalCertificateRow[0] = certificateId;
266
-
267
- // // Now set the file path on disk where this binary stream will be picked up at import time
268
- // digitalCertificateRow[1] = string.Concat(certificateId, ".cer");
269
-
270
- // // Load the cert to get it's thumbprint
271
- // X509Certificate cert = X509Certificate.CreateFromCertFile(certPath);
272
- // X509Certificate2 cert2 = new X509Certificate2(cert);
273
-
274
- // certificates.Add(cert2.Thumbprint, certificateId);
275
- // }
276
- // }
277
- // }
278
- // }
279
-
280
- // using (View mediaView = database.OpenExecuteView("SELECT * FROM `Media`"))
281
- // {
282
- // while (true)
283
- // {
284
- // using (Record mediaRecord = mediaView.Fetch())
285
- // {
286
- // if (null == mediaRecord)
287
- // {
288
- // break;
289
- // }
290
-
291
- // X509Certificate2 cert2 = null;
292
- // Row digitalSignatureRow = null;
293
-
294
- // string cabName = mediaRecord.GetString(4); // get the name of the cab
295
- // // If there is no cabinet or it's an internal cab, skip it.
296
- // if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal))
297
- // {
298
- // continue;
299
- // }
300
-
301
- // string cabId = mediaRecord.GetString(1); // get the ID of the cab
302
- // string cabPath = Path.Combine(Path.GetDirectoryName(databaseFile), cabName);
303
-
304
- // // If the cabs aren't there, throw an error but continue to catch the other errors
305
- // if (!File.Exists(cabPath))
306
- // {
307
- // this.OnMessage(WixErrors.WixFileNotFound(cabPath));
308
- // continue;
309
- // }
310
-
311
- // try
312
- // {
313
- // // Get the certificate from the cab
314
- // X509Certificate signedFileCert = X509Certificate.CreateFromSignedFile(cabPath);
315
- // cert2 = new X509Certificate2(signedFileCert);
316
- // }
317
- // catch (System.Security.Cryptography.CryptographicException e)
318
- // {
319
- // uint HResult = unchecked((uint)Marshal.GetHRForException(e));
320
-
321
- // // If the file has no cert, continue, but flag that we found at least one so we can later give a warning
322
- // if (0x80092009 == HResult) // CRYPT_E_NO_MATCH
323
- // {
324
- // foundUnsignedExternals = true;
325
- // continue;
326
- // }
327
-
328
- // // todo: exactly which HRESULT corresponds to this issue?
329
- // // If it's one of these exact platforms, warn the user that it may be due to their OS.
330
- // if ((5 == Environment.OSVersion.Version.Major && 2 == Environment.OSVersion.Version.Minor) || // W2K3
331
- // (5 == Environment.OSVersion.Version.Major && 1 == Environment.OSVersion.Version.Minor)) // XP
332
- // {
333
- // this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFileDownlevelOS(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult)));
334
- // }
335
- // else // otherwise, generic error
336
- // {
337
- // this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFile(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult)));
338
- // }
339
- // }
340
-
341
- // // If we haven't added this cert to the MsiDigitalCertificate table, set it up to be added
342
- // if (!certificates.ContainsKey(cert2.Thumbprint))
343
- // {
344
- // // generate a stable identifier
345
- // string certificateGeneratedId = Common.GenerateIdentifier("cer", cert2.Thumbprint);
346
-
347
- // // Add it to our "add to MsiDigitalCertificate" table dictionary
348
- // Row digitalCertificateRow = digitalCertificateTable.CreateRow(null);
349
- // digitalCertificateRow[0] = certificateGeneratedId;
350
-
351
- // // Export to a file, because the MSI API's require us to provide a file path on disk
352
- // string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate");
353
- // Directory.CreateDirectory(certPath);
354
- // certPath = Path.Combine(certPath, string.Concat(cert2.Thumbprint, ".cer"));
355
- // File.Delete(certPath);
356
-
357
- // using (BinaryWriter writer = new BinaryWriter(File.Open(certPath, FileMode.Create)))
358
- // {
359
- // writer.Write(cert2.RawData);
360
- // writer.Close();
361
- // }
362
-
363
- // // Now set the file path on disk where this binary stream will be picked up at import time
364
- // digitalCertificateRow[1] = string.Concat(cert2.Thumbprint, ".cer");
365
-
366
- // certificates.Add(cert2.Thumbprint, certificateGeneratedId);
367
- // }
368
-
369
- // digitalSignatureRow = digitalSignatureTable.CreateRow(null);
370
-
371
- // digitalSignatureRow[0] = "Media";
372
- // digitalSignatureRow[1] = cabId;
373
- // digitalSignatureRow[2] = certificates[cert2.Thumbprint];
374
- // }
375
- // }
376
- // }
377
-
378
- // if (digitalCertificateTable.Rows.Count > 0)
379
- // {
380
- // database.ImportTable(codepage, digitalCertificateTable, this.TempFilesLocation, true);
381
- // shouldCommit = true;
382
- // }
383
-
384
- // if (digitalSignatureTable.Rows.Count > 0)
385
- // {
386
- // database.ImportTable(codepage, digitalSignatureTable, this.TempFilesLocation, true);
387
- // shouldCommit = true;
388
- // }
389
-
390
- // // TODO: if we created the table(s), then we should add the _Validation records for them.
391
-
392
- // certificates = null;
393
-
394
- // // If we did find external cabs but none of them were signed, give a warning
395
- // if (foundUnsignedExternals)
396
- // {
397
- // this.OnMessage(WixWarnings.ExternalCabsAreNotSigned(databaseFile));
398
- // }
399
-
400
- // if (shouldCommit)
401
- // {
402
- // database.Commit();
403
- // }
404
- //}
405
-
406
- //return shouldCommit;
407
- return false;
408
- }
409
-
410
- /// <summary>
411
- /// Cleans up the temp files used by the Inscriber.
412
- /// </summary>
413
- /// <returns>True if all files were deleted, false otherwise.</returns>
414
- public bool DeleteTempFiles()
415
- {
416
-#if REDO_IN_NETCORE
417
- if (null == this.tempFiles)
418
- {
419
- return true; // no work to do
420
- }
421
- else
422
- {
423
- bool deleted = Common.DeleteTempFiles(this.TempFilesLocation, this);
424
-
425
- if (deleted)
426
- {
427
- ((IDisposable)this.tempFiles).Dispose();
428
- this.tempFiles = null; // temp files have been deleted, no need to remember this now
429
- }
430
-
431
- return deleted;
432
- }
433
-#endif
434
- return true;
435
- }
436
- }
437
-}
src/WixToolset.Core/WixToolset.Core.csproj
+1
@@ -16,6 +16,7 @@
16
<ItemGroup>
17
<PackageReference Include="WixToolset.Data" Version="4.0.*" />
18
<PackageReference Include="WixToolset.Extensibility" Version="4.0.*" />
19
+ <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" />
20
</ItemGroup>
21
22
<!--