Merge module files into different locations - wix

I'd like to parse merge module files into two different locations. Is it possible?
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="MergeRedirectFolder">
<Component Id="LoggerClient" Guid="*">
<File Id="log4net" Name="log4net.dll" Source="..\..\_Release\log4net.dll" KeyPath='yes' />
<File Id="LoggerLibrary" Name="LoggerLibrary.dll" Source="..\..\_$(var.Configuration)\LoggerLibrary.dll" />
<File Id="app.config" Name="app.config.xml" Source="..\..\_Release\app.config.xml" />
<File Id="msvcr110.dll" Name="msvcr110.dll" Source="c:\windows\sysWoW64\msvcr110.dll" />
</Component>
</Directory>
</Directory>
</Module>
<Merge Id ="MergeModule.msm" Language ="!(loc.Lang)" SourceFile ="_$(var.Configuration)\MergeModule.msm" DiskId ="1" />
I want the second file to copy to a different folder than the other files.

There is a concept for that, it is called a retargetable merge module. I have avoided used it - the concept doesn't seem right to me. I have not tried to make one with Wix.
I think you could combine a Wix include file (simple sample) with the new auto-generated component guids to deploy such duplicated files reliably by adding an Include statement where appropriate. You must not hard code the guids in this case, but let them be auto generated by the Wix compiler and linker.
Also have a read of WixLibs (Wix library files): http://robmensching.com/blog/posts/2008/10/10/what-are-.wixlibs-and-why-would-you-use-them/
Wix documentation; http://wixtoolset.org/documentation/manual/v3/overview/files.html

Merge modules are for installing common runtimes and genuinly shared files. Typically C and C++ runtimes and other, similar libraries that should be available in the latest version for all applications.
Your files look like they are part of your application folder, with the exception of msvcr110.dll which you should remove and allow to be loaded from the system folder.
If the remaining files have no per-machine registration (COM for example or COM Interop), you can duplicate them in several folders without interference, yes, but why not load them from a shared location inside your own application folder structure?
%ProgramFiles%\My Company\My Shared Runtimes
%ProgramFiles%\My Company\My Apps\My App 1\
%ProgramFiles%\My Company\My Apps\My App 2\
These sample folders you "own" and you can deploy things here however you like. Not so for shared, system folders. You could make your own merge module for shared components between your applications into "My Shared Runtimes" and make your applications aware of the shared location "....\MySharedRuntimes\"

It depends on what you mean by different locations. You can build a merge module with 4 files, each in their own component and directory. One could go to the CommonFilesFolder; another to the SystemFolder; another to...you get the idea. So it's potentially easy if you make each file its own component in its own directory. However you've got them all under TARGETDIR, so you're going the wrong direction. You just define the other directory and that other component and file and you might be done, unless there's more to the question than meets the eye.

I would suggest contacting me privately for a few 30-60 minute conversation on MSI, component rules, Merge Modules and file set theory. It's too much to write. In a nutshell I would advise more merge modules.

Related

How do I stop removal of files during uninstallation using Wix

When uninstalling my application, I'd like to configure the Wix setup to NOT to remove few files that were added as part of the installation. It seems like the uninstaller removes all the files that were originally installed from the MSI file. How do I do that?
Here are my files which I wish to keep it forever
<Binary Id="RootCABinary" SourceFile="Assets\Certificates\RootCA.cer" />
<Binary Id="SubCABinary" SourceFile="Assets\Certificates\SubCA.cer" />
I have used WixIIsExtension.dll to install these certificates to the windows store.
Overwrite: Is it important that the file never gets overwritten? If so, add
"Never Overwrite" to your component. WiX attribute: NeverOverwrite="yes". Remember to test upgrade scenarios!
Permanent Component: As stated by Pavel, you can set a component permanent:
<Component Permanent="yes">
<File Source="License.rtf" />
</Component>
Blank GUID: Another way to do it is to set a blank component GUID. It essentially means "install and then leave alone". No repair or uninstall should be done (remember to add NeverOverwrite="yes" if the file should never be overwritten):
<Component Guid="" Feature="MainApplication">
<File Source="SubCA.cer" KeyPath="yes" />
</Component>
Read-Only Copy: I sometimes install files to a per-machine path (for example somewhere under program files) and then copy them to a per-user location (somewhere in the user-profile) on application launch, and then do operations on them that entail that the files should not be deleted. This is good in cases where you want to do something that change the files in question (they need to be writable). Then it is good to "untangle" them from deployment concerns (files will not be meddled with by installer operations at all - the installer has no knowledge of them). The original read-only copy installed to program files can be uninstalled though (no longer needed?).
Other approaches: You can also create such files using custom actions during installation (usually text files only), you can download the file in question from your web site on application launch (makes the file easy to manage and update / replace? Vulnerable to connection problems - firewalls, etc...) and the application can create the file using "internal defaults" in the main executable on launch. And there are no doubt further approaches that I can't recall.
Put your binaries in a separate WiX component and make it permanent. Have a look at this thread as well

How to include inherited permissions when specifying permissions for a file installed by Wix / Windows Installer?

The Wix source code that I feed to the Wix compiler to build an MSI package for my application, contains the following PermissionEx directive, part of a file component which Windows Installer should install with additional (to those that should be inherited by default) permissions:
<PermissionEx Sddl="D:AR(A;;FW;;;BU)" />
As you can surmise, I intend to install the file with inherited permissions ("AR") included in its ACL and on top of that allow members of the Built-in Users group ("BU") to be allowed ("A") to write to the file ("FW").
The code above does not have the desired effect -- the file is installed, but only that single explicit ACE is listed, none of the ACEs that are supposed to be inherited from parent folder.
In contrast, if I subsequently remove all permissions from the file and run cacls file /S:D:AR(A;;FW;;;BU), i.e. specify exactly the same SDDL string, it does work as intended -- the permissions from parent are inherited and form part of the ACL, together with the explicit non-inherited ACE.
I am using Wix 3.11.1.2318 and the Windows Installer version is 5.0.16299.611, all running on Windows 10 Enterprise 64-bit. Orca tells me the MsiLockPermissionsEx table embedded in my built MSI file is populated with the intended SDDL record. So why is the file created without inheriting permissions from its containing folder?
I tried to use "AI" in place of "AR", and both strings together, but none of it had any effect either.
Is this some known limitation or a quirk with Windows Installer? I know that people were talking a while back how the old LockPermissions table (the one specified for Windows Installer versions earlier than 5) was inadequate in this specific regard -- inherited permissions, namely -- but they also said Microsoft was out to address this very issue with the new table feature.
Otherwise what am I doing wrong?
Given your knowledge in this field, you probably have already tried this. It would also be much better to eliminate the need for permissioning, but two snippets for you - notice the Append attribute:
Create a WiX project in Visual Studio. Add the Util namespace to the WiX element:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
In Visual Studio project, right click References and add reference to "%ProgramFiles(x86)%\WiX Toolset v3.11\bin\WixUtilExtension.dll".
Permission Folder:
<Component Feature="ProductFeature" Id="Test.exe" Guid="PUT-GUID-HERE">
<File Source="C:\Test.exe" />
<CreateFolder>
<util:PermissionEx User="Power Users" GenericWrite="yes" />
</CreateFolder>
</Component>
Permission File:
<Component>
<File Source="C:\Test2.exe">
<util:PermissionEx Append="yes" User="Users" GenericWrite="yes" />
</File>
</Component>
Take a look at WiX's custom PermissionEx in the Util extension.
http://wixtoolset.org/documentation/manual/v3/xsd/util/permissionex.html

Patch (minor upgrade) creation issues with MSM (merge modules)

I am facing issues with patches (minor upgrade) installation (updates) with MSM (merge modules).
I am creating MSI (test.msi) with texst.wxs. And inside text.wxs referring to app.msm file (there is a folder app, which contains so many folders and files. And harvesting this folder and making app.msm file)
Below are steps for making app.msm file.
heat dir "app" -gg -sfrag -template:module -srd -ke -var var.source -out app.wxs
candle -dsource=app app.wxs
light app.wixobj
Below is snippet of test.wxs file
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
....
....
<Directory Id='Config' Name='Config'>
<Component Id='APP_CLIENT' Guid='*'>
<Component Id='Manual' Guid='*'>
<File Id='Manual' Name='Manual.pdf' DiskId='1' Source='Resources/Manual.pdf'
KeyPath='yes'>
<Shortcut Id="startmenuManual" Directory="ProgramMenuDir"
Name="Instruction Manual" Advertise="yes" />
</File>
</Component>
</Directory>
<Directory Id='exmp_REPO' Name='!(loc.Merge_FolderTitle)'>
<Merge Id="LocalRepository" Language="1033" SourceFile="app.msm" DiskId="1"/>
<Component Id='exmp_REPOSITORY' Guid='*'>
<CreateFolder/>
<RemoveFolder Id='exmp_REPO' On='uninstall' />
</Component>
</Directory>
....
<Feature Id='Complete' Display='expand' Level='1' ConfigurableDirectory='MYAPPPATH'>
<ComponentRef Id='Manual'/>
<ComponentRef Id='App_CLIENT'/>
<ComponentRef Id='exmp_REPOSITORY'/>
...
...
I am able to make major upgrade with my test.wxs by using app.msm (merge module). But not able to make patch with successful installation. Patch install (update) is reflecting in version change in the "Programs and Features" and showing in "View Installed updates". The manual changes also are reflecting with patch update. But whatever the changes in "app" (which are created app.msm and referred in test.wxs) folder are not reflecting.
I have used 2 approaches for making patch, which are mentioend in below urls
1) http://wixtoolset.org/documentation/manual/v3/patching/patch_building.html
2) http://wixtoolset.org/documentation/manual/v3/patching/wix_patching.html
Please help in this regards.
First, I would advise to find out, whether the built patch contains the correct files or not. If not, you have a build problem, that the msm is not updated. If yes, you have most likely a problem with the content of the msm which may be not consistent with it's predecessor (especially GUIDs, table primary keys, etc.).
You can find out and see the content of the patch without installing with tools like Orca and Insted which you can search and download.
Second, using merge modules is highly complicating things, especially for patches, and of limited usefulness, if they are your own and you use them only once. Msms are primarily made for situations, where you need the .msm at least for 2 different MSI packages. I have seen a handfull of problems using merge modules in patches with other tools, BTW. I have no special experience here with WiX+patches+MSMs, but, it's as I said.
Last, but not least, you will have to choose, if you really want to keep this complexity in the future. As I remember, there are other possibilities in WiX to modularize / encapsulate parts of your software.
You can check the versions of files in merge modules and MSI files by opening them with Orca and looking in the File table. Or open the MSI file with Orca and then Transform=>View patch to see changes.
It may be obvious, but a binary versioned file will be replaced by a file with a higher file version. I mention because there is a belief out there that somehow "new" files replace "old" files, and that's wrong. Versions matter.
Generally you need to install a patch with an msiexec command that specifies REINSTALL=ALL REINSTALLMODE=omus. Double-clicking an MSP file will not necessarily just work unless you've arranged for it to do this internally with a custom action that sets them when PATCH is set.
The patch will not work if you break component rules. A common mistake is to remove a component during a patch, and that will result in an "advertised" update that doesn't actually update anything. In a verbose log look for SELMGR entries and text about removal of components is not supported. Setting the MSIENFORCEUPGRADECOMPONENTRULES property to 1 will fail the patch if you've done this.
If a file has no version whether it's overwritten depends on the replacement rules here, and there's some difference if the file is hashed or not:
https://msdn.microsoft.com/en-us/library/aa370531(v=vs.85).aspx
Also: how do you know the patch isn't working? If you have no file versions then you can't know if a file has been replaced unless you look very carefully. You cannot trust the dates because Windows changes timestamps when a file is installed. You really need to build binary files with file versions because everything like patches, hotfixes, service packs etc will use them to replace binary files. Otherwise for data files use file hashing.
I see several potential problems here, maybe even in addition to the other answers:
when you heat up files for your merge modules -gg autogenerates new component guids. This will not work with patches, since it'll basically add a bunch of new components (new guids each time!!). Also, you'll remove components this way, which is something you shouldn't do and which cannot be done easily, unless you still include the original merge module. And then you'll end up with path problems.
The tutorial for wix patching uses wixpdb files for diffing the original and the updated installer. With wixpdb files, merge modules will not be patched, irrespective of whether files changed in them or not. You will need to do administrative installations and then diff on the msi itself. You'll still have problem #1.
your wxs snippet is bad. At least the xml element is never correctly closed. Your Feature also has a MergeRef somewhere?
Some tips:
you can view what your patches do with a program called Orca. Open the original msi, then just drag your msp patch file on top of it.
rather don't use merge modules, they complicate things. You can also use heat to generate a fragment which you then simply include into your wix project.
use the wix patching approach (Patch element, not the PatchCreation element). It's easier, but you have the same control
don't autogenerate guids if you plan to update those autogenerated components with a patch. It won't be a problem with major upgrades :)
Just one important issue of a number of potential reasons while files are not updated correctly: You write, in your .msm is a high number of unversioned files, like .xml, etc.
Important rule:
EVERY unversioned file which is changed on the PC AFTER the first MSI install not by the MSI engine itself (e.g. you edited a config.xml file or so), will be normally NEVER updated by MSI again, not by patch and not by Major Upgrade. (With normally I mean, you have to take special actions, like uninstalling or especially specifying those files as socalled companion files).

Conditional inclusion of files based on an Environment variable in a WIX file

So I have a deployment project based on WIX. I notice that you can include features and files in there. However I only want to deploy a particular file if the DEV/QA environment is selected. If they select Production I want it to ignore this particular file.
Is there a way in the .wxi file to conditionally include a feature / directory & files based on a particular value of a variable?
ie. I want to have something like the below - potentially the componentRef included dynamically? (I have sanitised the values).
<Feature Id="MyApplication" Title="MyApp" Description="My Application" ConfigurableDirectory="MYAPP" Level="1">
<ComponentRef Id="AppEmailTemplatesDir" />
</Feature>
and then further down
<Directory Id="EmailTemplatesDir" Name="EmailTemplates">
<Component Id="AppEmailTemplatesDir" Guid="{A-GUID}">
<File Id="EmailTemplate1.htm" Name="EmailTemplate1.htm" DiskId="1" Source="..\..\EmailTemplates\EmailTemplate1.htm" />
</Component>
</Directory>
Any ideas? We do have custom Actions code (VB.NET) but I'm not sure how that could be used apart from writing code to include files.
There seem to be a variety of ways to do this ... this is what worked for me in Visual Studio 2013.
In the WiX project Properties / Tool Settings add this to Additional parameters / Compiler::
-dReleaseType=$(ReleaseType)
Create a component group containing only the additional file (this is left as an exercise for the reader)
In the main .wxs file add something like this where PDBFile is the id of the component group in step 2:
<!-- Installs a PDB file for daily builds -->
<?if $(var.ReleaseType) = daily ?>
<ComponentGroupRef Id="PDBFile"/>
<?endif?>
Run devenv to build the WiX project with ReleaseType set in the environment
Looks like I can use a Component NeverOverwriteOption="yes" option to ensure the installer doesn't overwrite the files when they exists.
Unless the environment conditional stuff was easy to figure out - this seems to achieve what I need which is to not overwrite the file on production.
I also found that on uninstall it was deleting all the folders (as expected) but to keep the template path I could use the Permanent="yes" attribute.
After discussion we've decided to keep all the files in source control and deploy them. But at least I learnt about NeverOverwriteOption and Permanent :)

Config files for GAC assemblies using Wix

I know this has been asked a few times in the past. And I have read all the responses and answers and none of them seem appropriate.
I've tried putting the .config in the same component and in a different component.
I've tried CompanionFile in the same component and in a different component.
I've tried CopyFile.
I've tried a Custom Action.
The component needs to be in the GAC because it is a general logging dll used by many different subsystems (services, websites, etc). But it is configured the same for all systems.
So for now I'm installing the file to a SDK directory and telling the user to copy the file.
The ONLY thing that works is copying the file manually and saying yes to "you need admin perms to do this".
<File Id="SDK.Logging.dll.config"
Source="$(var.LOGGER_DIR)\SDK.Logging.dll.config"
Vital="yes">
</File>
<Property Id="XCOPY">xcopy.exe</Property>
<CustomAction Id="Copy.SDK.Logging.dll.config"
Property="XCOPY"
ExeCommand='"[INSTALLLOCATION]SDK.Logging.dll.config" "[GAC.SDK.Logging.Dir]"' />