I'm writing a few WiX files today and there's a lot of repetitve typing involved, so it looks to me like Resharper's Live Templates would be very useful here. Does anyone know of any?
I know it's not too hard to write new Live Templates so I may end up answering my own question in a couple of hours, but if anyone can point me to pre-exisitng ones that would be great.
As an aside any other WiX editing tips would be appreciated:-)
I actually only needed a couple of very simple ones...
For creating file components:
<Component Id="C_$COMP_ID$" Guid="$GUID$">
<File Id="F_$FILE_ID$" Name="$FILENAME$" />
</Component>
I wired up $GUID$ to the "generate new guid" macro.
Then an even more simple one for creating directory entries:
<Directory Id="D_$DIR_NAME$" Name="$NAME$" />
The handy thing I found with the Live Templates was the ability to assign one of the fields to the clipboard value, so when adding a new file I could highlight the file's name and ctrl-C it to the clipboard and then run the template, but it only saves an tiny bit of typing.
I'll probably write a few more next time I'm editing WiX files, I'd be happy to share but they are so easy to write and customise to personal preference I'm not sure there's going to be a huge demand:-)
Are you using Votive? because then you get InteliSense when working on wxs.
if you are not using Votive then you can put the Wix XSD into Visual Studio XSD repository to get InteliSense.
Related
My ultimate goal here is to have an MSI that puts a bunch of folders and files where they need to go, and install CouchDB. Given all the dependencies and such, this is 1000+ files in a folder structure. I've gone through the Wix tutorial on firegiant's site, and I understand that the .wxs file needs to be put together correctly. I've tried scraping what I have with Heat to try to get this to work, and while I've been able to actually produce an MSI, it doesn't work and throws error 2728.
How do people normally put together an initial .wxs file for a brand new product that didn't involve Visual Studio? I can't tell if I'm missing key Heat parameters or if this is actually done by hand, which sounds insane.
I am someone with little to no experience with wix and I am trying to support Windows also for the component I am responsible for. I am trying to create merge module for a set of files that my product generates. These files exist in numerous sub directories. I was wondering how I can create a single component ID for all the files in the entire tree. I am not worried about minor upgrades as that is something I am not going to be doing. I am trying to avoid generating numerous GUIDs for each of the file.
Also is there any way I can change the name of the root directory I want the files to be installed. Currently, in our build system the files I want to install end up in a directory name "install". In the wxs file generated by heat it comes up as install. I was wondering if I could change it to the actual product name instead of "install".
Use one file per component - this avoids all sorts of problems (except .NET assemblies spanning multiple files). See the following thread: One file per component or several files per component?
Wix is a great framework for creating installers, but it has a steep learning curve. I strongly recommend you read a few sections of this great, online tutorial: https://www.firegiant.com/wix/tutorial/
If you are a "sample based tinkerer", you can find an even quicker, sample based tour in this article: http://www.codeproject.com/Tips/105638/A-quick-introduction-Create-an-MSI-installer-with
Wix is hands-on. Just focus on the samples, and focus on getting the components created and a major upgrade set up:
How to implement WiX installer upgrade? (modern, convenience way)
How to get WiX major upgrade working? (legacy way - more flexible, less convenient)
http://wixtoolset.org/documentation/manual/v3/howtos/updates/major_upgrade.html
Once you got that running the rest of the details fall into place by reading the documentation for whatever feature you need. Using Visual Studio / Votive with intellisense ensures that you can learn as you go with features such as shortcuts, ini files, xml files, dialogs, etc...
Another top tip is to use dark.exe (part of the Wix toolkit) to decompile existing MSI files. This yields Wix XML with code you can copy and paste into your own Wix files. I use other MSI tools to compile such MSI files, and then copy the sections I need into my Wix file - just to speed up the process of creating the Wix XML. Studying the decompiled XML is very educational - a real time saver.
UPDATE, May 2021: Some more links:
WiX Quick Start - Very long version
WiX Quick Start - Short version
If all the files are going to the same destination folder, then you can create one single COMPONENT with all the FILE within it. There is nothing stopping you to do that. You can then just create one GUID for that component. Also read these answers which talks about the advantages vs disadvantages of one component vs multiple components before you implement it: Answer1 Answer2. To Summarize:
You will have trouble with minor upgrades/repairs. If a component is
being updated, only the file designated as the KEYPATH is checked to see if
it is out of date: if it is up to date, all the others are ignored.
You'll also have difficulty if you want to add or remove files from each
component. Once released, a component is immutable (in terms of what files
are in it). The only way to update it without breaking component rules would
be to effectively remove and install the a new version of the MSI.
Understanding the component rules is key in Windows Installer and one file
per component makes the component rules easier to work with, which is why it
is the recommendation of many people here.
LINK
The root directory name can be changed by modifying the "Name" property for the DIRECTORY element.
I have a C# project which is built in a few different configurations. Some of the source files should be always included, and some only in certain configurations. So far I've been doing this with #if ... #endif around the entire files, but I was hoping to create a small extension to do this a nicer way.
I've created an extension that adds an item to files' context menus, but I can't find any way to set the Condition attribute on the item node in the project file.
I've looked at the Properties collection of the EnvDTE.ProjectItem interface, but can't see anything useful there (except BuildAction... I'll come back to that).
Then I tried getting an IVsBuildPropertyStorage on the item and calling SetItemAttribute(). This does add information to the project file, but as a child element like this:
<ItemGroup>
<Compile Include="Program.cs">
<Condition>%27%24%28Configuration%29%27==%27Debug%27</Condition>
</Compile>
</ItemGroup>
when what I was trying to achieve was:
<ItemGroup>
<Compile Include="Program.cs" Condition="'$(Configuration)'=='Debug'" />
</ItemGroup>
There's also an IVsBuildPropertyStorage.SetPropertyValue() but that adds a similar child element to a PropertyGroup section near the top, not to the item node.
I've looked at 'Project Subtypes/Flavors', but that looks like it's just going to get me another IVsBuildPropertyStorage, which doesn't seem to be useful. They do look capable of a lot of complex things, but documentation on the subject appears to be minimal and vague.
I've seen some posts describing how to use the MSBuild assemblies to directly load and manipulate the project file, but I'm not sure when is safe to do that without confusing Visual Studio and potentially losing changes, since VS prompts to reload when it detects changes to the project file.
As a last idea, I thought about manipulating the BuildAction property between Compile and None, but that sounds like it could be a lot of work for my extension to maintain correctly, keeping it in sync with every time the user switches configurations in the IDE for example.
Is there anyone with any experience with this kind of thing that has any advice to offer me, or should I give up hope and stick with manually adding #if directives everywhere?
You may like to explore the MSBuild option you mentioned.
You don't actually have to load the MSBuild project from file, because Visual Studio gives you a way of accessing the MSBuild project directly, i.e.:
string projectPath = projectItem.ContainingProject.FullName;
MsBuildProject project = ProjectCollection.GlobalProjectCollection.GetLoadedProjects(projectPath);
var compileItems = project.GetItems("Compile");
From there you can locate your specific items and potentially add the condition attribute, though I haven't tried this step myself (if this doesn't work, you might have to try modifying the project elements under the project.Xml property instead).
You can then call project.Save(), which shouldn't trigger the "Reload project?" dialog because of the way the MsBuild project instance is linked to the Visual Studio project hierarchy.
However, you may like to force Visual Studio to reload the project anyway, because if you switch build configurations (e.g. between Debug and Release), the MSBuild engine may not re-evaluate your item conditions during build. The code to do this programmatically can be found here:
How do I programmatically refresh/reload a VS project after modifying the underlying file?
Unfortunately I never got the time to persue the original goal of creating an extension for doing this, however I did achieve what I needed using the suggestion by lex-li: using separate project files per configuration.
Since the project files can all reside in the same directory, it's easy to simply use the 'Include/Exclude from project' context menu item in the solution explorer to choose which files are included. There's also no need for file linking this way, which I'd tried before and found very time-consuming to manage.
Partial Methods are also worth looking at, if you have similar needs. They allow you to define the signature of a method in one place, but optionally implement it elsewhere. If you don't implement it, no call is generated by the compiler.
With respect to the original idea of the extension, I suspect the answer by Daniel Nolan was heading in the right direction, but unfortunately I didn't get to try it out.
I am using heat.exe available in WiX3.5 to get the list of components and componentref for the files I want to install. However, for the file which should be installed as windows service, I dont want it to be generated by heat.exe as I need to add <ServiceInstall> etc.
I dont want to put the <serviceinstall> in xslt as it would make it very ugly code. Right now, I delete the exe before running heat.exe and then copy it back, but this is also not ideal. Is there a better way of doing this?
I would say that tweaking the heat output with XSLT templates is a kind of recommended approach. Although heat is not that rich in features to consider cases like you mentioned, its ability to apply XSLT to the output covers all possible needs.
Why do you think the code will be ugly? Do you reference the XSLT syntax here or the idea to tweak wxs file in general? Anyway, this piece of code won't change that much, I guess. And once you code it thoroughly and debug it, it won't take much of your time in future.
In the spirit of this question by Si here: WiX tricks and tips. I am trying to determine the best way to get create wix fragments based on a directories. File harvesting, so to speak. For example under the bin\release folder I could have many different folders plus files that I want to capture very easily in fragments. I have been doing this by typing them or using wixedit.
Please note I haven't tried anything just done the reasearch here:
A)I read a little bit on heat.(http://installing.blogspot.com/2006/04/heatexe-making-setup-easier.html) I am not sure though about running it from msbuild?
B)I found this blog article from Newagesolution which discusses using t4 script: http://blog.newagesolution.net/2008/06/how-to-use-msbuild-and-wix-to-msi.html
I would like to know what others are doing to solve this.
Regards, Brian
Ok, Daniel I definately agree with using heat, but I think Rob pointed me in the right direction for what I ended up using.
What I ended up using was HeatDirectory.(Please note, I do not plan on doing patching. If you want patching, you may want to look at another solution, but heat/heat directory can work for patching.) Unfortunately, Rob's answer was quite limited, so I wouldn't say that he really answered my question. Just pointed me in the right direction. Thanks to both Rob and Daniel for your help.
Therefore, I came back and answered this question myself.
Hurdles...
Hurdle 1
I ran into is there is nearly no documentation on the web for how to implement heat tasks/heat directory(Heat wrapped in msbuild) from within visual studio. Please note that the wrapper to run from msbuild appears to be pretty new and I disclaim to use at your own risk, etc. Because of the lack of documentation, I sent an email to the wix user list. I received help from Brian Rogers. Thanks Brian, this solved everything for me. Take a look at his great blog entry here for a better understand how heat is going to help you automate: http://icumove.spaces.live.com/blog/cns!FB93073C6534B681!461.entry
Hurdle 2
After working with heat, I found out that I was not using components the recommended way, but I had to piece together all the reasoning. I think many people will run into this in the beginning of using Wix if you don't have prior knowledge of windows installer. Therefore I recommend some reading:
Make sure you read component rules as well if you are a novice like I was with Windows Installer.Component rules from MS: http://msdn.microsoft.com/en-us/library/aa370561.aspx. Read these from Rob Mensching for a better understanding of components: http://robmensching.com/blog/posts/2003/10/4/Windows-Installer-Components-Introduction
http://robmensching.com/blog/posts/2003/10/18/Component-Rules-101
For Extra Reading on Windows installer check these rules from the windows installer team(Rule 16: Follow Component Rules):
http://blogs.msdn.com/windows_installer_team/archive/2006/05/12/595950.aspx
Hurdle 3
You must decide whether or not you want to do patching of your files or upgrade everytime you install a new version.
I fortunately do not need to do patching, therefore for every upgrade I will just uninstall the previous version like this: How to implement WiX installer upgrade?.
This simplifies things greatly. When patching you are going to need full control over things. Something that is more difficult when you want automation/automatic building for by many developers that do not know anything about wix other than wix builds msi fields. It seems that this will work with using heat, but I am uncertain.
Hurdle 4
For me it took a little time to figure out why the include file with my preprocessor variables was not working. I finally figured it out. You must include the file in your .wxs file like this:
See here for more details:
Include a text file content into a WiX script
http://wix.sourceforge.net/manual-wix2/preprocessor.htm
Hurdle 5
Since I am using major upgrades with mix and I wanted to hook in subversion into my product number. This I thought would be quite simple and it is if you know how to do it. I had trouble here and had to get help for this as well.
Hurdle 6
With heat updating the files based on a bin folder everything works quite well. Well almost automatic, if there are any conflicts in dll references, etc then files will not be included in the installer and therefore things might not run properly. You need to have a testing process in place so as to test your program after installing. This can be critical if you miss a dll. I would also recommended that you keep track of the program's used dlls and compare against the msi file.
Now for the solution using HeatDirectory(from the help of Brian Rogers(wix team)):
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == ''">Debug</Configuration>
<OutputName>msbuild.heatfile</OutputName>
<OutputType>Package</OutputType>
<WixToolPath>..\..\YourHeatDir</WixToolPath>
<WixToolPath>$(WixToolPath)</WixToolPath>
<Cultures>en-us</Cultures>
<LinkerBaseInputPaths>..\..\data\HeatDir</LinkerBaseInputPaths>
</PropertyGroup>
<ItemGroup>
<Compile Include="product.wxs" />
<Compile Include="TestDir.wxs" />
</ItemGroup>
<Import Project="$(WixToolPath)\Wix.targets" />
<UsingTask TaskName="HeatDirectory"
AssemblyFile="$(WixToolPath)WixUtilExtension.dll" />
<Target Name="BeforeBuild">
<HeatDirectory
Directory="..\..\data\HeatDir"
DirectoryRefId="DataDir"
OutputFile="TestDir.wxs"
AutogenerateGuids="true"
ToolPath="$(WixToolPath)" />
</Target>
This needs to be pasted into your project file and appropriate settings/pathing needs to be changed. What this will do is take all the files in the path you specify
and create a TestDir.wxs file which you then can reference by component group. There are several Heatdirectory options see you need to see the heat sourcecode for details.
Just for reference: I found this post on stackoverflow after I posted my question: How to add a whole directory or project output to WiX package
Also for reference I just saw this article here: Harvesting a .csproj with heat.exe in Visual Studio 2008 and WiX(v3). and again this can be done using heat tasks instead.
Both discuss using third party tools. One called Mallow and another called Paraffin. I think paraffin looks supported and can do pretty much what heat does.
With a few additions: See here for details: http://www.wintellect.com/cs/blogs/jrobbins/archive/2007/10/18/wix-hints-for-new-users-part-1-of-3.aspx
Anyways hope this helps others.
The new HeatTasks might work very well for you here. They can pull project output groups from other projects in Visual Studio. It does much better in the latest build than older builds, so be sure to pick up a weekly http://wixtoolset.org/releases/.
For what it's worth, we are, in fact, using heat.exe from msbuild. If you're as picky as I am, the output of heat is probably not exactly what you want, but this is easy to rectify with an XSL transformation (I believe heat.exe has a command-line parameter expressly for this purpose).