LGHT1076 / LGHT1076: Install a data file to localappdata - wix

Using WiX, a file can be installed to ProgramFiles using the following:
<DirectoryRef Id="ApplicationBinDirectory">
<Component ...>
<File Id="..." KeyPath="yes" Source="..." />
</Component>
</DirectoryRef>
Now I want to do the same, but the target is a folder in local application data. The file really belongs there according to http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx
<!-- this is the folder in %LOCALAPPDATA% -->
<Directory Id="LocalAppDataFolder">
<Directory Id="ApplicationLocalAppDataDirectory" Name="my folder name"/>
</Directory>
<DirectoryRef Id="ApplicationLocalAppDataDirectory">
<File Id="fil" KeyPath="yes" Source="..." />
</DirectoryRef>
But I get the following error and warning now:
installer.wxs(63) : error LGHT0204 : ICE38: Component ApplicationConfiguration installs to user profile. It must use a registry key under HKCU as its KeyPath, not a file.
installer.wxs(64) : warning LGHT1076 : ICE91: The file 'fil' will be installed to the per user directory 'ApplicationLocalAppDataDirectory' that doesn't vary based on ALLUSERS value. This file won't be copied to each user's profile even if a per
machine installation is desired.
Adding RegistryValue and RemoveFolder as I have to do it for start menu shortcuts doesn't change the message.
I'm kind of lost here. How do I install a file to local appdata? Please note that I want to install only 1 file there, in addition to the usual setup in program files.

This should help. It shows adding a registry key item to be the keypath:
http://nofoe.blogspot.com/2008/12/wix-it-must-use-registry-key-under-hkcu.html

Related

WiX ICE30 error but directory is correct

My WiX (3.10.3.3007) project has 2 different web.config files from, and installed to, 2 different locations. The 2 errors from my build are:
Error ICE30: The target file 'svcenub9.con|Web.config' is installed in '[TARGETDIR]\inetpub\wwwroot\barcode\' by two different components on an LFN system: 'web_config' and 'views_web_config'. This breaks component reference counting.
Error ICE30: The target file 'svcenub9.con|Web.config' is installed in '[TARGETDIR]\inetpub\wwwroot\barcode\' by two different components on an LFN system: 'web_config' and 'views_web_config'. This breaks component reference counting.
The XML in question, and their directories, are:
<Fragment>
<DirectoryRef Id="barcode">
...
<Component Id="web_config" Guid="*">
<File Id="web_config" KeyPath="yes" Source="$(var.buildSrc)\BarcodeIntegrationService\Web.config" />
</Component>
...
<Directory Id="views">
...
<Component Id="views_web_config" Guid="*">
<File Id="views_web_config" KeyPath="yes" Source="$(var.buildSrc)\BarcodeIntegrationService\Views\Web.config" />
</Component>
...
</Directory>
...
</DirectoryRef>
</Fragment>
Since this is an ICE error I do have an MSI generated. When I look there at the Component table I can see that they do indeed have distinct directories.
Is there something in my WiX project that I'm not adding?
The problem is that my Directory elements did not have a Name attribute. In the Directory table the DefaultDir was set to . for all of my directories. Thus the ICE was viewing them as the same directory.

How do I remove files and Folders from ProgramData Folder on Uninstall

Hi there I am having a problem getting my Wix installer to remove elements on Uninstall. The problem folders and files are located on our corporate specified programdata folder 'D:\programdata'. The folders get created OK, however will not remove on Uninstall. The folder structure is as follows
D:\programdata
Company Name
App Name
Logs
QueryOutput
The following is an excerpt from the relevant section of the product.wxs file:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="CommonAppDataFolder" Name="CommonAppData" >
<Directory Id="dirCompanyAppData" Name="Company Name">
<Directory Id="dirAppNameAppData" Name="AppName">
<Component Id="cmpDirCommonAppData" Guid="{F808944A-D898-43F3-BA1D-A35A3FD7DF41}" KeyPath="yes">
<CreateFolder Directory="dirAppNameAppData" />
<RemoveFile Id="PurgeAppName" Name="*.*" On="uninstall" />
<RemoveFolder Id="idDirAppNameAppData" On="uninstall" Directory="dirAppNameAppData" />
</Component>
</Directory>
<Component Id="cmpDirCompanyName" Guid="{A1E7E75A-D582-40C5-BD6B-D36BFB11795E}" KeyPath="yes">
<RemoveFile Id="PurgeCompanyName" Name="*.*" On="uninstall" />
<RemoveFolder Id="idDirCompanName" On="uninstall" Directory="dirCompanyNameAppData" />
</Component>
</Directory>
</Directory>
<Directory Id="ProgramFilesFolder">
... etc
Note company and application identifying elements have been replaced in the code. I have left out the remainder of the wxs file for brevity and because I believe the relevent code is included in this extract. Any assistance much appreciated, this has me stumped.
Kind Regards
Paul J.
From RemoveFolder definition:
Remove an empty folder if the parent component is selected for installation or removal.
In your case the AppData folder probably has user specific configuration in it like it is supposed to.
I think all the component planning is done first, then executed. So, RemoveFile will plan all the files in that folder to be removed and RemoveFolder will decide it shouldn't delete the folder because at the time of planning, the folder still has stuff in it that is not part of the installation included components and therefore not empty.
You will need to use util:RemoveFolderEx. Again there is another caveat to using this.
Because it might dramatically affect Windows Installer's File Costing, the temporary rows must be written before the CostInitialize standard action. Unfortunately, MSI doesn't create properties for the Directory hierarchy in your package until later, in the CostFinalize action.
So you need to manually set a directory based off of a property you probably read from the registry before the WixRemoveFoldersEx action which I think is scheduled just before CostInitialize.

Why are logs left after removal of an application has occurred?

I am struggling against the issue with wix toolset: why after I uninstall an application some folders including the "logs" are not deleted? is it a bug or not?
<Directory Id="logs" Name="logs">
<Component Id="logs" Guid="0A4D0A3F-2E0D-1B1A-1C6D-1A0F8FAAABC6" Win64="$(var.is64)">
<CreateFolder Directory="logs">
<Permission GenericAll="yes" User="Everyone" />
</CreateFolder>
<RemoveFolder Id="logs" On="uninstall"></RemoveFolder>
</Component>
</Directory>
Sometimes if the application you install generates files or folders after the installation, that can prevent WiX from removing the parent folder during uninstall.
If there are log files created after install, you can purge them by adding this to your existing component:
<RemoveFile Id="RemoveLogFiles" Name="*.*" On="uninstall" />
If your application also creates subdirectories and RemoveFile doesn't get rid of them, I would look into using RemoveFolderEx(http://wixtoolset.org/documentation/manual/v3/xsd/util/removefolderex.html). This would require you to to create a Property and write the directory path to a place in the registry so you can set the Property before RemoveFolderEx runs. You can't just use the Directory Id because RemoveFileEx runs before the MSI creates the Directory properties. Read the link I provided if my explanation didn't make sense to you.
Hope this helps!

How to create msi installer which can install file located near by it?

How to create msi installer which can install file located near by it or fetch this file over http?
We want to create an msi installer with wix toolkit 3.9 that should distribute our virtual machine (size is bigger than allowed in cab files), hypervisor, register(unregister) powershell scripts and something else.
We cannot create MSI with big file.
I see two approaches:
We can put virtual machine image located near by msi installed and programming this installer to install image if it exists near by it.
d:> dir
myapp.msi
vm.vdi
We can agree with client that he must put vm image located near the msi installer manually, before run it.
Download this vm image with http. What are the options for this?
How I can do this ?
I do this like this:
<!-- This is a list of directories that are used by this product as installation locations or custom -->
<!-- action file search locations. -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder" Name="AppData">
<Directory Id="AppRootDirectory" Name="Lookd"/>
</Directory>
</Directory>
<DirectoryRef Id="AppRootDirectory">
<Component Id="SupplementalScripts" Guid="31693357-578d-4dde-aefc-92f413942810" KeyPath="yes" DiskId="1">
<CreateFolder/>
<RemoveFolder Id="RemoveAppRootDirectory" On="uninstall" />
<File Id="SupplementalScripts_Register" DiskId="1" Vital="yes" Source="dst\Scripts\Register.ps1" Checksum="no"/>
<File Id="SupplementalScripts_UnRegister" DiskId="1" Vital="yes" Source="dst\Scripts\UnRegister.ps1" Checksum="no"/>
<File Id="SupplementalScripts_Throw" DiskId="1" Vital="yes" Source="dst\Scripts\Throw.ps1" Checksum="no"/>
<RegistryKey Root="HKCU" Key="Software\CVisionLab\Lookd" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Name="Version" Value="[ProductVersion]" Type="string"/>
</RegistryKey>
</Component>
<Component Id="VirtualMachineDiskImage" Guid="daa7375f-7bd8-4e97-846a-db5f6e6b025a">
<CopyFile Id="VDIFile" SourceName="lookd.vdi" SourceDirectory="SOURCEDIR" DestinationDirectory="TARGETDIR" />
</Component>
</DirectoryRef>
But I recive and error when build:
error LGHT0094 : Unresolved reference to symbol 'Directory:SOURCEDIR' in section 'Product:{7BBA165B-9A8A-40D1-97FA-233F93426F83}'.
If 1 will work for you, then a WiX CopyFile should work. The source location of the copy would be the [SourceDir] property, and the destination some directory defined in your WiX.
If it's really that big, download may be tedious, but if you use it then do it from an app you install rather than run it from the MSI install.
Clarifying in response to comment: there are just two recommendations here that are separate and not related:
Use WiX CopyFile if you choose to copy the file from next to the MSI file to the client system.
If you choose the download option, doing that from the MSI will be tedious and very error prone. It may not even work given that VS custom actions have very limited (or no) access to the network. So do a download from the app you're installing and not the MSI, if you do in fact decide to download.

WiX3 - util:XmlFile element executes again when new user first uses a per-machine installation

i created WiX installer project for deploying my .net winform app on a customer machine. The app only scans documents and saves the images to database on a server. The scanner is quite specific and only one in the company, but there are approx. four users that can occasionaly use it => app will be installed just on a single workstation dedicated only for scanning - most of the time it will be free and any of these users can come, scan the docs and go continuing his work.
=> i am doing a per-machine installation: ALLUSERS is hardcoded to 1.
Because the database servers in production are not controlled by me and i do not really know, where the database will be stored, i can not pack correct ConnectionStrings.config file to the MSI archive. Instead of it the setup modifies this config according to parameter values provided by the user during install. For updating the connection strings I use util:XmlFile element. The connectionstrings.config file is stored in installation directory together with app binaries.
Everything seemed to work fine, until I simulated two users using this per-machine installation. I have executed my wix setup project under my own account, the XML config file had been correctly updated and then I launched the application and tested the connection strings are ok. Everything was fine.
Then I switched to another user account. The shortcut was already present in the program menu - just as I would have expected since the installation is per-machine. So I clicked the shortcut and then (unexpectedly for me) a progress bar window "Wait until the configuration of product XY is finished." appeared. (Note that my machine locale is not english, the message would probably be slightly different on an english locale workstation). After few seconds the window disappeared and my application launched. Unfortunately it was not able to connect to the database, since the connectionStrings.config file has been rewritten - the connection strings have been updated using default (=incorrect) property values.
I have been investigating why the setup launchs again whenever new user-account tries to use it. It is because of the shortcut element (Shortcut is placed to 'ProgramMenuFolder'. There is a request for uninstall action, which AFAIK requires a parent Component and this Component needs a KeyPath, which has to be a registry key under HKCU.). When I remove all the Program-Menu-Shortcut-stuff from WXS, MSI is not launched again after switching user context.
Result is that I have setup program, which is able to configure connection to a database according to input parameters. But any later attempt to use the app from a second user-account just sends this configuration down the toilette. In production environment this would mean, that an administrator has to come and manually change the connection strings every time new user tries to use the app, which is of course unacceptable behavior.
This is simplified version of my WiX source:
<?define ProductID = "11111111-1111-1111-1111-111111111111" ?>
<?define ProductName = "MyProduct" ?>
<?define ProductLocalName = "MyLocalLanguageProductName" ?>
<!-- application's root registry path, where it stores its settings -->
<?define ApplicationRootRegistryKey = "Software\MyCompany\MyProject\MyBuildConfiguration" ?>
<Product Id="$(var.ProductID)" UpgradeCode="{11111111-1111-1111-1111-111111111112}"
Name="$(var.ProductName)" Version="1.10.1103"
Manufacturer="MyCompany"Language="1029" Codepage="1250">
<Package Id="*" InstallerVersion="200" Compressed="yes"
Description="$(var.ProductName) Installer" Languages="1029"
SummaryCodepage="1250" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<!-- always install the app for all users -->
<Property Id="ALLUSERS" Value="1"/>
<!-- initialize properties used for adjusting connection strings.
The user will provide valid property values through command-line -->
<Property Id="DB_SERVER_NAME" Value="please-specify-db-server-name"/>
<Property Id="DB_NAME" Value="please-specify-db-name"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="CompanyProgramFilesFolder" Name="CompanyName" >
<Directory Id="INSTALLDIR" Name="ProjectName">
<Directory Id="InstallDirApp" Name="Bin" />
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="AppProgramMenuDir" Name="$(var.ProductLocalName)">
<Component Id="ProgramMenuDir" Guid="*">
<RemoveFolder Id='AppProgramMenuDir' On='uninstall'/>
<RegistryValue Root='HKCU' Key='$(var.ApplicationRootRegistryKey)' Type='string' Value='' KeyPath='yes' />
</Component>
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="InstallDirApp">
<Component Id="Executable" Guid="*">
<File KeyPath="yes" Source="$(var.MyProject.TargetPath)">
<Shortcut Id="ProgramMenuShortcut" Name="$(var.ProductLocalName)"
Directory="AppProgramMenuDir" Advertise="yes"
WorkingDirectory="InstallDirApp" Icon="AppIcon.ico" IconIndex="0"/>
</File>
</Component>
<!-- ConnectionStrings config file deployment and settings adjustment -->
<Component Id="ConnectionStrings.config" Guid="*">
<File KeyPath="yes" Source="$(var.Csob.ChequesScanning.SmartShell.TargetDir)ConnectionStrings.config" />
<!--</Component>
<Component Id="xml01" Guid="*">-->
<!--<Condition><![CDATA[NOT Installed]]></Condition>-->
<!-- this sets the connection strings according to provided parameters -->
<util:XmlFile Id="SetConnectionString" Action="bulkSetValue"
File="[#ConnectionStrings.config]"
ElementPath="//add" Name="connectionString"
Value="Data Source=[DB_SERVER_NAME];Initial Catalog=[DB_NAME];Integrated Security=True;Pooling=True"
Permanent="yes" />
</Component>
</DirectoryRef>
<Icon Id="AppIcon.ico" SourceFile="$(var.MyProject.ProjectDir)Resources\AppIcon.ico" />
<Feature Id="ProductFeature" Title="MyProjectName" Level="1">
<ComponentRef Id="Executable" />
<ComponentRef Id="ConnectionStrings.config"/>
<ComponentRef Id="ProgramMenuDir" />
</Feature>
</Product>
</Wix>
I have tried these steps to resolve the problem, but nothing helped me:
1) I have separated the and the to independent components.
2) I Have Tried adding a NOT INstalled under these components.
3) I have tried writing a registry value to HKLM during installation. I have added a RegistrySearch and Property for that registry value and then used that value as a condition (in fact just a replacement of "NOT Installed" from the previous)
Can anyone help with this? What am I doing wrong?
Thanks in advice
Marek
Root your registry key under HKMU (See reference). This will correctly root your registry key in either HKLM or HKCU depending on the value of the ALLUSERS property.