How to not copy a file in subsequent installations? - wix

In the Product.wxs, I set Schedule="afterInstallInitialize" in the MajorUpgrade so that if the installation fails, it will roll back to the previous version.
Our Windows Service uses app.config that the installer copied to the installed machine.
We do this by including the below line in the Product.wxs:
<Component Id="Config" Win64="yes">
<File Source="$(var.WixWindowsService2012.TargetDir)WixWindowsService2012.exe.config"
Name="WixWindowsService2012.exe.config"
Vital="yes" KeyPath="yes" />
</Component>
We only want to copy this app.config file on the first installation, and we do NOT want to copy it in the subsequent installations.
When I comment out the above Component element in the Product.wxs, the installation failed because during installation, it deletes the app.config on the installed folder, and since the Windows Service requires it to run, the installation fails.
How can I make the installation to not copy the app.config to the installed folder if app.config already exists there ?
Thank you.

The problem is that the RemoveExistingProducts of the upgrade is removing the file, then the incoming upgrade installs the new one, as discussed in the WiX mailing list. RemoveExistingProducts needs to be just before InstallFinalize and after InstallExecute at the end.

Related

VC redistributable fails to install when executed within an MSI [duplicate]

I have an application compiled in VS 2015 and requires the VC++ Redistributable package in order to run properly. Prior to this latest build, we were using an older version of VS and simply used a merge module to handle the installation of the appropriate redist files. However, I noticed that when using the latest version of the merge modules for 2015 (Microsoft_VC140_CRT_x64.msm) that my application still wouldn't work out of the box. I did some digging and it appears that some things have changed with the latest version of the merge modules. It appears that Microsoft is now recommending to install the vcredist_x64.exe package directly instead of using merge modules.
So, I'm attempting to create a custom action to do this. I'm following a similar tutorial here, although adapting it for the VC Redistributable executable. The first thing I need to do is setup where the .exe file is going to be placed once installed:
<Directory Id='APPLICATIONROOTDIRECTORY' Name='MyApp'>
<Directory Id="VCREDISTDIR" Name="VCRedist">
</Directory>
</Directory>
Then, I need to add my files into a component group which will be installed as part of a hidden feature (as I want this to be automatically installed).
<ComponentGroup Id="VCRedist" Directory="VCREDISTDIR">
<Component Id="vcredist_x64.exe" Guid="-INSERT-GUID-HERE-" Win64="yes">
<File Id="VCREDISEXE" Name="vcredist_x64.exe" KeyPath="yes" Source="$(var.VCRedistSourceDir)" Checksum="yes"></File>
</Component>
</ComponentGroup>
And...
<Feature Id="VCRedistributable" Title="Visual C++ Runtime" AllowAdvertise="no" Display="hidden" Level="1">
<ComponentGroupRef Id="VCRedist" />
</Feature>
At this point, the vcredist_x64.exe should be copied to the end user's machine. Now, I need to create a custom action to launch the executable after the installation.
<CustomAction Id="InstallVCRedistributable"
FileKey="VCREDISEXE"
Execute="deferred"
ExeCommand="/silent"
Impersonate="no"
Return="check"/>
<InstallExecuteSequence>
<Custom Action="InstallVCRedistributable" Before="InstallFinalize">
<![CDATA[NOT REMOVE]]>
</Custom>
</InstallExecuteSequence>
I also include a status message to my UI so that I can see when the executable is being executed.
<UI>
<ProgressText Action="InstallVCRedistributable">Installing Visual C++ Redistributable for Visual Studio 2015</ProgressText>
</UI>
Now, when I run my installer it should launch the vcredist_x64.exe... and it does... but then during the installation of that executable it gets hung up. I get a popup message that says there is a problem with this Windows Installer Package and that a program run as part of the setup did not complete. It then rolls-back my main application installation and never gets installed. Can anyone explain why this is happening and how to fix it? Thanks!
I found this question and tried it myself, being in the same situation. I found the installer error you're running into was/is Error 1618: "Another installation is already in progress." It seems that running the vc_redist installer inside your own installer simply won't work.
Your other options seem to be creating a bootstrapper as Patrick Allwood suggests above, or simply asking users to install the vc_redist package on their own before running your own installer. You can detect if the Universal C Runtime is already present by checking for ucrtbase.dll in C:\Windows\System32:
<Property Id="UCRTINSTALLED">
<DirectorySearch Id="UCRTSystemSearch" Path="[WindowsFolder]System32" Depth="0">
<FileSearch Id="UCRTFileSearch" Name="ucrtbase.dll" MinVersion="10.0.10240.16389" />
</DirectorySearch>
</Property>
If you only have a 32-bit installer, you can also use the [SystemFolder] property directly.
EDIT: As Kevin Smyth mentioned, the version of ucrtbase.dll is giving weird issues - reporting version 2.X to some tools, and version 10.Y to other tools. You can remove the MinVersion property if you just want to check for the existence of ucrtbase.dll.
I think the correct approach to take when having prerequisites that have their own installers is to create a WiX bootstrapper bundle, which runs through each installer in turn. This handles things like rollbacks on install failures, etc, which running custom actions from within an installer does not.
A barebones sample can be seen here, you add <MsiPackage> and <ExePackage> in the Chain element in the order you need them to install.
I was facing a similar problem (fully described in this closed question, which actually redirected me here). I was able to solve it, inspired by this entry about running the application after setup.
The key part is basically to add a final step to the UI that launches the vcredist installer:
<UI Id="UI_Main">
<!-- ...... -->
<Publish Dialog="ExitDialog"
Control="Finish"
Event="DoAction"
Value="InstallVCRedistributable">1</Publish>
</UI>
Regarding the custom action:
<CustomAction Id="InstallVCRedistributable"
FileKey="VCREDISEXE"
ExeCommand="/install /passive /norestart"
Impersonate="yes"
Return="asyncNoWait" />

Hot ti Install File just in the first time with WIX

I have a component
<Component Id="ProductComponent" Guid="7935315f-4242-4c7a-a02c-6fd256805356">
<CreateFolder/>
<File
Id="propFile"
Name="aaa.properties"
DiskId="1"
Source="$(var.Project.TargetDir)"
Vital="yes"
KeyPath="yes" ></File>
<?endif?>
</Component>
I want to copy the file just on install , not upgrade.
But I can't find how to do it.
Any idea?
Have you tried using Condition element. I think you can provide a Condition inside Component element to check whether product is already installed or not. If not installed, then create file.
<Component Id="ProductComponent" Guid="7935315f-4242-4c7a-a02c-6fd256805356">
<Condition> NOT Installed </Condition>
<CreateFolder/>
<File
Id="propFile"
Name="aaa.properties"
DiskId="1"
Source="$(var.Project.TargetDir)"
Vital="yes"
KeyPath="yes" ></File>
</Component>
This is a weak spot of MSI (which WiX uses).
MSI installs a file
User modifies the file
MSI goes to install the file. Should it:
a) overwrite and lose user data
b) not overwrite and lose new applciation data
c) merge --- MSI doesn't support this.
If the user data is only one or few attributes there are tricks with custom actions to harvest the user data and reapply it but this is very tricky stuff.
IMO, the best way to approach this is never keep user data in a file installed by the installer. Take app.config appSettings element as an example. It was an atttribute that allows you to extend the file with another file that overrides the settings in the first file. Using this pattern the installer can lay down the app config and the application can create the override file and everything just works because MSI doesn't have to deal with the problem at all.

Wix Installer Is Copying a File During Build Instead of Install

I have a kind of strange issue that I've never run into before. I have a Wix installer that has the following fragment/component:
<Fragment>
<ComponentGroup Id="groupID">
<Component Id="componentID" Guid="a guid" Directory="a directory defined elsewhere">
<File Id="fileID" Source="$(var.mylibraryname.TargetPath)"/>
</Component>
</ComponentGroup >
</Fragment>
The issue is that the file defined above gets copied into the DirectoryRef when I build the Wix project, but it does not copy over when I install it. I do this type of thing pretty frequently, but have never seen this issue crop up. Why would Wix copy the file while being built? In every other instance , running the MSI does.

WIX run vcredist_x64.exe on install

I have an application compiled in VS 2015 and requires the VC++ Redistributable package in order to run properly. Prior to this latest build, we were using an older version of VS and simply used a merge module to handle the installation of the appropriate redist files. However, I noticed that when using the latest version of the merge modules for 2015 (Microsoft_VC140_CRT_x64.msm) that my application still wouldn't work out of the box. I did some digging and it appears that some things have changed with the latest version of the merge modules. It appears that Microsoft is now recommending to install the vcredist_x64.exe package directly instead of using merge modules.
So, I'm attempting to create a custom action to do this. I'm following a similar tutorial here, although adapting it for the VC Redistributable executable. The first thing I need to do is setup where the .exe file is going to be placed once installed:
<Directory Id='APPLICATIONROOTDIRECTORY' Name='MyApp'>
<Directory Id="VCREDISTDIR" Name="VCRedist">
</Directory>
</Directory>
Then, I need to add my files into a component group which will be installed as part of a hidden feature (as I want this to be automatically installed).
<ComponentGroup Id="VCRedist" Directory="VCREDISTDIR">
<Component Id="vcredist_x64.exe" Guid="-INSERT-GUID-HERE-" Win64="yes">
<File Id="VCREDISEXE" Name="vcredist_x64.exe" KeyPath="yes" Source="$(var.VCRedistSourceDir)" Checksum="yes"></File>
</Component>
</ComponentGroup>
And...
<Feature Id="VCRedistributable" Title="Visual C++ Runtime" AllowAdvertise="no" Display="hidden" Level="1">
<ComponentGroupRef Id="VCRedist" />
</Feature>
At this point, the vcredist_x64.exe should be copied to the end user's machine. Now, I need to create a custom action to launch the executable after the installation.
<CustomAction Id="InstallVCRedistributable"
FileKey="VCREDISEXE"
Execute="deferred"
ExeCommand="/silent"
Impersonate="no"
Return="check"/>
<InstallExecuteSequence>
<Custom Action="InstallVCRedistributable" Before="InstallFinalize">
<![CDATA[NOT REMOVE]]>
</Custom>
</InstallExecuteSequence>
I also include a status message to my UI so that I can see when the executable is being executed.
<UI>
<ProgressText Action="InstallVCRedistributable">Installing Visual C++ Redistributable for Visual Studio 2015</ProgressText>
</UI>
Now, when I run my installer it should launch the vcredist_x64.exe... and it does... but then during the installation of that executable it gets hung up. I get a popup message that says there is a problem with this Windows Installer Package and that a program run as part of the setup did not complete. It then rolls-back my main application installation and never gets installed. Can anyone explain why this is happening and how to fix it? Thanks!
I found this question and tried it myself, being in the same situation. I found the installer error you're running into was/is Error 1618: "Another installation is already in progress." It seems that running the vc_redist installer inside your own installer simply won't work.
Your other options seem to be creating a bootstrapper as Patrick Allwood suggests above, or simply asking users to install the vc_redist package on their own before running your own installer. You can detect if the Universal C Runtime is already present by checking for ucrtbase.dll in C:\Windows\System32:
<Property Id="UCRTINSTALLED">
<DirectorySearch Id="UCRTSystemSearch" Path="[WindowsFolder]System32" Depth="0">
<FileSearch Id="UCRTFileSearch" Name="ucrtbase.dll" MinVersion="10.0.10240.16389" />
</DirectorySearch>
</Property>
If you only have a 32-bit installer, you can also use the [SystemFolder] property directly.
EDIT: As Kevin Smyth mentioned, the version of ucrtbase.dll is giving weird issues - reporting version 2.X to some tools, and version 10.Y to other tools. You can remove the MinVersion property if you just want to check for the existence of ucrtbase.dll.
I think the correct approach to take when having prerequisites that have their own installers is to create a WiX bootstrapper bundle, which runs through each installer in turn. This handles things like rollbacks on install failures, etc, which running custom actions from within an installer does not.
A barebones sample can be seen here, you add <MsiPackage> and <ExePackage> in the Chain element in the order you need them to install.
I was facing a similar problem (fully described in this closed question, which actually redirected me here). I was able to solve it, inspired by this entry about running the application after setup.
The key part is basically to add a final step to the UI that launches the vcredist installer:
<UI Id="UI_Main">
<!-- ...... -->
<Publish Dialog="ExitDialog"
Control="Finish"
Event="DoAction"
Value="InstallVCRedistributable">1</Publish>
</UI>
Regarding the custom action:
<CustomAction Id="InstallVCRedistributable"
FileKey="VCREDISEXE"
ExeCommand="/install /passive /norestart"
Impersonate="yes"
Return="asyncNoWait" />

Preventing Msi external file from being compressed and included into burn bootstrapper

Is it possible to include a Msi package into the bootstrapper but not any of it's external files?
So my msi installer has a file:
<Component Directory="INSTALLDIR">
<File Id="DatabaseBackup"
Name="Database.bak"
Source="Database.bak"
Compressed="no" />
</Component>
which outputs:
Installer.msi
Database.bak
Now if I set the burn chain to include the msi package:
<MsiPackage SourceFile="$(var.Installer.TargetPath)" />
the "Database.bak" file is also compressed into the resultant exe. Is it possible to compress the msi but not the .bak file?
If not can someone answer this question better than I can then I won't need to do this at all! :)
I've used the Payload element for this purpose... in your example I would change the MsiPackage element to:
<MsiPackage SourceFile="$(var.Installer.TargetPath)" >
<Payload Compressed="no" SourceFile="{path_to_bak_file}\Database.bak" />
</MsiPackage>
The MSI then picks up the file and uses it as expected.
I haven't found a way to make this conditional or flexible.. in my case it's a config file that is not critical, but my setup now fails (first opens up a file open dialog looking for that file) if the file is missing - of course this depends on the details of the MSI I've created.
Hope this helps