I am making installer for a utility that can be installed as part of a main program or independently. The location of the main program in present in a registry key. If the main program is installed, the utility should be installed in a "Utilities" sub-directory. e.g. D:\Program Files(x86)\MainProgram\Utilities. If the main program is not installed, then it should default to root drive folder e.g. C:\Program Files(x86)\MainProgram\Utilities.
Installation should get the registry key (e.g. HKLM\Software\MainProgram\ Key:"Install_location"). This will give a path till d:\Program File(x86)\MainProgram. The utility should be installed in its sub-directly. If the key is not present, it should default to the standard location.
Read the registry value from custom action using C# or some other language and check if key exists or else you can use WIX to find if registry key exists.
RegistryKey regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(#"Software\MainProgram\Key");
if ((string)Registry.GetValue(regKey, "Install_location", "0") != "0")
{
session["Somevariable"] = (string)Registry.GetValue(regKey, "Install_location")
}
using WIX
<Property Id="INSTALLLOCATION">
<RegistrySearch Id="INSTALLLOCATION"
Name="Install_location"
Root="HKLM"
Key="Software\MainProgram\Key"
Type="raw" />
</Property>
On the basis of the value of WIX session variable you can decide the install location and install the utility at the desired path.
Read the MainProgram location into a property:
<Property Id="MainProgramDir">
<RegistrySearch Id="FindMainProgramDir"
Root="HKLM"
Key="Software\MainProgram"
Name="Install_location"
Type="directory" />
</Property>
And set up your directory structure for the default behavior:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="MainProgramDir" Name="MainProgram">
<Directory Id="INSTALLDIR" Name="Utilities"/>
</Directory>
</Directory>
</Directory>
Directory elements are like properties, and will be overridden if there is a property with the same Id. If the property is not set (because the RegistrySearch fails) then it will be as it was defined in the directory structure you set up.
Related
I am using the feature tree dialog set which allows for a customised install directory, I am then trying to store this install directory inside a registry
As per Wix's documentation I am defaulting the ui variable to the directory I want
<Property Id="WIXUI_INSTALLDIR" Value="VERSION" />
<SetProperty Id="VERSION" Value="[ProgramFilesFolder]Thermo\SampleManager\[PROP_VERSION]" After="CostInitialize" />
Then trying to set the registry as follow
<RegistryKey Root="HKCR" Key="x\x\x">
<RegistryValue Type="string" Value="[VERSION]aaasx\aasx" />
</RegistryKey>
Obviously the [VERSION] does not change with the UI selection, which variable should I be using to change the configured directory? Feel as if I've tried every suggested [INSTALLDIR] etc.
Directory is configured as such
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="COMPANY" Name="Company">
<Directory Id="PRODUCT" Name="Product">
<Directory Id="VERSION" Name="Version">
Further investigation found that using file references ( [#file] ) works, which solves 90% of my problems, however pointing/storing a directory path does not work
You can use only RegistryValue like that:
<RegistryValue Root='HKCR' Key='SOFTWARE\MyProcudt'
Name='MyPath' Value='[INSTALLDIR]'
Type='string' />
It will create registry in HKCR/software/myproduct name "mypath" with value [installdir] (set ealrier).
I'm using Wix to create an installer that will search for a directory on the user's PC and install a related application to that directory. For example, I need to install to the folder ProductA\Utilities, the location of which is outside of my control.
To accomplish this, I have tried the following:
<Property Id="UTILITIES_DIR">
<DirectorySearch Id="FindUtilsDir" Path="ProductA\Utilities"/>
</Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<!-- WiX requires me to use a special folder at some point -->
<Directory Id="ProgramFilesFolder" Name="ProgramFiles">
<Directory Id="UTILITIES_DIR">
<Directory Id="INSTALLFOLDER" Name="MyUtility"/>
</Directory>
</Directory>
</Directory>
This all works well when I'm running the installer by double clicking, however, when I run the installer through msiexec.exe, the UTILITIES_DIR is found, but overwritten immediately after:
From log file:
MSI (c) (C0:0C) [16:49:34:064]:
PROPERTY CHANGE: Adding TARGETDIR property. Its value is 'F:\'.
MSI (c) (C0:0C) [16:49:34:064]:
PROPERTY CHANGE: Modifying ProgramFilesFolder property.
Its current value is 'C:\Program Files (x86)\'. Its new value: 'F:\ProgramFiles\'.
MSI (c) (C0:0C) [16:49:34:064]:
PROPERTY CHANGE: Modifying UTILITIES_DIR property.
Its current value is 'C:\ProductA\Utilities'. Its new value: 'F:\ProgramFiles\'.
It's worth noting that F:\ on my machine is a network share to parts of C:\ and it reports the exact same free space as C:\, so it seems that I'm getting lucky when running the .msi directly and TARGETDIR is set to C:\, but when running from msiexec, TARGETDIR is getting set to F:.
Is there a way to accomplish finding a specific directory that may be in any root?
You can set the SourceDir to WindowsVolume. So it will not change anymore.
<SetDirectory Id="SourceDir " Value="[WindowsVolume]" />
I'm creating a program which is being installed by Wix, using VS 2010 and I've already got the product.wxs ready.
In my wxs file, I've got directory definitions which looks like this:
<SetDirectory Id="INSTALLFOLDER" Value="[WindowsVolume]Myapp" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLFOLDER" Name="Myapp">
<Directory Id="Myapp_Installer_Dir" Name="Myapp">
<Directory Id="BIN" Name="Bin" />
<Directory Id="ICONS" Name="Icons" />
</Directory>
</Directory>
</Directory>
And then I got these file installation definitions:
<DirectoryRef Id="Myapp_Installer_Dir">
<Component Id="INSTALLER_Myapp" Guid="{94F18477-8562-4004-BC6F-5629CC19E4CB}" >
<File Source="$(var.Myapp.TargetPath)" KeyPath="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="BIN">
<Component Id="INSTALLER_Data" Guid="{545FB5DD-8A52-44D7-898E-7316E70A93F5}" >
<File Source="$(var.Data.TargetPath)" KeyPath="yes"/>
</Component>
...
And it continues in that manner. The files for the "ICONS" directory are defined as well.
I am also using the WixUI_InstallDir dialog set and I got these lines present as well:
<Property Id="WIXUI_INSTALLDIR" Value="Myapp_Installer_Dir" />
<UIRef Id="WixUI_InstallDir" />
The problem is when the user installs the program and changes the value of the installation folder, the files of the "Bin" and "Icons" are installed to their correct path, but the Myapp target is installed to a fix location which was defined at the start as the default installation path.
Why do only the bin and icon files installed to the correct folder the user wanted, but the myapp target does not?
I have finally figured out the problem.
After searching for a while, I came across this document:
WixUI_InstallDir Dialog Set
The relevant part: "The directory ID must be all uppercase characters because it must be passed from the UI to the execute sequence to take effect."
And as you can see in my code: "Myapp_Installer_Dir" does not meet this criteria.
After changing it to "MYAPPINSTALLERDIR", everything worked.
I'm not quite sure, but this is what I think has happened.
When you author a SetDirectory element, you basically add a custom action which sets a directory to the MSI database. As long as you do not specify the sequence it is executed in, it defaults to both, which means execute in both InstallUISequence and InstallExecuteSequence.
Now, when a user changes the installation directory in the wizard, this happens in the UI sequence. Obviously, when the installation enters the execute sequence, the value of INSTALLFOLDER is set to [WindowsVolume]Myapp as it was instructed.
So, you have to rework this somehow. Keep in mind the silent installation as well - there's only execute sequence there.
UPDATE instead of what you have, try something like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="WindowsVolume">
<Directory Id="INSTALLFOLDER" Name="Myapp">
<Directory Id="BIN" Name="Bin" />
<Directory Id="ICONS" Name="Icons" />
</Directory>
</Directory>
</Directory>
And let the user optionally change the INSTALLFOLDER as you do now.
Additionally to the pitfall with capital letters there is also an other one:
You have to mark the ID of the changeable directory as secure. (At least when the setup runs with admin rights.)
Related to Yonatan's answer with the directory ID MYAPPINSTALLERDIR you have to add this:
<Property Id="MYAPPINSTALLERDIR" Secure="yes" />
Related to the example WixUI_InstallDir in the WiX documentation you have to add this:
<Property Id="TESTFILEPRODUCTDIR" Secure="yes" />
Unfortunately this important fact is not mentioned in the WiX example.
I have a default directory for installation:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLFOLDER" Name="$(var.Manufacturer) $(var.ProductName)"></Directory>
</Directory>
</Directory>
During installation, I allow users to change directory. If a user does change directory during major upgrade, do I have to retrieve the directory manually and set INSTALLFOLDER with actual path or is there a way to detect it automatically somehow?
This is not supported by Windows Installer directly; I think you're looking for the "remember property" pattern. The strategy is:
On initial installation, save the value of INSTALLFOLDER to the registry in a well-known location.
When starting an upgrade, retrieve the value from the registry and use it.
The authoring looks like this:
<!-- Retrieve the property from the registry during AppSearch -->
<Property Id='REMEMBERME'>
<RegistrySearch Id='RememberProperty'
Root='HKCU'
Key='SOFTWARE\My Company\My App'
Name='Remembered'
Type='raw' />
</Property>
<!-- Save the value in the registry for future upgrades -->
<Component Directory='INSTALLFOLDER'>
<RegistryValue Root='HKCU'
Key='SOFTWARE\My Company\My App'
Name='Remembered'
Value='[REMEMBERME]'
Type='string' />
</Component>
Rob Mensching's blog post describes this in much more detail.
I've been using Wix 3.5 with WixVSExtension to install project item templates for Visual Studio 2010, Visual C# 2010 Express and Visual Web Developer 2010 Express. I'd like now to add support for Visual Studio 11 Beta.
I added registry search and custom actions to find the VS11 installation folders but, when specifying directory and components structure, I'm getting compilation errors like this one:
error LGHT0204: ICE30: The target file 'ewa5nwrn.zip|BasicApplication.zip' is installed in '[TARGETDIR]\CSharp\' by two different components on an LFN system: 'VS2010CSharpProjectTemplates' and 'VS11CSharpProjectTemplates'. This breaks component reference counting.
I have this directory structure:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="VS2010_PROJECTTEMPLATES_DIR">
<Directory Id="VS2010_PROJECTTEMPLATES_CSHARP_DIR" Name="CSharp">
</Directory>
</Directory>
<Directory Id="VS11_PROJECTTEMPLATES_DIR">
<Directory Id="VS11_PROJECTTEMPLATES_CSHARP_DIR" Name="CSharp">
</Directory>
</Directory>
</Directory>
Notice that I have VS2010_PROJECTTEMPLATES_DIR and VS11_PROJECTTEMPLATES_DIR inside TARGETDIR. The error message shows that they are ignored.
The components are defined as follow:
<DirectoryRef Id="VS2010_PROJECTTEMPLATES_CSHARP_DIR">
<Component Id="VS2010CSharpProjectTemplates" Guid="{0976A222-8243-40F2-81AB-84D8F1771840}" Transitive="yes">
<File Id="VS2010BasicApplication" Source="BasicApplication.zip" />
</Component>
</DirectoryRef>
<DirectoryRef Id="VS11_PROJECTTEMPLATES_CSHARP_DIR">
<Component Id="VS11CSharpProjectTemplates" Guid="{A70428F1-AE26-4B07-9F58-D67587B44657}" Transitive="yes">
<File Id="VS11BasicApplication" Source="BasicApplication.zip" />
</Component>
</DirectoryRef>
Is it possible to install the same file into two different directories specified by properties?
Thanks in advance,
aalmada
I don't have any source code to share but I can tell you in general how I've done this in the past.
We decided to "install" the zip files to our main application directory in a Integration folder so that the files would always be available even if VS2008 and/or VS2010 had not been installed at the time of installation. I then used a bunch of built-in properties that exist in the Util extension and a couple custom RegLocator searches to define a bunch of properties related to the location of devenv.exe and ItemTemplate, ProjectTemplates and other directories that we needed in .NET. I then used those properties in CopyFile elements so that MSI would duplicate those files in the Integration folder to the actual VS directories as needed and approriate. Finally I used the WiX QuietExec custom action to call Devenv /setup to register the content with VS. I also used the ProgressText element ( ActionText table ) to make the UI look good while this was all happening as VS devenv can take awhile.
As explained in the wix documentation of the Directory element: when you omit the Name attribute you are creating an alias for the parent Directory element.
This is done by recording "." as the directory name in the installer database, as explained in the windows installer documentation for the Directory table.
In your case, I believe you attempt to change this "." value into a real directory name by setting the VS2010_PROJECTTEMPLATES_DIR and VS11_PROJECTTEMPLATES_DIR properties (because directories are properties) during the installation.
That's fine, but the problem here is that the light linker doesn't know what values you will set these properties to during the installation. It only has the Name attribute value to work with. And at link time, it looks like you are installing the same file twice to the same directory.
To fix this, add Name attributes with different placeholder values to the VS2010_PROJECTTEMPLATES_DIR and VS11_PROJECTTEMPLATES_DIR directory elements.
I ended up adding two base directories, under TARGETDIR, with the Name properties set:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="VS2010" Name="VS2010">
<Directory Id="VS2010_PROJECTTEMPLATES_DIR">
<Directory Id="VS2010_PROJECTTEMPLATES_CSHARP_DIR" Name="CSharp">
</Directory>
</Directory>
</Directory>
<Directory Id="VS11" Name="VS11">
<Directory Id="VS11_PROJECTTEMPLATES_DIR">
<Directory Id="VS11_PROJECTTEMPLATES_CSHARP_DIR" Name="CSharp">
</Directory>
</Directory>
</Directory>
</Directory>
Here is the code for the properties (based on the WixVSExtension code):
<Property Id="VS11DEVENV" Secure="yes">
<RegistrySearch Id="VS11DevEnvSearch" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\11.0\Setup\VS" Name="EnvironmentPath" Type="raw"/>
</Property>
<Property Id="VS11_ROOT_FOLDER" Secure="yes">
<RegistrySearch Id="SearchForVS11RootPath" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\SxS\VS7" Name="11.0" Type="raw"/>
</Property>
<Property Id="VS11_PROJECTTEMPLATES_DIR" Secure="yes">
<RegistrySearch Id="VS11DevEnvForProjectTemplatesSearch" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\11.0\Setup\VS" Name="EnvironmentDirectory" Type="raw">
<DirectorySearch Id="VS11ProjectTemplatesPathSearch" Path="ProjectTemplates" Depth="1" />
</RegistrySearch>
</Property>
<Property Id="VS11_ITEMTEMPLATES_DIR" Secure="yes">
<RegistrySearch Id="VS11DevEnvForItemTemplatesSearch" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\11.0\Setup\VS" Name="EnvironmentDirectory" Type="raw">
<DirectorySearch Id="VS11ItemTemplatesPathSearch" Path="ItemTemplates" Depth="1" />
</RegistrySearch>
</Property>
<CustomAction Id="VS11InstallVSTemplates" Property="VS11DEVENV" ExeCommand="/InstallVSTemplates" Execute="deferred" Return="ignore" Impersonate="no" />
I then found out that the VS2010 templates don't expand correctly under VS11 but that's a different question now... :-/