aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2020-05-21 23:08:52 -0700
committerRob Mensching <rob@firegiant.com>2020-05-22 15:21:29 -0700
commite28fcc906046ed12a867b621fc0eabf75fd9db09 (patch)
tree4d879b9e222fcdeadf6091b4b185655ac71b8845 /src
parenta4cc6c64cb94279daeef2ab14e6319105806c053 (diff)
downloadwix-e28fcc906046ed12a867b621fc0eabf75fd9db09.tar.gz
wix-e28fcc906046ed12a867b621fc0eabf75fd9db09.tar.bz2
wix-e28fcc906046ed12a867b621fc0eabf75fd9db09.zip
Add support using mergmod.dll and its interfaces
Diffstat (limited to 'src')
-rw-r--r--src/WixToolset.Core.Native/MsmInterop.cs507
-rw-r--r--src/WixToolset.Core.Native/WixToolset.Core.Native.csproj6
-rw-r--r--src/WixToolset.Core.Native/WixToolset.Core.Native.v3.ncrunchproject10
-rw-r--r--src/test/WixToolsetTest.Core.Native/MsmFixture.cs18
-rw-r--r--src/test/WixToolsetTest.Core.Native/WixToolsetTest.Core.Native.csproj2
-rw-r--r--src/wixnative/Win32/mergemod.dllbin0 -> 169304 bytes
-rw-r--r--src/wixnative/runtime.win.WixToolset.Core.Native.nuspec2
-rw-r--r--src/wixnative/wixnative.vcxproj8
-rw-r--r--src/wixnative/x64/mergemod.dllbin0 -> 183848 bytes
9 files changed, 539 insertions, 14 deletions
diff --git a/src/WixToolset.Core.Native/MsmInterop.cs b/src/WixToolset.Core.Native/MsmInterop.cs
new file mode 100644
index 00000000..6b1ad141
--- /dev/null
+++ b/src/WixToolset.Core.Native/MsmInterop.cs
@@ -0,0 +1,507 @@
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.Core.Native
4{
5 using System;
6 using System.IO;
7 using System.Reflection;
8 using System.Runtime.InteropServices;
9
10 /// <summary>
11 /// Errors returned by merge operations.
12 /// </summary>
13 [Guid("0ADDA825-2C26-11D2-AD65-00A0C9AF11A6")]
14 public 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 public 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 public 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 public 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 public 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 public 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 public 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 public 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 public class MsmInterop
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 public IMsmMerge2 GetMsmMerge()
502 {
503 var classFactory = (IClassFactory)MergeModGetClassObject(typeof(MsmMerge2).GUID, typeof(IClassFactory).GUID);
504 return (IMsmMerge2)classFactory.CreateInstance(IntPtr.Zero, typeof(IMsmMerge2).GUID);
505 }
506 }
507}
diff --git a/src/WixToolset.Core.Native/WixToolset.Core.Native.csproj b/src/WixToolset.Core.Native/WixToolset.Core.Native.csproj
index ee5cbc8e..ca8797a9 100644
--- a/src/WixToolset.Core.Native/WixToolset.Core.Native.csproj
+++ b/src/WixToolset.Core.Native/WixToolset.Core.Native.csproj
@@ -23,13 +23,13 @@
23 </PropertyGroup> 23 </PropertyGroup>
24 24
25 <Target Name="BuildWixNative" BeforeTargets="GetCopyToOutputDirectoryItems" Condition=" '$(NCrunch)'=='' "> 25 <Target Name="BuildWixNative" BeforeTargets="GetCopyToOutputDirectoryItems" Condition=" '$(NCrunch)'=='' ">
26 <MSBuild Projects="..\wixnative\wixnative.vcxproj" Properties="Platform=Win32" Targets="Build;BuiltProjectOutputGroup;DebugSymbolsProjectOutputGroup"> 26 <MSBuild Projects="..\wixnative\wixnative.vcxproj" Properties="Platform=Win32" Targets="Build;BuiltProjectOutputGroup;ContentFilesProjectOutputGroup;DebugSymbolsProjectOutputGroup">
27 <Output TaskParameter="TargetOutputs" ItemName="_NativeProjectOutput" /> 27 <Output TaskParameter="TargetOutputs" ItemName="_NativeProjectOutput" />
28 </MSBuild> 28 </MSBuild>
29 <MSBuild Projects="..\wixnative\wixnative.vcxproj" Properties="Platform=x64" Targets="Build;BuiltProjectOutputGroup;DebugSymbolsProjectOutputGroup"> 29 <MSBuild Projects="..\wixnative\wixnative.vcxproj" Properties="Platform=x64" Targets="Build;BuiltProjectOutputGroup;ContentFilesProjectOutputGroup;DebugSymbolsProjectOutputGroup">
30 <Output TaskParameter="TargetOutputs" ItemName="_NativeProjectOutput" /> 30 <Output TaskParameter="TargetOutputs" ItemName="_NativeProjectOutput" />
31 </MSBuild> 31 </MSBuild>
32 32
33 <WriteLinesToFile File="$(NativeFileListPath)" Lines="@(_NativeProjectOutput)" Overwrite="true" /> 33 <WriteLinesToFile File="$(NativeFileListPath)" Lines="@(_NativeProjectOutput)" Overwrite="true" />
34 34
35 <ItemGroup> 35 <ItemGroup>
diff --git a/src/WixToolset.Core.Native/WixToolset.Core.Native.v3.ncrunchproject b/src/WixToolset.Core.Native/WixToolset.Core.Native.v3.ncrunchproject
deleted file mode 100644
index 0da1f42d..00000000
--- a/src/WixToolset.Core.Native/WixToolset.Core.Native.v3.ncrunchproject
+++ /dev/null
@@ -1,10 +0,0 @@
1<ProjectConfiguration>
2 <Settings>
3 <AdditionalFilesToIncludeForProject>
4 <Value>..\..\build\Debug\Win32\wixnative.x86.exe</Value>
5 <Value>..\..\build\Debug\Win32\wixnative.x86.pdb</Value>
6 <Value>..\..\build\Debug\x64\wixnative.amd64.exe</Value>
7 <Value>..\..\build\Debug\x64\wixnative.amd64.pdb</Value>
8 </AdditionalFilesToIncludeForProject>
9 </Settings>
10</ProjectConfiguration> \ No newline at end of file
diff --git a/src/test/WixToolsetTest.Core.Native/MsmFixture.cs b/src/test/WixToolsetTest.Core.Native/MsmFixture.cs
new file mode 100644
index 00000000..a1e42d94
--- /dev/null
+++ b/src/test/WixToolsetTest.Core.Native/MsmFixture.cs
@@ -0,0 +1,18 @@
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 WixToolsetTest.CoreNative
4{
5 using WixToolset.Core.Native;
6 using Xunit;
7
8 public class MsmFixture
9 {
10 [Fact]
11 public void CanCreateMsmInterface()
12 {
13 var msm = new MsmInterop();
14 var merge = msm.GetMsmMerge();
15 Assert.NotNull(merge);
16 }
17 }
18}
diff --git a/src/test/WixToolsetTest.Core.Native/WixToolsetTest.Core.Native.csproj b/src/test/WixToolsetTest.Core.Native/WixToolsetTest.Core.Native.csproj
index 263712bb..14928112 100644
--- a/src/test/WixToolsetTest.Core.Native/WixToolsetTest.Core.Native.csproj
+++ b/src/test/WixToolsetTest.Core.Native/WixToolsetTest.Core.Native.csproj
@@ -3,7 +3,7 @@
3 3
4<Project Sdk="Microsoft.NET.Sdk"> 4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup> 5 <PropertyGroup>
6 <TargetFramework>netcoreapp2.0</TargetFramework> 6 <TargetFramework>netcoreapp2.1</TargetFramework>
7 <IsPackable>false</IsPackable> 7 <IsPackable>false</IsPackable>
8 </PropertyGroup> 8 </PropertyGroup>
9 9
diff --git a/src/wixnative/Win32/mergemod.dll b/src/wixnative/Win32/mergemod.dll
new file mode 100644
index 00000000..2bf647b2
--- /dev/null
+++ b/src/wixnative/Win32/mergemod.dll
Binary files differ
diff --git a/src/wixnative/runtime.win.WixToolset.Core.Native.nuspec b/src/wixnative/runtime.win.WixToolset.Core.Native.nuspec
index 59eff4e6..a775b570 100644
--- a/src/wixnative/runtime.win.WixToolset.Core.Native.nuspec
+++ b/src/wixnative/runtime.win.WixToolset.Core.Native.nuspec
@@ -14,8 +14,10 @@
14 </metadata> 14 </metadata>
15 15
16 <files> 16 <files>
17 <file src="Win32\mergemod.dll" target="runtimes\win-x86\native" />
17 <file src="Win32\wixnative.exe" target="runtimes\win-x86\native" /> 18 <file src="Win32\wixnative.exe" target="runtimes\win-x86\native" />
18 <file src="Win32\wixnative.pdb" target="runtimes\win-x86\native" /> 19 <file src="Win32\wixnative.pdb" target="runtimes\win-x86\native" />
20 <file src="x64\mergemod.dll" target="runtimes\win-x64\native" />
19 <file src="x64\wixnative.exe" target="runtimes\win-x64\native" /> 21 <file src="x64\wixnative.exe" target="runtimes\win-x64\native" />
20 <file src="x64\wixnative.pdb" target="runtimes\win-x64\native" /> 22 <file src="x64\wixnative.pdb" target="runtimes\win-x64\native" />
21 </files> 23 </files>
diff --git a/src/wixnative/wixnative.vcxproj b/src/wixnative/wixnative.vcxproj
index 57afcc0b..80e0aae5 100644
--- a/src/wixnative/wixnative.vcxproj
+++ b/src/wixnative/wixnative.vcxproj
@@ -69,6 +69,14 @@
69 <None Include="packages.config" /> 69 <None Include="packages.config" />
70 </ItemGroup> 70 </ItemGroup>
71 71
72 <ItemGroup>
73 <None Include="$(Platform)\mergemod.dll">
74 <DeploymentContent>true</DeploymentContent>
75 <Link>%(Filename)%(Extension)</Link>
76 <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
77 </None>
78 </ItemGroup>
79
72 <Target Name="Pack" DependsOnTargets="GetBuildVersion"> 80 <Target Name="Pack" DependsOnTargets="GetBuildVersion">
73 <Exec Command='nuget pack runtime.win.WixToolset.Core.Native.nuspec -BasePath "$(BaseOutputPath)$(Configuration)" -OutputDirectory "$(BaseOutputPath)$(Configuration)" -NoPackageAnalysis -Properties Configuration=$(Configuration);Id=runtime.win.WixToolset.Core.Native;Version="$(BuildVersionSimple)";Platform=$(PlatformTarget);Authors="$(Authors)";Copyright="$(Copyright)";Description="$(Description)";Title="$(Title)"' /> 81 <Exec Command='nuget pack runtime.win.WixToolset.Core.Native.nuspec -BasePath "$(BaseOutputPath)$(Configuration)" -OutputDirectory "$(BaseOutputPath)$(Configuration)" -NoPackageAnalysis -Properties Configuration=$(Configuration);Id=runtime.win.WixToolset.Core.Native;Version="$(BuildVersionSimple)";Platform=$(PlatformTarget);Authors="$(Authors)";Copyright="$(Copyright)";Description="$(Description)";Title="$(Title)"' />
74 </Target> 82 </Target>
diff --git a/src/wixnative/x64/mergemod.dll b/src/wixnative/x64/mergemod.dll
new file mode 100644
index 00000000..2f4cdc7c
--- /dev/null
+++ b/src/wixnative/x64/mergemod.dll
Binary files differ