What is the purpose of the Source attribute? Have a look at this snippet:
<Component Id="MyComponent" Guid="123456789-abcd-defa-1234-DCEA-01234567890A">
<File Id="myFile" Name="myFile.dll" Source="myFile.dll"/>
</Component>
Since Name and Source have the same value, what does Source add? The code does not compile without it.
Where can I find documentation that explains these attributes? I have tried MSDN for MSI but did not find an answer.
Thanks.
WiX and MSI are not the same. Hence no reference in the MSDN documentation ;)
You need to refer to WiX.CHM where you installed WiX, or the online WiX documentation.
Assuming you're talking about File/#Name and File/#Source, this is optional if your source files are laid out in the same way as your WiX directory structure.
The nifty part comes in when you use multiple -b arguments to light and SourceDir in the File/#Source attribute. For example...
<File Id="example.dll" KeyPath="yes" Source="SourceDir\example.dll" DefaultLanguage="0" />
I usually specify 4 folders with -b in my standard build. One for various installer specfiic resources, one for where I store merge modules, one for common resources between all my installs and one for my source files. Now WiX will look in every directory specified on the command line, which makes things a lot more portable if I'm building on a different system with a different directory layout.
As per the documentation, if (in your example) myfile.dll was in the current directory, you could omit the File/#Source attribute.
File/#Source provides the location to get information about the file (size, language, hash) and to copy it to the correct location (either in a cabinet or laid out in a directory relative to the MSI file).
File/#Name is optional if you do not want to install the file with a different name. In other words, if the file exists with the right name on your build machine, just refer to it using the File/#Source and leave off File/#Name.
File/#Id is also optional as long your file name is unique. You cannot have two files with the same File/#Id so add File/#Id when you have collisions.
In WiX v3.5 I often just do:
<Component>
<File Source="my.exe"/>
</Component>
Related
I'm currently trying to make a library with several variable definitions I can use in different Setup Projects but without success.
I have several huge *.wxs files which are build into a library where the File/#Source should depend on project settings. The reason for that is our internal directory structur which looks like any\path\Redistributables\In-Test\X64\productA or any\path\Redistributables\RC\X86\productA so the last 2 parts of my path should change e.g. on x64 and x86 build.
Now I have several Setup Projects too which uses the same path but working in another subdirectory e.g Redistributables\In-Test\X64\AnyOtherProductB.
I dont want to pass preprocessor variables with the same values to each project because the path could change later and I would have to edit too many project settings then.
So my question:
Is it possible to build something like a "Variable/property Container" with public variables/properties so I could just reference that library to use the variables defined in it for my <component><file source...>?
I've tried to achieve that with prepocessor variables before $(var.sourcedir)$(var.compilemode)$(var.platform) with no luck. These 3 are the parts I need to define once to use them in nearly all projects.
Small edit here, I do this a lot where I read the question quickly and make an answer then reread the question and think my answer doesn't quite fit the question but in this case I hope it is still helpful and maybe one of the other resources referenced here will help as well.
Ah I did something like this and banged my head against the wall for a while trying to figure it out.
The problem is you can't use variables like $(var.sourceDir) in the wixlib and then change it later on when you use the lib in a project. What happens is the compiler replaces $(var.sourceDir) in your wixlib with the actual value of this variable when you build it. You can verify this by opening up your obj file and looking for a component or something that uses this directory and see that it has the value of the sourceDir variable not $(var.sourceDir).
To solve the issue we are going to use bind/wix variables (not sure of the terminology) which get evaluated at linking time.
This was the "how to" that I eventually got to which helped me a lot
So, update your variables to something like this !(bindpath.SourceDir)
<Fragment>
<util:RegistrySearchRef Id="MSVCPPRedist_x64_12"/>
<PackageGroup Id="MSVCPPRedist_x64_12">
<ExePackage
Id="MSVCPPRedist_x64_12_0_21005"
Cache="no"
Description="Visual C++ 2013 Redistributable needed for [WixBundleName]"
DetectCondition="MSVCPPRedist_x64_12 OR NOT VersionNT64"
DisplayName="Prerequisite - Visual C++ 2013 Redistributable (x64)"
InstallCommand="/install /quiet /norestart /log vc12log.txt"
PerMachine="yes"
Permanent="yes"
SourceFile="!(bindpath.PrerequisitesDir)VC++\vcredist_x64_12.exe"
UninstallCommand="/uninstall"
Vital="yes"/>
</PackageGroup>
</Fragment>
And then in some props file or project file on the build machine you can include something like this:
<LinkerAdditionalOptions>-b "PrerequisitesDir=$(PrerequisitesDir)\"</LinkerAdditionalOptions>
Where the $(PrerequisitesDir) property was set based on a relative path in a msbuild file on the build machine like so (or use absolute path is also fine):
<!-- Directories -->
<PrerequisitesDir>$(MSBuildThisFileDirectory)..\..\..\Installers\Prerequisites\</PrerequisitesDir>
Now when you build the linker phase will use the build time defined bindPath to find the source files.
In regards to the platform and configuration vars, I think you can use WixVariables referenced as !(wix.VariableName) but I'm not sure off the top of my head and without more experimenting myself. You can take a look at this answer here to help get more acquainted with the different types of variables. If WixVariables don't work you can just build several flavours of yoru wixlib and reference the appropriate one in your wixproj themselves by using the MSBuild properties $(configuration), ect.. in the hintpath of the wixlib file.
I need to include all the output from some of the programs projects in the installer... my question is similar to the one in this post: How to add a whole directory or project output to WiX package
However, I am afraid I don't really understand the answer given in this link. From all the reading I have done, I think I need to use Paraffin to do this. But is there a "start from the very beginning, how-to" resource for using paraffin?
I have read this page: http://www.wintellect.com/CS/blogs/jrobbins/archive/2008/12/22/paraffin-3-0-now-with-full-wix-3-0-support.aspx
and one of the posts mentions calling paraffin from a bat file. Is this how one would "use paraffin" in their installer? If it makes a difference, I have been using Visual Studio to work on this project, and am also not sure how to use command line from within Visual Studio. Does anyone have any resources for a very new beginner? Thanks.
I ended up including each .dll and .exe manually, since they don't change very often. It was fairly easy to format them in this style:
`<File Id="WhateverId" Name="NameToDisplayAfterInstall" Source="$(var.ProjectName.TargetDir)Filename.ext" />`
I used Excel to format a list of files quickly and easily. I put all of these File tags in the <DirectoryRef Id="INSTALLLOCATION">
tag.
I did figure out how to scrape all the dlls and exes from the project output by using Heat (not paraffin) and harvesting a directory, not a project. Harvesting a project yields only the main exe and dlls. The problem with harvesting a directory, at least in my case, is that I ended up with a lot of excess files, (like .pdb and .xml) that I didn't want.
I've got one customer specific file added to my WiX project like that:
<Component Id="IMPORT" DiskId="1" Guid="xxxxx">
<File Id="IMPORT" Name="Import.xml" Source="..\..\config_customerA\Import.xml"/>
</Component>
The rest of the file is the same for all customers.
Right now I have one Wix project for each customer. The project Wix file is all the same, only the above lines are changed according to the customer. I don't like this solutions because of all the redundancy and duplication (DRY principle...).
How do you solve this dilemma?
Would be nice to use one Wix file and only change the link to the specific customer file.
Three possible approaches...
1) Make this a build issue not an installer issue. Leave the WXS alone and have the build automation copy the correct XML file into scope when building the MSI.
2) abstract the path of the XML file using a preprocessor statement and pass the path into the build so that the WXS dynamically points to different XML files at build time.
3) Identify "what" is different about the XML and use the XML Changes capability to transform the base XML to the customer specific XML at installtime. For example, let's say that the XML file is different except some key/value pair has a value with the customers name. Use a proprocessor statement to define a variable for customers name and pass the customers name into the build. Use the preprocessor statement so that a property gets the customers name. Then use the property in an XmlConfig element to apply the customers name to the key value attribute in the XML file.
One possible approach is to package your XML file as 'loose' (not in the embedded in the msi). You'll need a separate Media element and reference it with the DiskId on the File element. Then, you have a single msi file that references the external file so you're free to change the XML file for each customer.
I've done this in one of my projects and it works. Whether this works for you depends on your requirements. One downside is that this isn't very download friendly since you now have two files instead of a single msi.
Using WiX (Windows Installer XML) I have created an MSI installer which installs Word templates into the users Application Data folder, e.g. on Windows XP
C:\Documents and Settings\<user>\Application Data\Microsoft\Templates
I'm retrieving the path to this folder from the registry:
<Property Id="APPDIR" Secure="yes">
<RegistrySearch Id="RegSearch_AppData"
Type="directory"
Key="Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
Name="AppData"
Root="HKCU" />
</Property>
<CustomAction Id="ActionWordTemplateFolderAssign"
Property="TEMPLATEFOLDER"
Value="[APPDIR]Microsoft\Templates" />
<InstallExecuteSequence>
<Custom Action="ActionWordTemplateFolderAssign" Sequence="1" />
</InstallExecuteSequence>
However, some users installing the MSI file on Windows Vista receive an error because the APPDIR property is empty.
Is APPDIR not the correct way to retrieve the Application Data folder? Or do I have to consider another property on Vista?
EDIT: This is just a short version of the WiX Code to retrieve Word's template folder. First I'm actually checking whether the user has a custom template folder defined by a policy or under HKCU\Software\Microsoft\Office\12.0\Common\General\UserTemplates. However, if none of these are set the fallback is to use the default location under %APPDATA%\Microsoft\Templates which is retrieved by the above code.
You should use [AppDataFolder] instead. I can't find anything about "appdir" in the windows installer property reference.
Edit after question edit: The shell folders key (great blogpost btw) where you get your appdir value from is a very old and deprecated way to get at the system folders. It is only there for backwards compatibility and you should not rely on it. Especially if you live near Raymond Chen.
Edit 2: Since the real question turns out to be "how do I find the user's word template folder"... The word template folder is not always
[AppDataFolder]\Microsoft\Templates
This is because the template folder can be configured under tools - options - file locations - user templates. Ironically we are back to searching the registry if we want to detect this:
<Property Id="USERTEMPLATES">
<RegistrySearch Id="SearchUserTemplates"
Root="HKCU"
Key="Software\Microsoft\Office\11.0\Common\General"
Name="UserTemplates"
Type="raw" />
</Property>
This registry value is normally not present however, and you cannot specify a default value that contains [AppDataFolder] here (I tried).
Instead, I would try to define two components, one which installs to USERTEMPLATES and one which installs to [AppData]\Microsoft\Templates. You can then make use of Condition elements to test for the existence of USERTEMPLATES, and install only the right one.
Some additional information:
The reference for MSI properties containing special folders:
http://msdn.microsoft.com/en-us/library/aa370905(VS.85).aspx#system_folder_properties
And a link to a related blog post:
What is the WiX equivilent of Environment.SpecialFolder.ApplicationData from .NET?
Divo - In response to your comment on localized Vista installations, the problem probably isn't so much localized Vista (unless I'm reading you wrong) but localized Office.
Microsoft\Templates might become Microsoft\Vorlagen with German office for example. It's a pain in the ass, because I haven't found a reliable source of documentation on what folder names have been localized in Office, and what haven't.
My particular problem was with installing Macros to [AppDataFolder]Microsft\Word\STARTUP - which is localized for some languages only. #$%# in the end we just get customers to manually move the templates, the majority of our markets don't have a problem but we've noticed Italian and Turkish office plus a couple of others seems to exhibit this rather annoying behaviour.
On Vista there is a new standard folder available called TemplateFolder. I think that is what you want. To use it in WiX just do something like:
<DirectoryRef Id="TARGETDIR">
<Directory Id="TemplateFolder" Name="Templates"/>
</DirectoryRef>
Then you can reference the TemplateFolder Directory where ever you may need it.
I have a question regarding the commandline options of msbuild. I am
currently using msbuild to build projects using the existing solution
files. These solution files have references to external dll which have
different paths on each machine. I am currently writing a build script
and passing the specific path to the project file via the /p: switch of
msbuild.
My current build line is:
msbuild test.sln /p:ReferencePath="c:\abc" /p:ReferencePath="c:\rca"
What i have noticed that Reference Path now contains only c:\rca and
not c:\abc. this is causing problems for me since, the external dlls
lie in two different directorys. I am allowed to keep multiple
reference paths via visual studio, but not via the commandline.
Is there any known way by which i can do this
I believe you can use this /p:ReferencePath="c:\abc;c:\rca"
At least that is what that link is hinting at, they are using %3B to encode the ";" within the build file.
Although the correct syntax for providing more the one reference path is listed above, I would suggest solving the root cause which in my opinion is the different locations of your referenced assembly. I would suggest you put all thirdparty dependencies, apart from the framework assemblies in your source code repository for the following reasons:
Relatitve paths are consistent across computers
The source code is always in sink with the correct version of your thirdparty assembly (if you for instance need to build an old version of your software 2 years from now).
Upgrading your thirdparty assembly is as easy as upgrading on one machine and then committing your changes to the repository. (In a previous project we even went as far as checking in the entire java runtime environment and were quite happy with the given setup.)
Try seperating your pathes with a semi-colon (;)
Like this:
c:\abc;c:\rca
You may be better off by synchronizing your libraries across machines. I have found that Visual Studio makes this easy. Simply add a solution folder, and add your libraries there. Then, in each project, reference the libraries from this common place. This way, each developer has them in the same place.
This will remove one of variables you have when trying to script out builds.
The command line options for setting the reference path will work just fine (assuming you escape the semi colon, it seems both %3B and ; will work). However, when the argument was passed in from nant (and I needed multiple paths), creating a 'Visual Studio Project User Options file' seemed to work better.
I just emit (echo) a file to the file system with the following format:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ReferencePath>
C:\abc;c:\rca
</ReferencePath>
</PropertyGroup>
I give the *.user file an appropriate name (given a project file MyProject.csproj, my user file would be MyProject.csproj.user)