How to use FileSearch result as condition in Component section.
I want to get something like this:
<Property Id=\"CONFIG_XML_EXISTS\">
<DirectorySearch Id="CheckForConfigXml" Path="[INSTALLDIR]\">'
<FileSearch Id="ConfigXmlSearch" Name="config.xml" />
</DirectorySearch>
</Property>
...
<Component Id="c_DefaultConfig.xml" Guid="{1AAB0AFD-B763-4A55-8585-B0AD4D8CE23C}">
<File Id="f_default_config.xml"
Name="default-config.xml"
Source="$(var.SourceRoot)\config.xml"/>
<Condition>CONFIG_XML_EXISTS</Condition>
</Component>
I don't know why but property wix doesn't want to evaluate CONFIG_XML_EXISTS.
Because that search happens very early in the install, the most likely reason is that INSTALLDIR has no value. You haven't said whether you're doing a fresh install or an upgrade, so it's not clear where you think it might be getting its value from.
I'd also point out that the purpose of that source code is apparently to prevent the install of a file if there is one there already, so:
If INSTALLDIR turns out to be the application folder (typically program files) where your files are installed then users can usually change this location, so it's not clear the file is going to be where you expect it to be.
The file overwrite rules prevent incoming files from overwriting modified data files (modify date > creation date) so if that config file has been changed it won't be overwritten and you don't need to do the check.
In your comment you say "My installer must create file config.xml only if there is no such file in target(install) directory. If such file exists, my installer must create file with name template.xml". I think that perhaps the easiest way to do this is in the application after the install has finished, or possibly in a custom action after all the files have been installed. There seems to be no good way to do this before the install because INSTALLDIR is unpredictable. I've seen this kind of problem solved by installing the XML files to (say) User's Application Data, and after the files are installed then the application or a custom action can see what files are there (or not) and get them from User's Application Data.
Related
In my setup i copy an external file (which path comes from an custom action) into the install directory with CopyFile. This works for an clean new installation.
But when the user chooses "change installation" on second execution of the setup and choose an different external file, the CopyFile isn't executed and the file doesnt get updated.
This is the component with CopyFile. In CFGFILE is the path to the file the users has chosen stored.
<Component Id="C_CopyCfgFile" Guid="0D09480A-36E8-41C9-B887-0C6AF0B99E05">
<Condition><![CDATA[CFGFILE <> ""]]></Condition>
<CopyFile Id="copyCFG" DestinationDirectory="INSTALLDIR" SourceProperty="CFGFILE" DestinationName="prod_556.cfg" />
</Component>
It seems that the installer doesnt recognize the change of the CFGFILE property. What must be done to, that the file is copied every time?
Edit:
In the log file the folllowig appears at change install:
MSI (s) (4C:38) [08:36:30:724]: PROPERTY CHANGE: Modifying CFGFILE property. Its current value is 'C:\Users\marco\Desktop\newconfig.cfg'. Its new value: 'C:\Users\marco\Desktop\newconfig.cfg\'.
That is the new file that is choosen at "change" install. The original file is never mentioned in the log
A verbose log file will tell for sure, but the Component install state is probably detected as already present since the KeyPath of the Component is just it's Directory.
So, you'll need to manually set the parent Feature of the Component install state to be reinstalled. See the REINSTALL Property.
I have adapted a program to stop needing administrator rights or writing data files into its installation programfiles directory. These files are not created by the program but modified: they exist in a fresh installation, even if they were empty (not really the case anyway).
Now I need to adapt the installer, for the additional requirement that, if there are files from a previous version, I must preserve them somehow, so the program uses them instead of the default ones. The previous MSI (not made with WiX) leaves these files behind after un-installation.
My solution for the program itself has been to install the default data files directly into INSTALLFOLDER/programfiles as before, but check within the program at every run if the files exist in appdata, otherwise copy the fresh ones from programfiles, then start using the new path. I do this because I still want this to be per-user data, but I can't rely on an installation to store files in every current and future user profile; and I think that would not be something an MSI should do. (BTW am I wrong here?)
Now for installation the effect I thought would be best is to keep installing the fresh data files into programfiles, but have the MSI move existing files, if any (if there are no data files in programfiles installation should just go on), into appdata (so they will be found and used by the program, for the user who installed). The icing on the cake would be resolving the conflict in case files are found both in programfiles and appdata (I should assume the latter would be more recent).
This is my first try:
<Directory Id="AppDataFolder">
<Directory Id="appdataDirAuthor" Name="authorName">
<Directory Id="appdataDir" Name="productName">
<Component Id="dbPreserve" Permanent="yes" Guid="XXXXXX">
<CopyFile Id="dbPreserveFoo" Delete="yes" DestinationDirectory="appdataDir" SourceDirectory="dbDir" SourceName="Foo*.*" />
</Component>
</Directory>
</Directory>
</Directory>
Of course I get errors that I must use a registry KeyPath, and that I'm missing RemoveFile. But what I want is a one-time copy, and I don't need or want the OS to track it, because I'm just mimicking how files would be left over in appdata by the software itself, that un-installation would not touch.
Perhaps this is better suited for an ad hoc script outside the MSI run via a custom action?
what is the best way to accomplish this file copying (via MSI standard actions or not)?
Is this copying the best or least bad way to accomplish my original goal?
Many thanks in advance.
Well after reading the authoritative answers to this other question, I am reaffirmed that this kind of thing is not appropriate to be done by the installer.
Just for info this is the Windows batch script I'll use instead (before InstallFiles):
#echo off
if exist "%APPDATA%\authorName\prodName\Foo.bar" exit /b 0
set dirOrig=0
if exist "%ProgramFiles(x86)%\prodNameOld\DATABASE\Foo.bar" set dirOrig=%ProgramFiles(x86)%\prodNameOld\DATABASE
if exist "%ProgramFiles(x86)%\prodName\DATABASE\Foo.bar" set dirOrig=%ProgramFiles(x86)%\prodName\DATABASE
if "%dirOrig%"=="0" exit /b 0
xcopy "%dirOrig%\Foo.bar" "%APPDATA%\authorName\prodName\" /y
xcopy "%dirOrig%\etc.*" "%APPDATA%\authorName\prodName\" /y
del /f/q "%dirOrig%\*.*"
exit /b 0
I am linking my product with other libraries, trying to make it easier to install a set of directories in multiple installations. The purpose is to reuse the xml code, problem is they have to be installed in the Root directory per customer requirement.
So I have my ComponentGroups inside the WixLibrary.
I set up my directories in the Wix Application.
But after CostFinalize just before Installation the Directories are reset to their default values and not the ones chosen by my user during the Dialogs Sequence.
Is there a way to prevent this?
Ok, First things first:
The problem is that after CostFinalize and all UI operations my directories where replaced with the default values.
The problem started when I linked two different libraries that used the same global directory.
The folder is set in the root folder of Windows (Per customer Requirement) and then set up to a default value. Then we attach a Property just like we would do it for the WIXUI_INSTALLDIR, overall we have the following:
One root folder for the specific files of the installer
A library that installs files to 4 directories that are unrelated to that root directory.
Another library that installs files and runs scripts to 1 directory of those 4 external directories. This library is the only specifc to our install.
Linking all that is a problem of its own, it has to be done in the Product, in the UI, and using the PropertyRefspecified in the external library. Furthermore, keep in mind that every PathEdit has to be set to Indirect="yes", and you have to set all indirect Properties that point to your Directory in the UI
To fix the problem is really simple, Microsoft Installer rechecks all our folders after the user has set them up during the Install Sequence, so we need to prevent any changes after the user has changed it during the UI Sequence. Thus Properties to the rescue.
Here is an example, in the UI you set a freeze folders to each folder you want to set in the InstallUISequence
<Property Id="SETFOLDERFREEZE">0</Property>
<CustomAction Id="caSetPreventChanges" Property="SETFOLDERFREEZE" Value="1"/>
Then in your Product you link that property.
<PropertyRef Id="SETFOLDERFREEZE"/>
<SetDirectory Id="SPECIFIC_FOLDER" Value="[WindowsVolume]MoreStuff" Sequence="both">
<![CDATA[SETFOLDERFREEZE<>"1"]]>
</SetDirectory>
<Property Id="EXTRAFILES_INSTALLDIR" Value="SPECIFIC_FOLDER"/>
You use the Property EXTRAFILES_INSTALLDIR in your specific UI for that project and you use SPECIFIC_FOLDER in your reusable Library.
It's a mess... but allows reusability, and setting some simple properties and custom actions beats setting up the Files and Folders all over again, specially if there are hundreds of them.
I have multiple config files (for different environments). During install user get to select the environment, and based on that correct files are copied. I want to delete the extra files that are not used.
I am using but it doesn't seem to be working. I don't get any errors as such, in the log I see action getting executed but files are not deleted. Can anyone please point what I am doing wrong?
<Component Id="RemoveFiles" Guid="C5D634C2-744E-4CA5-BB44-F3DE88482AB5">
<RemoveFile Id="RemoveConfigs" Name="???_*.config" On="install" />
</Component>
My RemoveFile table also looks like
FileKey Component FileName DirProperty InstallMode
RemoveExtraConfigFiles RemoveExtraFiles p6wjlh9a.con|Web_*.config INSTALLDIR 1
Still it's not deleting anything
RemoveFile or CopyFile always run before InstallFiles, and it finds no files in the install directory, hence it fails.
The RemoveFiles action will try to find the files you specified in the parent directory of the component, in case you don't override it in the RemoveFile element itself (according to your sample, you don't). Make sure that it is really a folder containing that file. If the file is not found, the action won't fail - it will silently continue.
(I'm newbe in Installer world so I'm still not sure what is right what is wrong. Anyway.)
I make a installer for service which uses desktop database. The database file should somehow be copied during first installation, be intact during upgrades and finally removed during uninstall.
As far I know, I can't add the database file as a directory component - 'cause installer will automatically remove it during uninstall. On the other hand, if I set the Persistent attribute, the database file will be NEVER removed by installer (even, if I will create separate component with RemoveFile element).
The above leads me to thinking, that I can't add the database file as directory's component.
So what are other options?
Is it possible to include a file into installer file (msi) and then copy the file with custom action to target folder?
Then deletion could be solved with RemoveFile element and condition base on UPGRADINGPRODUCTCODE property.
What do you think, guys?
If you are going to be using a custom action, why not create a custom action the will remove the file on uninstall. I have a custom action like that in a couple of my installers due to updates that happen to the target folder after the program has been running for a while. this just ensures a clean uninstall with no files laying around.