aboutsummaryrefslogtreecommitdiff
path: root/src/dtf/WixToolset.Dtf.WindowsInstaller/DatabaseTransform.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dtf/WixToolset.Dtf.WindowsInstaller/DatabaseTransform.cs278
1 files changed, 278 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.WindowsInstaller/DatabaseTransform.cs b/src/dtf/WixToolset.Dtf.WindowsInstaller/DatabaseTransform.cs
new file mode 100644
index 00000000..fa843012
--- /dev/null
+++ b/src/dtf/WixToolset.Dtf.WindowsInstaller/DatabaseTransform.cs
@@ -0,0 +1,278 @@
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
3namespace WixToolset.Dtf.WindowsInstaller
4{
5 using System;
6 using System.IO;
7 using System.Globalization;
8 using System.Diagnostics.CodeAnalysis;
9
10 public partial class Database
11 {
12 /// <summary>
13 /// Creates a transform that, when applied to the object database, results in the reference database.
14 /// </summary>
15 /// <param name="referenceDatabase">Database that does not include the changes</param>
16 /// <param name="transformFile">Name of the generated transform file, or null to only
17 /// check whether or not the two database are identical</param>
18 /// <returns>true if a transform is generated, or false if a transform is not generated
19 /// because there are no differences between the two databases.</returns>
20 /// <exception cref="InstallerException">the transform could not be generated</exception>
21 /// <exception cref="InvalidHandleException">a Database handle is invalid</exception>
22 /// <remarks><p>
23 /// A transform can add non-primary key columns to the end of a table. A transform cannot
24 /// be created that adds primary key columns to a table. A transform cannot be created that
25 /// changes the order, names, or definitions of columns.
26 /// </p><p>
27 /// If the transform is to be applied during an installation you must use the
28 /// <see cref="Database.CreateTransformSummaryInfo"/> method to populate the
29 /// summary information stream.
30 /// </p><p>
31 /// Win32 MSI API:
32 /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidatabasegeneratetransform.asp">MsiDatabaseGenerateTransform</a>
33 /// </p></remarks>
34 [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
35 public bool GenerateTransform(Database referenceDatabase, string transformFile)
36 {
37 if (referenceDatabase == null)
38 {
39 throw new ArgumentNullException("referenceDatabase");
40 }
41
42 if (String.IsNullOrEmpty(transformFile))
43 {
44 throw new ArgumentNullException("transformFile");
45 }
46
47 uint ret = NativeMethods.MsiDatabaseGenerateTransform((int) this.Handle, (int) referenceDatabase.Handle, transformFile, 0, 0);
48 if (ret == (uint) NativeMethods.Error.NO_DATA)
49 {
50 return false;
51 }
52 else if (ret != 0)
53 {
54 throw InstallerException.ExceptionFromReturnCode(ret);
55 }
56 return true;
57 }
58
59 /// <summary>
60 /// Creates and populates the summary information stream of an existing transform file, and
61 /// fills in the properties with the base and reference ProductCode and ProductVersion.
62 /// </summary>
63 /// <param name="referenceDatabase">Database that does not include the changes</param>
64 /// <param name="transformFile">Name of the generated transform file</param>
65 /// <param name="errors">Error conditions that should be suppressed
66 /// when the transform is applied</param>
67 /// <param name="validations">Defines which properties should be validated
68 /// to verify that this transform can be applied to a database.</param>
69 /// <exception cref="InstallerException">the transform summary info could not be
70 /// generated</exception>
71 /// <exception cref="InvalidHandleException">a Database handle is invalid</exception>
72 /// <remarks><p>
73 /// Win32 MSI API:
74 /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msicreatetransformsummaryinfo.asp">MsiCreateTransformSummaryInfo</a>
75 /// </p></remarks>
76 [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
77 public void CreateTransformSummaryInfo(
78 Database referenceDatabase,
79 string transformFile,
80 TransformErrors errors,
81 TransformValidations validations)
82 {
83 if (referenceDatabase == null)
84 {
85 throw new ArgumentNullException("referenceDatabase");
86 }
87
88 if (String.IsNullOrEmpty(transformFile))
89 {
90 throw new ArgumentNullException("transformFile");
91 }
92
93 uint ret = NativeMethods.MsiCreateTransformSummaryInfo(
94 (int) this.Handle,
95 (int) referenceDatabase.Handle,
96 transformFile,
97 (int) errors,
98 (int) validations);
99 if (ret != 0)
100 {
101 throw InstallerException.ExceptionFromReturnCode(ret);
102 }
103 }
104
105 /// <summary>
106 /// Apply a transform to the database, recording the changes in the "_TransformView" table.
107 /// </summary>
108 /// <param name="transformFile">Path to the transform file</param>
109 /// <exception cref="InstallerException">the transform could not be applied</exception>
110 /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
111 /// <remarks><p>
112 /// Win32 MSI API:
113 /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidatabaseapplytransform.asp">MsiDatabaseApplyTransform</a>
114 /// </p></remarks>
115 public void ViewTransform(string transformFile)
116 {
117 TransformErrors transformErrors =
118 TransformErrors.AddExistingRow |
119 TransformErrors.DelMissingRow |
120 TransformErrors.AddExistingTable |
121 TransformErrors.DelMissingTable |
122 TransformErrors.UpdateMissingRow |
123 TransformErrors.ChangeCodePage |
124 TransformErrors.ViewTransform;
125 this.ApplyTransform(transformFile, transformErrors);
126 }
127
128 /// <summary>
129 /// Apply a transform to the database, suppressing any error conditions
130 /// specified by the transform's summary information.
131 /// </summary>
132 /// <param name="transformFile">Path to the transform file</param>
133 /// <exception cref="InstallerException">the transform could not be applied</exception>
134 /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
135 /// <remarks><p>
136 /// Win32 MSI API:
137 /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidatabaseapplytransform.asp">MsiDatabaseApplyTransform</a>
138 /// </p></remarks>
139 public void ApplyTransform(string transformFile)
140 {
141 if (String.IsNullOrEmpty(transformFile))
142 {
143 throw new ArgumentNullException("transformFile");
144 }
145
146 TransformErrors errorConditionsToSuppress;
147 using (SummaryInfo transformSummInfo = new SummaryInfo(transformFile, false))
148 {
149 int errorConditions = transformSummInfo.CharacterCount & 0xFFFF;
150 errorConditionsToSuppress = (TransformErrors) errorConditions;
151 }
152 this.ApplyTransform(transformFile, errorConditionsToSuppress);
153 }
154
155 /// <summary>
156 /// Apply a transform to the database, specifying error conditions to suppress.
157 /// </summary>
158 /// <param name="transformFile">Path to the transform file</param>
159 /// <param name="errorConditionsToSuppress">Error conditions that are to be suppressed</param>
160 /// <exception cref="InstallerException">the transform could not be applied</exception>
161 /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
162 /// <remarks><p>
163 /// Win32 MSI API:
164 /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidatabaseapplytransform.asp">MsiDatabaseApplyTransform</a>
165 /// </p></remarks>
166 public void ApplyTransform(string transformFile, TransformErrors errorConditionsToSuppress)
167 {
168 if (String.IsNullOrEmpty(transformFile))
169 {
170 throw new ArgumentNullException("transformFile");
171 }
172
173 uint ret = NativeMethods.MsiDatabaseApplyTransform((int) this.Handle, transformFile, (int) errorConditionsToSuppress);
174 if (ret != 0)
175 {
176 throw InstallerException.ExceptionFromReturnCode(ret);
177 }
178 }
179
180 /// <summary>
181 /// Checks whether a transform is valid for this Database, according to its validation data and flags.
182 /// </summary>
183 /// <param name="transformFile">Path to the transform file</param>
184 /// <returns>true if the transform can be validly applied to this Database; false otherwise</returns>
185 /// <exception cref="InstallerException">the transform could not be applied</exception>
186 /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
187 public bool IsTransformValid(string transformFile)
188 {
189 if (String.IsNullOrEmpty(transformFile))
190 {
191 throw new ArgumentNullException("transformFile");
192 }
193
194 using (SummaryInfo transformSummInfo = new SummaryInfo(transformFile, false))
195 {
196 return this.IsTransformValid(transformSummInfo);
197 }
198 }
199
200 /// <summary>
201 /// Checks whether a transform is valid for this Database, according to its SummaryInfo data.
202 /// </summary>
203 /// <param name="transformSummaryInfo">SummaryInfo data of a transform file</param>
204 /// <returns>true if the transform can be validly applied to this Database; false otherwise</returns>
205 /// <exception cref="InstallerException">error processing summary info</exception>
206 /// <exception cref="InvalidHandleException">the Database or SummaryInfo handle is invalid</exception>
207 public bool IsTransformValid(SummaryInfo transformSummaryInfo)
208 {
209 if (transformSummaryInfo == null)
210 {
211 throw new ArgumentNullException("transformSummaryInfo");
212 }
213
214 string[] rev = transformSummaryInfo.RevisionNumber.Split(new char[] { ';' }, 3);
215 string targetProductCode = rev[0].Substring(0, 38);
216 string targetProductVersion = rev[0].Substring(38);
217 string upgradeCode = rev[2];
218
219 string[] templ = transformSummaryInfo.Template.Split(new char[] { ';' }, 2);
220 int targetProductLanguage = 0;
221 if (templ.Length >= 2 && templ[1].Length > 0)
222 {
223 targetProductLanguage = Int32.Parse(templ[1], CultureInfo.InvariantCulture.NumberFormat);
224 }
225
226 int flags = transformSummaryInfo.CharacterCount;
227 int validateFlags = flags >> 16;
228
229 string thisProductCode = this.ExecutePropertyQuery("ProductCode");
230 string thisProductVersion = this.ExecutePropertyQuery("ProductVersion");
231 string thisUpgradeCode = this.ExecutePropertyQuery("UpgradeCode");
232 string thisProductLang = this.ExecutePropertyQuery("ProductLanguage");
233 int thisProductLanguage = 0;
234 if (!String.IsNullOrEmpty(thisProductLang))
235 {
236 thisProductLanguage = Int32.Parse(thisProductLang, CultureInfo.InvariantCulture.NumberFormat);
237 }
238
239 if ((validateFlags & (int) TransformValidations.Product) != 0 &&
240 thisProductCode != targetProductCode)
241 {
242 return false;
243 }
244
245 if ((validateFlags & (int) TransformValidations.UpgradeCode) != 0 &&
246 thisUpgradeCode != upgradeCode)
247 {
248 return false;
249 }
250
251 if ((validateFlags & (int) TransformValidations.Language) != 0 &&
252 targetProductLanguage != 0 && thisProductLanguage != targetProductLanguage)
253 {
254 return false;
255 }
256
257 Version thisProductVer = new Version(thisProductVersion);
258 Version targetProductVer = new Version(targetProductVersion);
259 if ((validateFlags & (int) TransformValidations.UpdateVersion) != 0)
260 {
261 if (thisProductVer.Major != targetProductVer.Major) return false;
262 if (thisProductVer.Minor != targetProductVer.Minor) return false;
263 if (thisProductVer.Build != targetProductVer.Build) return false;
264 }
265 else if ((validateFlags & (int) TransformValidations.MinorVersion) != 0)
266 {
267 if (thisProductVer.Major != targetProductVer.Major) return false;
268 if (thisProductVer.Minor != targetProductVer.Minor) return false;
269 }
270 else if ((validateFlags & (int) TransformValidations.MajorVersion) != 0)
271 {
272 if (thisProductVer.Major != targetProductVer.Major) return false;
273 }
274
275 return true;
276 }
277 }
278}