diff options
Diffstat (limited to 'src')
12 files changed, 105 insertions, 513 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 32da410f..22858d1f 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
@@ -505,7 +505,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
505 | // necessary. | 505 | // necessary. |
506 | foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) | 506 | foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) |
507 | { | 507 | { |
508 | var sequenceTableName = sequence.ToString(); | 508 | var sequenceTableName = (sequence == SequenceTable.AdvertiseExecuteSequence) ? "AdvtExecuteSequence" : sequence.ToString(); |
509 | var sequenceTable = output.Tables[sequenceTableName]; | 509 | var sequenceTable = output.Tables[sequenceTableName]; |
510 | 510 | ||
511 | if (null == sequenceTable) | 511 | if (null == sequenceTable) |
@@ -519,8 +519,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
519 | } | 519 | } |
520 | } | 520 | } |
521 | 521 | ||
522 | var command = new MergeModulesCommand(); | 522 | var command = new MergeModulesCommand(this.Messaging); |
523 | command.FileFacades = fileFacades; | 523 | command.FileFacades = fileFacades; |
524 | command.IntermediateFolder = this.IntermediateFolder; | ||
524 | command.Output = output; | 525 | command.Output = output; |
525 | command.OutputPath = this.OutputPath; | 526 | command.OutputPath = this.OutputPath; |
526 | command.SuppressedTableNames = suppressedTableNames; | 527 | command.SuppressedTableNames = suppressedTableNames; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs index 0cc5996a..9a609463 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ConfigurationCallback.cs | |||
@@ -5,6 +5,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
5 | using System; | 5 | using System; |
6 | using System.Collections; | 6 | using System.Collections; |
7 | using System.Globalization; | 7 | using System.Globalization; |
8 | using WixToolset.Core.Native; | ||
8 | using WixToolset.Core.WindowsInstaller.Msi; | 9 | using WixToolset.Core.WindowsInstaller.Msi; |
9 | 10 | ||
10 | /// <summary> | 11 | /// <summary> |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs index 49b6a6f8..62f7fce3 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs | |||
@@ -48,7 +48,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
48 | { | 48 | { |
49 | var mergeModulesFileFacades = new List<FileFacade>(); | 49 | var mergeModulesFileFacades = new List<FileFacade>(); |
50 | 50 | ||
51 | var merge = MsmInterop.GetMsmMerge(); | 51 | var interop = new MsmInterop(); |
52 | var merge = interop.GetMsmMerge(); | ||
52 | 53 | ||
53 | // Index all of the file rows to be able to detect collisions with files in the Merge Modules. | 54 | // Index all of the file rows to be able to detect collisions with files in the Merge Modules. |
54 | // It may seem a bit expensive to build up this index solely for the purpose of checking collisions | 55 | // It may seem a bit expensive to build up this index solely for the purpose of checking collisions |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs index b90aecd1..cd6170d0 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs | |||
@@ -9,9 +9,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
9 | using System.Runtime.InteropServices; | 9 | using System.Runtime.InteropServices; |
10 | using System.Text; | 10 | using System.Text; |
11 | using WixToolset.Core.Bind; | 11 | using WixToolset.Core.Bind; |
12 | using WixToolset.Core.Native; | ||
12 | using WixToolset.Core.WindowsInstaller.Msi; | 13 | using WixToolset.Core.WindowsInstaller.Msi; |
13 | using WixToolset.Data; | 14 | using WixToolset.Data; |
14 | using WixToolset.Data.Tuples; | ||
15 | using WixToolset.Data.WindowsInstaller; | 15 | using WixToolset.Data.WindowsInstaller; |
16 | using WixToolset.Data.WindowsInstaller.Rows; | 16 | using WixToolset.Data.WindowsInstaller.Rows; |
17 | using WixToolset.Extensibility.Services; | 17 | using WixToolset.Extensibility.Services; |
@@ -21,6 +21,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
21 | /// </summary> | 21 | /// </summary> |
22 | internal class MergeModulesCommand | 22 | internal class MergeModulesCommand |
23 | { | 23 | { |
24 | public MergeModulesCommand(IMessaging messaging) | ||
25 | { | ||
26 | this.Messaging = messaging; | ||
27 | } | ||
28 | |||
24 | public IEnumerable<FileFacade> FileFacades { private get; set; } | 29 | public IEnumerable<FileFacade> FileFacades { private get; set; } |
25 | 30 | ||
26 | public IMessaging Messaging { private get; set; } | 31 | public IMessaging Messaging { private get; set; } |
@@ -51,7 +56,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
51 | string logPath = null; | 56 | string logPath = null; |
52 | try | 57 | try |
53 | { | 58 | { |
54 | merge = MsmInterop.GetMsmMerge(); | 59 | var interop = new MsmInterop(); |
60 | merge = interop.GetMsmMerge(); | ||
55 | 61 | ||
56 | logPath = Path.Combine(this.IntermediateFolder, "merge.log"); | 62 | logPath = Path.Combine(this.IntermediateFolder, "merge.log"); |
57 | merge.OpenLog(logPath); | 63 | merge.OpenLog(logPath); |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs index ae872f45..5d18a230 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs | |||
@@ -74,7 +74,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
74 | 74 | ||
75 | patchGroup.Add(facade); | 75 | patchGroup.Add(facade); |
76 | } | 76 | } |
77 | else | 77 | else if (!facade.FromModule) |
78 | { | 78 | { |
79 | var fileRow = fileRows.Get(facade.Id); | 79 | var fileRow = fileRows.Get(facade.Id); |
80 | fileRow.Sequence = ++lastSequence; | 80 | fileRow.Sequence = ++lastSequence; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Msi/MsmInterop.cs b/src/WixToolset.Core.WindowsInstaller/Msi/MsmInterop.cs deleted file mode 100644 index 970d5aaa..00000000 --- a/src/WixToolset.Core.WindowsInstaller/Msi/MsmInterop.cs +++ /dev/null | |||
@@ -1,505 +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.Runtime.InteropServices; | ||
7 | |||
8 | /// <summary> | ||
9 | /// Errors returned by merge operations. | ||
10 | /// </summary> | ||
11 | [Guid("0ADDA825-2C26-11D2-AD65-00A0C9AF11A6")] | ||
12 | public enum MsmErrorType | ||
13 | { | ||
14 | /// <summary> | ||
15 | /// A request was made to open a module with a language not supported by the module. | ||
16 | /// No more general language is supported by the module. | ||
17 | /// Adds msmErrorLanguageUnsupported to the Type property and the requested language | ||
18 | /// to the Language Property (Error Object). All Error object properties are empty. | ||
19 | /// The OpenModule function returns ERROR_INSTALL_LANGUAGE_UNSUPPORTED (as HRESULT). | ||
20 | /// </summary> | ||
21 | msmErrorLanguageUnsupported = 1, | ||
22 | |||
23 | /// <summary> | ||
24 | /// A request was made to open a module with a supported language but the module has | ||
25 | /// an invalid language transform. Adds msmErrorLanguageFailed to the Type property | ||
26 | /// and the applied transform's language to the Language Property of the Error object. | ||
27 | /// This may not be the requested language if a more general language was used. | ||
28 | /// All other properties of the Error object are empty. The OpenModule function | ||
29 | /// returns ERROR_INSTALL_LANGUAGE_UNSUPPORTED (as HRESULT). | ||
30 | /// </summary> | ||
31 | msmErrorLanguageFailed = 2, | ||
32 | |||
33 | /// <summary> | ||
34 | /// The module cannot be merged because it excludes, or is excluded by, another module | ||
35 | /// in the database. Adds msmErrorExclusion to the Type property of the Error object. | ||
36 | /// The ModuleKeys property or DatabaseKeys property contains the primary keys of the | ||
37 | /// excluded module's row in the ModuleExclusion table. If an existing module excludes | ||
38 | /// the module being merged, the excluded module's ModuleSignature information is added | ||
39 | /// to ModuleKeys. If the module being merged excludes an existing module, DatabaseKeys | ||
40 | /// contains the excluded module's ModuleSignature information. All other properties | ||
41 | /// are empty (or -1). | ||
42 | /// </summary> | ||
43 | msmErrorExclusion = 3, | ||
44 | |||
45 | /// <summary> | ||
46 | /// Merge conflict during merge. The value of the Type property is set to | ||
47 | /// msmErrorTableMerge. The DatabaseTable property and DatabaseKeys property contain | ||
48 | /// the table name and primary keys of the conflicting row in the database. The | ||
49 | /// ModuleTable property and ModuleKeys property contain the table name and primary keys | ||
50 | /// of the conflicting row in the module. The ModuleTable and ModuleKeys entries may be | ||
51 | /// null if the row does not exist in the database. For example, if the conflict is in a | ||
52 | /// generated FeatureComponents table entry. On Windows Installer version 2.0, when | ||
53 | /// merging a configurable merge module, configuration may cause these properties to | ||
54 | /// refer to rows that do not exist in the module. | ||
55 | /// </summary> | ||
56 | msmErrorTableMerge = 4, | ||
57 | |||
58 | /// <summary> | ||
59 | /// There was a problem resequencing a sequence table to contain the necessary merged | ||
60 | /// actions. The Type property is set to msmErrorResequenceMerge. The DatabaseTable | ||
61 | /// and DatabaseKeys properties contain the sequence table name and primary keys | ||
62 | /// (action name) of the conflicting row. The ModuleTable and ModuleKeys properties | ||
63 | /// contain the sequence table name and primary key (action name) of the conflicting row. | ||
64 | /// On Windows Installer version 2.0, when merging a configurable merge module, | ||
65 | /// configuration may cause these properties to refer to rows that do not exist in the module. | ||
66 | /// </summary> | ||
67 | msmErrorResequenceMerge = 5, | ||
68 | |||
69 | /// <summary> | ||
70 | /// Not used. | ||
71 | /// </summary> | ||
72 | msmErrorFileCreate = 6, | ||
73 | |||
74 | /// <summary> | ||
75 | /// There was a problem creating a directory to extract a file to disk. The Path property | ||
76 | /// contains the directory that could not be created. All other properties are empty or -1. | ||
77 | /// Not available with Windows Installer version 1.0. | ||
78 | /// </summary> | ||
79 | msmErrorDirCreate = 7, | ||
80 | |||
81 | /// <summary> | ||
82 | /// A feature name is required to complete the merge, but no feature name was provided. | ||
83 | /// The Type property is set to msmErrorFeatureRequired. The DatabaseTable and DatabaseKeys | ||
84 | /// contain the table name and primary keys of the conflicting row. The ModuleTable and | ||
85 | /// ModuleKeys properties contain the table name and primary keys of the row cannot be merged. | ||
86 | /// On Windows Installer version 2.0, when merging a configurable merge module, configuration | ||
87 | /// may cause these properties to refer to rows that do not exist in the module. | ||
88 | /// If the failure is in a generated FeatureComponents table, the DatabaseTable and | ||
89 | /// DatabaseKeys properties are empty and the ModuleTable and ModuleKeys properties refer to | ||
90 | /// the row in the Component table causing the failure. | ||
91 | /// </summary> | ||
92 | msmErrorFeatureRequired = 8, | ||
93 | |||
94 | /// <summary> | ||
95 | /// Available with Window Installer version 2.0. Substitution of a Null value into a | ||
96 | /// non-nullable column. This enters msmErrorBadNullSubstitution in the Type property and | ||
97 | /// enters "ModuleSubstitution" and the keys from the ModuleSubstitution table for this row | ||
98 | /// into the ModuleTable property and ModuleKeys property. All other properties of the Error | ||
99 | /// object are set to an empty string or -1. This error causes the immediate failure of the | ||
100 | /// merge and the MergeEx function to return E_FAIL. | ||
101 | /// </summary> | ||
102 | msmErrorBadNullSubstitution = 9, | ||
103 | |||
104 | /// <summary> | ||
105 | /// Available with Window Installer version 2.0. Substitution of Text Format Type or Integer | ||
106 | /// Format Type into a Binary Type data column. This type of error returns | ||
107 | /// msmErrorBadSubstitutionType in the Type property and enters "ModuleSubstitution" and the | ||
108 | /// keys from the ModuleSubstitution table for this row into the ModuleTable property. | ||
109 | /// All other properties of the Error object are set to an empty string or -1. This error | ||
110 | /// causes the immediate failure of the merge and the MergeEx function to return E_FAIL. | ||
111 | /// </summary> | ||
112 | msmErrorBadSubstitutionType = 10, | ||
113 | |||
114 | /// <summary> | ||
115 | /// Available with Window Installer Version 2.0. A row in the ModuleSubstitution table | ||
116 | /// references a configuration item not defined in the ModuleConfiguration table. | ||
117 | /// This type of error returns msmErrorMissingConfigItem in the Type property and enters | ||
118 | /// "ModuleSubstitution" and the keys from the ModuleSubstitution table for this row into | ||
119 | /// the ModuleTable property. All other properties of the Error object are set to an empty | ||
120 | /// string or -1. This error causes the immediate failure of the merge and the MergeEx | ||
121 | /// function to return E_FAIL. | ||
122 | /// </summary> | ||
123 | msmErrorMissingConfigItem = 11, | ||
124 | |||
125 | /// <summary> | ||
126 | /// Available with Window Installer version 2.0. The authoring tool has returned a Null | ||
127 | /// value for an item marked with the msmConfigItemNonNullable attribute. An error of this | ||
128 | /// type returns msmErrorBadNullResponse in the Type property and enters "ModuleSubstitution" | ||
129 | /// and the keys from the ModuleSubstitution table for for the item into the ModuleTable property. | ||
130 | /// All other properties of the Error object are set to an empty string or -1. This error | ||
131 | /// causes the immediate failure of the merge and the MergeEx function to return E_FAIL. | ||
132 | /// </summary> | ||
133 | msmErrorBadNullResponse = 12, | ||
134 | |||
135 | /// <summary> | ||
136 | /// Available with Window Installer version 2.0. The authoring tool returned a failure code | ||
137 | /// (not S_OK or S_FALSE) when asked for data. An error of this type will return | ||
138 | /// msmErrorDataRequestFailed in the Type property and enters "ModuleSubstitution" | ||
139 | /// and the keys from the ModuleSubstitution table for the item into the ModuleTable property. | ||
140 | /// All other properties of the Error object are set to an empty string or -1. This error | ||
141 | /// causes the immediate failure of the merge and the MergeEx function to return E_FAIL. | ||
142 | /// </summary> | ||
143 | msmErrorDataRequestFailed = 13, | ||
144 | |||
145 | /// <summary> | ||
146 | /// Available with Windows Installer 2.0 and later versions. Indicates that an attempt was | ||
147 | /// made to merge a 64-bit module into a package that was not a 64-bit package. An error of | ||
148 | /// this type returns msmErrorPlatformMismatch in the Type property. All other properties of | ||
149 | /// the error object are set to an empty string or -1. This error causes the immediate failure | ||
150 | /// of the merge and causes the Merge function or MergeEx function to return E_FAIL. | ||
151 | /// </summary> | ||
152 | msmErrorPlatformMismatch = 14, | ||
153 | } | ||
154 | |||
155 | /// <summary> | ||
156 | /// IMsmMerge2 interface. | ||
157 | /// </summary> | ||
158 | [ComImport, Guid("351A72AB-21CB-47ab-B7AA-C4D7B02EA305")] | ||
159 | public interface IMsmMerge2 | ||
160 | { | ||
161 | /// <summary> | ||
162 | /// The OpenDatabase method of the Merge object opens a Windows Installer installation | ||
163 | /// database, located at a specified path, that is to be merged with a module. | ||
164 | /// </summary> | ||
165 | /// <param name="path">Path to the database being opened.</param> | ||
166 | void OpenDatabase(string path); | ||
167 | |||
168 | /// <summary> | ||
169 | /// The OpenModule method of the Merge object opens a Windows Installer merge module | ||
170 | /// in read-only mode. A module must be opened before it can be merged with an installation database. | ||
171 | /// </summary> | ||
172 | /// <param name="fileName">Fully qualified file name pointing to a merge module.</param> | ||
173 | /// <param name="language">A valid language identifier (LANGID).</param> | ||
174 | void OpenModule(string fileName, short language); | ||
175 | |||
176 | /// <summary> | ||
177 | /// The CloseDatabase method of the Merge object closes the currently open Windows Installer database. | ||
178 | /// </summary> | ||
179 | /// <param name="commit">true if changes should be saved, false otherwise.</param> | ||
180 | void CloseDatabase(bool commit); | ||
181 | |||
182 | /// <summary> | ||
183 | /// The CloseModule method of the Merge object closes the currently open Windows Installer merge module. | ||
184 | /// </summary> | ||
185 | void CloseModule(); | ||
186 | |||
187 | /// <summary> | ||
188 | /// The OpenLog method of the Merge object opens a log file that receives progress and error messages. | ||
189 | /// If the log file already exists, the installer appends new messages. If the log file does not exist, | ||
190 | /// the installer creates a log file. | ||
191 | /// </summary> | ||
192 | /// <param name="fileName">Fully qualified filename pointing to a file to open or create.</param> | ||
193 | void OpenLog(string fileName); | ||
194 | |||
195 | /// <summary> | ||
196 | /// The CloseLog method of the Merge object closes the current log file. | ||
197 | /// </summary> | ||
198 | void CloseLog(); | ||
199 | |||
200 | /// <summary> | ||
201 | /// The Log method of the Merge object writes a text string to the currently open log file. | ||
202 | /// </summary> | ||
203 | /// <param name="message">The text string to display.</param> | ||
204 | void Log(string message); | ||
205 | |||
206 | /// <summary> | ||
207 | /// Gets the errors from the last merge operation. | ||
208 | /// </summary> | ||
209 | /// <value>The errors from the last merge operation.</value> | ||
210 | IMsmErrors Errors | ||
211 | { | ||
212 | get; | ||
213 | } | ||
214 | |||
215 | /// <summary> | ||
216 | /// Gets a collection of Dependency objects that enumerates a set of unsatisfied dependencies for the current database. | ||
217 | /// </summary> | ||
218 | /// <value>A collection of Dependency objects that enumerates a set of unsatisfied dependencies for the current database.</value> | ||
219 | object Dependencies | ||
220 | { | ||
221 | get; | ||
222 | } | ||
223 | |||
224 | /// <summary> | ||
225 | /// The Merge method of the Merge object executes a merge of the current database and current | ||
226 | /// module. The merge attaches the components in the module to the feature identified by Feature. | ||
227 | /// The root of the module's directory tree is redirected to the location given by RedirectDir. | ||
228 | /// </summary> | ||
229 | /// <param name="feature">The name of a feature in the database.</param> | ||
230 | /// <param name="redirectDir">The key of an entry in the Directory table of the database. | ||
231 | /// This parameter may be NULL or an empty string.</param> | ||
232 | void Merge(string feature, string redirectDir); | ||
233 | |||
234 | /// <summary> | ||
235 | /// The Connect method of the Merge object connects a module to an additional feature. | ||
236 | /// The module must have already been merged into the database or will be merged into the database. | ||
237 | /// The feature must exist before calling this function. | ||
238 | /// </summary> | ||
239 | /// <param name="feature">The name of a feature already existing in the database.</param> | ||
240 | void Connect(string feature); | ||
241 | |||
242 | /// <summary> | ||
243 | /// The ExtractCAB method of the Merge object extracts the embedded .cab file from a module and | ||
244 | /// saves it as the specified file. The installer creates this file if it does not already exist | ||
245 | /// and overwritten if it does exist. | ||
246 | /// </summary> | ||
247 | /// <param name="fileName">The fully qualified destination file.</param> | ||
248 | void ExtractCAB(string fileName); | ||
249 | |||
250 | /// <summary> | ||
251 | /// The ExtractFiles method of the Merge object extracts the embedded .cab file from a module | ||
252 | /// and then writes those files to the destination directory. | ||
253 | /// </summary> | ||
254 | /// <param name="path">The fully qualified destination directory.</param> | ||
255 | void ExtractFiles(string path); | ||
256 | |||
257 | /// <summary> | ||
258 | /// The MergeEx method of the Merge object is equivalent to the Merge function, except that it | ||
259 | /// takes an extra argument. The Merge method executes a merge of the current database and | ||
260 | /// current module. The merge attaches the components in the module to the feature identified | ||
261 | /// by Feature. The root of the module's directory tree is redirected to the location given by RedirectDir. | ||
262 | /// </summary> | ||
263 | /// <param name="feature">The name of a feature in the database.</param> | ||
264 | /// <param name="redirectDir">The key of an entry in the Directory table of the database. This parameter may | ||
265 | /// be NULL or an empty string.</param> | ||
266 | /// <param name="configuration">The pConfiguration argument is an interface implemented by the client. The argument may | ||
267 | /// be NULL. The presence of this argument indicates that the client is capable of supporting the configuration | ||
268 | /// functionality, but does not obligate the client to provide configuration data for any specific configurable item.</param> | ||
269 | void MergeEx(string feature, string redirectDir, IMsmConfigureModule configuration); | ||
270 | |||
271 | /// <summary> | ||
272 | /// The ExtractFilesEx method of the Merge object extracts the embedded .cab file from a module and | ||
273 | /// then writes those files to the destination directory. | ||
274 | /// </summary> | ||
275 | /// <param name="path">The fully qualified destination directory.</param> | ||
276 | /// <param name="longFileNames">Set to specify using long file names for path segments and final file names.</param> | ||
277 | /// <param name="filePaths">This is a list of fully-qualified paths for the files that were successfully extracted. | ||
278 | /// The list is empty if no files can be extracted. This argument may be null. No list is provided if pFilePaths is null.</param> | ||
279 | void ExtractFilesEx(string path, bool longFileNames, ref IntPtr filePaths); | ||
280 | |||
281 | /// <summary> | ||
282 | /// Gets a collection ConfigurableItem objects, each of which represents a single row from the ModuleConfiguration table. | ||
283 | /// </summary> | ||
284 | /// <value>A collection ConfigurableItem objects, each of which represents a single row from the ModuleConfiguration table.</value> | ||
285 | /// <remarks>Semantically, each interface in the enumerator represents an item that can be configured by the module consumer. | ||
286 | /// The collection is a read-only collection and implements the standard read-only collection interfaces of Item(), Count() and _NewEnum(). | ||
287 | /// The IEnumMsmConfigItems enumerator implements Next(), Skip(), Reset(), and Clone() with the standard semantics.</remarks> | ||
288 | object ConfigurableItems | ||
289 | { | ||
290 | get; | ||
291 | } | ||
292 | |||
293 | /// <summary> | ||
294 | /// The CreateSourceImage method of the Merge object allows the client to extract the files from a module to | ||
295 | /// a source image on disk after a merge, taking into account changes to the module that might have been made | ||
296 | /// during module configuration. The list of files to be extracted is taken from the file table of the module | ||
297 | /// during the merge process. The list of files consists of every file successfully copied from the file table | ||
298 | /// of the module to the target database. File table entries that were not copied due to primary key conflicts | ||
299 | /// with existing rows in the database are not a part of this list. At image creation time, the directory for | ||
300 | /// each of these files comes from the open (post-merge) database. The path specified in the Path parameter is | ||
301 | /// the root of the source image for the install. fLongFileNames determines whether or not long file names are | ||
302 | /// used for both path segments and final file names. The function fails if no database is open, no module is | ||
303 | /// open, or no merge has been performed. | ||
304 | /// </summary> | ||
305 | /// <param name="path">The path of the root of the source image for the install.</param> | ||
306 | /// <param name="longFileNames">Determines whether or not long file names are used for both path segments and final file names. </param> | ||
307 | /// <param name="filePaths">This is a list of fully-qualified paths for the files that were successfully extracted. | ||
308 | /// The list is empty if no files can be extracted. This argument may be null. No list is provided if pFilePaths is null.</param> | ||
309 | void CreateSourceImage(string path, bool longFileNames, ref IntPtr filePaths); | ||
310 | |||
311 | /// <summary> | ||
312 | /// The get_ModuleFiles function implements the ModuleFiles property of the GetFiles object. This function | ||
313 | /// returns the primary keys in the File table of the currently open module. The primary keys are returned | ||
314 | /// as a collection of strings. The module must be opened by a call to the OpenModule function before calling get_ModuleFiles. | ||
315 | /// </summary> | ||
316 | IMsmStrings ModuleFiles | ||
317 | { | ||
318 | get; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | /// <summary> | ||
323 | /// Collection of merge errors. | ||
324 | /// </summary> | ||
325 | [ComImport, Guid("0ADDA82A-2C26-11D2-AD65-00A0C9AF11A6")] | ||
326 | public interface IMsmErrors | ||
327 | { | ||
328 | /// <summary> | ||
329 | /// Gets the IMsmError at the specified index. | ||
330 | /// </summary> | ||
331 | /// <param name="index">The one-based index of the IMsmError to get.</param> | ||
332 | IMsmError this[int index] | ||
333 | { | ||
334 | get; | ||
335 | } | ||
336 | |||
337 | /// <summary> | ||
338 | /// Gets the count of IMsmErrors in this collection. | ||
339 | /// </summary> | ||
340 | /// <value>The count of IMsmErrors in this collection.</value> | ||
341 | int Count | ||
342 | { | ||
343 | get; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /// <summary> | ||
348 | /// A merge error. | ||
349 | /// </summary> | ||
350 | [ComImport, Guid("0ADDA828-2C26-11D2-AD65-00A0C9AF11A6")] | ||
351 | public interface IMsmError | ||
352 | { | ||
353 | /// <summary> | ||
354 | /// Gets the type of merge error. | ||
355 | /// </summary> | ||
356 | /// <value>The type of merge error.</value> | ||
357 | MsmErrorType Type | ||
358 | { | ||
359 | get; | ||
360 | } | ||
361 | |||
362 | /// <summary> | ||
363 | /// Gets the path information from the merge error. | ||
364 | /// </summary> | ||
365 | /// <value>The path information from the merge error.</value> | ||
366 | string Path | ||
367 | { | ||
368 | get; | ||
369 | } | ||
370 | |||
371 | /// <summary> | ||
372 | /// Gets the language information from the merge error. | ||
373 | /// </summary> | ||
374 | /// <value>The language information from the merge error.</value> | ||
375 | short Language | ||
376 | { | ||
377 | get; | ||
378 | } | ||
379 | |||
380 | /// <summary> | ||
381 | /// Gets the database table from the merge error. | ||
382 | /// </summary> | ||
383 | /// <value>The database table from the merge error.</value> | ||
384 | string DatabaseTable | ||
385 | { | ||
386 | get; | ||
387 | } | ||
388 | |||
389 | /// <summary> | ||
390 | /// Gets the collection of database keys from the merge error. | ||
391 | /// </summary> | ||
392 | /// <value>The collection of database keys from the merge error.</value> | ||
393 | IMsmStrings DatabaseKeys | ||
394 | { | ||
395 | get; | ||
396 | } | ||
397 | |||
398 | /// <summary> | ||
399 | /// Gets the module table from the merge error. | ||
400 | /// </summary> | ||
401 | /// <value>The module table from the merge error.</value> | ||
402 | string ModuleTable | ||
403 | { | ||
404 | get; | ||
405 | } | ||
406 | |||
407 | /// <summary> | ||
408 | /// Gets the collection of module keys from the merge error. | ||
409 | /// </summary> | ||
410 | /// <value>The collection of module keys from the merge error.</value> | ||
411 | IMsmStrings ModuleKeys | ||
412 | { | ||
413 | get; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | /// <summary> | ||
418 | /// A collection of strings. | ||
419 | /// </summary> | ||
420 | [ComImport, Guid("0ADDA827-2C26-11D2-AD65-00A0C9AF11A6")] | ||
421 | public interface IMsmStrings | ||
422 | { | ||
423 | /// <summary> | ||
424 | /// Gets the string at the specified index. | ||
425 | /// </summary> | ||
426 | /// <param name="index">The one-based index of the string to get.</param> | ||
427 | string this[int index] | ||
428 | { | ||
429 | get; | ||
430 | } | ||
431 | |||
432 | /// <summary> | ||
433 | /// Gets the count of strings in this collection. | ||
434 | /// </summary> | ||
435 | /// <value>The count of strings in this collection.</value> | ||
436 | int Count | ||
437 | { | ||
438 | get; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | /// <summary> | ||
443 | /// Callback for configurable merge modules. | ||
444 | /// </summary> | ||
445 | [ComImport, Guid("AC013209-18A7-4851-8A21-2353443D70A0"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] | ||
446 | public interface IMsmConfigureModule | ||
447 | { | ||
448 | /// <summary> | ||
449 | /// Callback to retrieve text data for configurable merge modules. | ||
450 | /// </summary> | ||
451 | /// <param name="name">Name of the data to be retrieved.</param> | ||
452 | /// <param name="configData">The data corresponding to the name.</param> | ||
453 | /// <returns>The error code (HRESULT).</returns> | ||
454 | [PreserveSig] | ||
455 | int ProvideTextData([In, MarshalAs(UnmanagedType.BStr)] string name, [MarshalAs(UnmanagedType.BStr)] out string configData); | ||
456 | |||
457 | /// <summary> | ||
458 | /// Callback to retrieve integer data for configurable merge modules. | ||
459 | /// </summary> | ||
460 | /// <param name="name">Name of the data to be retrieved.</param> | ||
461 | /// <param name="configData">The data corresponding to the name.</param> | ||
462 | /// <returns>The error code (HRESULT).</returns> | ||
463 | [PreserveSig] | ||
464 | int ProvideIntegerData([In, MarshalAs(UnmanagedType.BStr)] string name, out int configData); | ||
465 | } | ||
466 | |||
467 | /// <summary> | ||
468 | /// Merge merge modules into an MSI file. | ||
469 | /// </summary> | ||
470 | [ComImport, Guid("F94985D5-29F9-4743-9805-99BC3F35B678")] | ||
471 | public class MsmMerge2 | ||
472 | { | ||
473 | } | ||
474 | |||
475 | /// <summary> | ||
476 | /// Defines the standard COM IClassFactory interface. | ||
477 | /// </summary> | ||
478 | [ComImport, Guid("00000001-0000-0000-C000-000000000046")] | ||
479 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | ||
480 | public interface IClassFactory | ||
481 | { | ||
482 | [return:MarshalAs(UnmanagedType.IUnknown)] | ||
483 | object CreateInstance(IntPtr unkOuter, [MarshalAs(UnmanagedType.LPStruct)] Guid iid); | ||
484 | } | ||
485 | |||
486 | /// <summary> | ||
487 | /// Contains native methods for merge operations. | ||
488 | /// </summary> | ||
489 | public class MsmInterop | ||
490 | { | ||
491 | [DllImport("mergemod.dll", EntryPoint="DllGetClassObject", PreserveSig=false)] | ||
492 | [return: MarshalAs(UnmanagedType.IUnknown)] | ||
493 | private static extern object MergeModGetClassObject([MarshalAs(UnmanagedType.LPStruct)] Guid clsid, [MarshalAs(UnmanagedType.LPStruct)] Guid iid); | ||
494 | |||
495 | /// <summary> | ||
496 | /// Load the merge object directly from a local mergemod.dll without going through COM registration. | ||
497 | /// </summary> | ||
498 | /// <returns>Merge interface.</returns> | ||
499 | public static IMsmMerge2 GetMsmMerge() | ||
500 | { | ||
501 | IClassFactory classFactory = (IClassFactory) MergeModGetClassObject(typeof(MsmMerge2).GUID, typeof(IClassFactory).GUID); | ||
502 | return (IMsmMerge2) classFactory.CreateInstance(IntPtr.Zero, typeof(IMsmMerge2).GUID); | ||
503 | } | ||
504 | } | ||
505 | } | ||
diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs index 98232901..7b381347 100644 --- a/src/WixToolset.Core/Linker.cs +++ b/src/WixToolset.Core/Linker.cs | |||
@@ -356,7 +356,7 @@ namespace WixToolset.Core | |||
356 | case TupleDefinitionType.WixMerge: | 356 | case TupleDefinitionType.WixMerge: |
357 | if (SectionType.Product == resolvedSection.Type) | 357 | if (SectionType.Product == resolvedSection.Type) |
358 | { | 358 | { |
359 | this.ResolveFeatures(tuple, 0, 7, modulesToFeatures, null); | 359 | this.ResolveFeatures(tuple, -1, (int)WixMergeTupleFields.FeatureRef, modulesToFeatures, null); |
360 | } | 360 | } |
361 | break; | 361 | break; |
362 | 362 | ||
@@ -1316,7 +1316,7 @@ namespace WixToolset.Core | |||
1316 | /// <param name="multipleFeatureComponents">Hashtable of known components under multiple features.</param> | 1316 | /// <param name="multipleFeatureComponents">Hashtable of known components under multiple features.</param> |
1317 | private void ResolveFeatures(IntermediateTuple tuple, int connectionColumn, int featureColumn, ConnectToFeatureCollection connectToFeatures, Hashtable multipleFeatureComponents) | 1317 | private void ResolveFeatures(IntermediateTuple tuple, int connectionColumn, int featureColumn, ConnectToFeatureCollection connectToFeatures, Hashtable multipleFeatureComponents) |
1318 | { | 1318 | { |
1319 | var connectionId = tuple.AsString(connectionColumn); | 1319 | var connectionId = connectionColumn < 0 ? tuple.Id.Id : tuple.AsString(connectionColumn); |
1320 | var featureId = tuple.AsString(featureColumn); | 1320 | var featureId = tuple.AsString(featureColumn); |
1321 | 1321 | ||
1322 | if (EmptyGuid == featureId) | 1322 | if (EmptyGuid == featureId) |
diff --git a/src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs b/src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs index bb44395f..aa8a0a0d 100644 --- a/src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs | |||
@@ -8,6 +8,9 @@ namespace WixToolsetTest.CoreIntegration | |||
8 | using Example.Extension; | 8 | using Example.Extension; |
9 | using WixBuildTools.TestSupport; | 9 | using WixBuildTools.TestSupport; |
10 | using WixToolset.Core.TestPackage; | 10 | using WixToolset.Core.TestPackage; |
11 | using WixToolset.Data; | ||
12 | using WixToolset.Data.Tuples; | ||
13 | using WixToolset.Data.WindowsInstaller; | ||
11 | using Xunit; | 14 | using Xunit; |
12 | 15 | ||
13 | public class MsiQueryFixture | 16 | public class MsiQueryFixture |
@@ -1171,5 +1174,52 @@ namespace WixToolsetTest.CoreIntegration | |||
1171 | }, secureProperties.Substring(prefix.Length).Split(';').OrderBy(p => p)); | 1174 | }, secureProperties.Substring(prefix.Length).Split(';').OrderBy(p => p)); |
1172 | } | 1175 | } |
1173 | } | 1176 | } |
1177 | |||
1178 | [Fact] | ||
1179 | public void CanMergeModule() | ||
1180 | { | ||
1181 | var folder = TestData.Get(@"TestData\SimpleMerge"); | ||
1182 | |||
1183 | using (var fs = new DisposableFileSystem()) | ||
1184 | { | ||
1185 | var intermediateFolder = fs.GetFolder(); | ||
1186 | var msiPath = Path.Combine(intermediateFolder, @"bin\test.msi"); | ||
1187 | var cabPath = Path.Combine(intermediateFolder, @"bin\cab1.cab"); | ||
1188 | |||
1189 | var result = WixRunner.Execute(new[] | ||
1190 | { | ||
1191 | "build", | ||
1192 | Path.Combine(folder, "Package.wxs"), | ||
1193 | "-loc", Path.Combine(folder, "Package.en-us.wxl"), | ||
1194 | "-bindpath", Path.Combine(folder, ".data"), | ||
1195 | "-intermediateFolder", intermediateFolder, | ||
1196 | "-o", msiPath | ||
1197 | }); | ||
1198 | |||
1199 | result.AssertSuccess(); | ||
1200 | |||
1201 | Assert.True(File.Exists(msiPath)); | ||
1202 | Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.wixpdb"))); | ||
1203 | |||
1204 | var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); | ||
1205 | var section = intermediate.Sections.Single(); | ||
1206 | Assert.Empty(section.Tuples.OfType<FileTuple>()); | ||
1207 | |||
1208 | var data = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); | ||
1209 | Assert.Null(data.Tables["File"]); | ||
1210 | |||
1211 | var results = Query.QueryDatabase(msiPath, new[] { "File" }); | ||
1212 | Assert.Equal(new[] | ||
1213 | { | ||
1214 | "File:filyIq8rqcxxf903Hsn5K9L0SWV73g.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tModuleComponent.243FB739_4D05_472F_9CFB_EF6B1017B6DE\ttest.txt\t17\t\t\t512\t0" | ||
1215 | }, results); | ||
1216 | |||
1217 | var files = Query.GetCabinetFiles(cabPath); | ||
1218 | Assert.Equal(new[] | ||
1219 | { | ||
1220 | "filyIq8rqcxxf903Hsn5K9L0SWV73g.243FB739_4D05_472F_9CFB_EF6B1017B6DE" | ||
1221 | }, files.Select(f => f.Name).ToArray()); | ||
1222 | } | ||
1223 | } | ||
1174 | } | 1224 | } |
1175 | } | 1225 | } |
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/.data/test.msm b/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/.data/test.msm new file mode 100644 index 00000000..6f179aba --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/.data/test.msm | |||
Binary files differ | |||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.en-us.wxl b/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.en-us.wxl new file mode 100644 index 00000000..38c12ac1 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.en-us.wxl | |||
@@ -0,0 +1,11 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | |||
3 | <!-- | ||
4 | This file contains the declaration of all the localizable strings. | ||
5 | --> | ||
6 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> | ||
7 | |||
8 | <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String> | ||
9 | <String Id="FeatureTitle">MsiPackage</String> | ||
10 | |||
11 | </WixLocalization> | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.wxs new file mode 100644 index 00000000..303e2ba8 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.wxs | |||
@@ -0,0 +1,24 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
3 | <Product Id="*" Name="MsiPackage" Codepage="1252" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
4 | <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" /> | ||
5 | |||
6 | <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" /> | ||
7 | <MediaTemplate /> | ||
8 | |||
9 | <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)"> | ||
10 | <MergeRef Id="TestMsm" /> | ||
11 | </Feature> | ||
12 | </Product> | ||
13 | |||
14 | <Fragment> | ||
15 | <Directory Id="TARGETDIR" Name="SourceDir"> | ||
16 | <Directory Id="ProgramFilesFolder"> | ||
17 | <Directory Id="INSTALLFOLDER" Name="MsiPackage"> | ||
18 | <!-- --> | ||
19 | <Merge Id="TestMsm" Language="1033" SourceFile="test.msm" DiskId="1" /> | ||
20 | </Directory> | ||
21 | </Directory> | ||
22 | </Directory> | ||
23 | </Fragment> | ||
24 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj b/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj index 0651ec7a..9d2cf1d6 100644 --- a/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj +++ b/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj | |||
@@ -77,6 +77,9 @@ | |||
77 | <Content Include="TestData\SimpleBundle\data\fakeba.dll" CopyToOutputDirectory="PreserveNewest" /> | 77 | <Content Include="TestData\SimpleBundle\data\fakeba.dll" CopyToOutputDirectory="PreserveNewest" /> |
78 | <Content Include="TestData\SimpleBundle\data\MsiPackage\Shared.dll" CopyToOutputDirectory="PreserveNewest" /> | 78 | <Content Include="TestData\SimpleBundle\data\MsiPackage\Shared.dll" CopyToOutputDirectory="PreserveNewest" /> |
79 | <Content Include="TestData\SimpleBundle\data\MsiPackage\test.txt" CopyToOutputDirectory="PreserveNewest" /> | 79 | <Content Include="TestData\SimpleBundle\data\MsiPackage\test.txt" CopyToOutputDirectory="PreserveNewest" /> |
80 | <Content Include="TestData\SimpleMerge\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" /> | ||
81 | <Content Include="TestData\SimpleMerge\Package.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
82 | <Content Include="TestData\SimpleMerge\.data\test.msm" CopyToOutputDirectory="PreserveNewest" /> | ||
80 | <Content Include="TestData\SimpleModule\data\test.txt" CopyToOutputDirectory="PreserveNewest" /> | 83 | <Content Include="TestData\SimpleModule\data\test.txt" CopyToOutputDirectory="PreserveNewest" /> |
81 | <Content Include="TestData\SimpleModule\Module.en-us.wxl" CopyToOutputDirectory="PreserveNewest" /> | 84 | <Content Include="TestData\SimpleModule\Module.en-us.wxl" CopyToOutputDirectory="PreserveNewest" /> |
82 | <Content Include="TestData\SimpleModule\Module.wxs" CopyToOutputDirectory="PreserveNewest" /> | 85 | <Content Include="TestData\SimpleModule\Module.wxs" CopyToOutputDirectory="PreserveNewest" /> |