WiX: A Better TALLOW – PARAFFIN (Part 3 of 3)

82 Comments October 21, 2007

In the first installment of this series I discussed an introduction to WiX. In the second installment, I talked about the issues related to creating .WXS files with TALLOW.EXE and how you have to manually maintain those files by hand, which can be tedious to the extreme. In this final installment, I will present a tool I wrote to solve those problems.

Since all the binaries' names in WiX all play on parts that make up a candle, I knew I was going to have to continue the tradition. With my goal of replacing TALLOW.EXE (rendered beef or mutton fat and rarely used to make candles any more), I named my program PARAFFIN.EXE (a petroleum byproduct and what most candles are made out of in the modern world).

My goal for PARAFFIN.EXE was that it would build immediately consumable WiX fragments with a minimum of fuss on your part. I wanted PARAFFIN.EXE to meet the following requirements for initially creating a .WXS fragment for a directory:

  • PARRAFIN.EXE created unique values to the Component, Directory, and File elements Id attribute so you do not have to worry about conflicts across large projects
  • PARAFIN.EXE creates a ComponentGroup element in the output file with all Component elements in the file automatically specified with ComponentRef values
  • You can optionally exclude specific file extensions from being added to the .WXS fragment
  • You can optionally exclude directories from inclusion by specifying a partial name
  • You can optionally specify if you want GUID values automatically generated for all components
  • You can optionally specify multiple files per Component (the default is one file per component)
  • You can optionally specify that you do not want to recurse directories other than the one specified
  • You can optionally specify an alias for the directory name when setting the File element Source attribute so you do not have hard coded drive and directory names in the output .WXS file

After you've created a .WXS fragment with PARAFFIN.EXE, you don't want to have to edit the fragment manually, so I wanted PARAFFIN.EXE to meet the following requirements for creating an updated output file from an existing .WXS fragment:

  • The updated output is written to a .PARAFFIN file so the original .WXS fragment is not disturbed
  • All command line options specified when creating the initial .WXS fragment are automatically set when updating a file created by PARAFFIN.EXE
  • Any new directories and files found are automatically added to the output file
  • Any directories and files that are no longer part of the directory structure are removed from the output file

As you can tell from both sets of requirements, PARAFFIN.EXE makes it very easy to create the initial .WXS file and, most importantly, it does as much as is safely possible to provide you a way to avoid all the tedious manual editing of .WXS fragments. Before I get too far into showing how to use PARAFFIN.EXE, I want to reiterate from the previous installment that you can break component rules with PARAFFIN.EXE. While I can't stop you from running PARAFFIN.EXE from your build and creating all your .WXS fragments every time you build, I would strongly recommend you don't do that because you'll have different GUIDs for your components and completely break all component rules. I would also recommend you stay with the PARAFFIN.EXE defaults of one file per component so you can remove a single file without invalidating an entire component. That will make your installs slower than multiple files per component, but it helps you avoid breaking the component rules for large groups of files at a time. Finally, when using PARAFFIN.EXE during the heat of development, it's an extremely good practice to uninstall any previous version of your application before installing the current build. This helps ensure the previous version removed all the files that might have been deleted in the new installation.

Using a small example is probably the best way to show you how to create and maintain WiX fragments with PARAFFIN.EXE. Let's say I have a directory called .\Example with two files in it, HelpFile.chm and ReadMeFirst.txt. I also have a sibling directory of .\Example, called .\Install, where the installation code is build from.

The first step that I'll want to do is to create the initial .WXS file for the .\Example directory with PARAFFIN.EXE. In a Command Prompt window, I'll switch to the .\Example directory and run the following command line (one line):

Paraffin.exe -dir .\ -custom EXAMPLE -g -alias ..\Example –ext .WXS ExampleFragment.wxs

The –dir switch tells PARAFFIN.EXE what directory I want to process. The –custom switch specifies the custom value PARAFFIN.EXE will use to build up the Id attributes for the ComponentGroup, Directory, and File elements for this fragment file. Specifying –g will automatically generate GUID values for all components. The –alias switch will cause .\Example to be substituted for the starting directory in the File element's Source attribute. The –ext switch tells PARAFFIN.EXE to ignore all files with the extension .WXS. Obviously, ExampleFragment.wxs will be the output file. After running the above command, ExampleFragment.wxs looks like the following (note that I wrapped some lines to get them to fit better):

<?xml version="1.0" encoding="utf-8"?>
<
Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<!--
<CommandLineOptions>
  <Producer>Autogenerated by Paraffin -
                    Wintellect - John Robbins -
                    john@wintellect.com</Producer>
  <WARNING>Manual changes to this file may cause incorrect
           behavior.</WARNING>
  <CreatedOn>10/17/2007 6:03 PM</CreatedOn>
  <Directory>.\</Directory>
  <Custom>EXAMPLE</Custom>
  <DirAlias>..\Example\</DirAlias>
  <Increment>1</Increment>
  <Guids>true</Guids>
  <Multiple>false</Multiple>
  <Norecurse>false</Norecurse>
  <ExtensionExcludes>
    <Ext>.WXS</Ext>
  </ExtensionExcludes>
  <DirExcludes />
  <NextDirectoryNumber>1</NextDirectoryNumber>
  <NextComponentNumber>2</NextComponentNumber>
</CommandLineOptions>
-->
  <
Fragment>
    <
ComponentGroup Id="group_EXAMPLE">
      <
ComponentRef Id="comp_EXAMPLE_0" />
      <
ComponentRef Id="comp_EXAMPLE_1" />
    </
ComponentGroup>
    <
DirectoryRef Id="TARGETDIR">
      <
Directory Id="dir_Example_0" Name="Example">
        <
Component Id="comp_EXAMPLE_0"
                   DiskId="1"
                   KeyPath="yes"
                   Guid="DE4C9C18-1B4B-42E0-A199-E530462A7561">
          <
File Id="file_EXAMPLE_0" 
                Name="HelpFile.chm"
                Source="..\Example\HelpFile.chm" />
        </
Component>
        <
Component Id="comp_EXAMPLE_1"
                   DiskId="1"
                   KeyPath="yes"
                   Guid="A5B3009D-93CC-4853-B945-C9D177157997">
          <
File Id="file_EXAMPLE_1" 
                Name="README_1.TXT"
                LongName="ReadmeFirst.txt"
                Source="..\Example\ReadmeFirst.txt" />
        </
Component>
      </
Directory>
    </
DirectoryRef>
  </
Fragment>
</
Wix>

Most of the file is your standard .WXS fragment, but the interesting part is the comment after the start of the WiX element. PARAFFIN.EXE uses that comment element to identify the file as one it produced. If you look through the comment you can see how PARAFFIN.EXE stores the various command line options so it knows what to apply when you update the file. If the comment section is missing or corrupt, PARAFFIN.EXE cannot work with the file.

As development progresses, suppose you add one new file to the .\Example directory, AdvancedHelp.chm, and remove ReadmeFirst.txt. To generate the ExampleFragment.PARAFFIN file with the updates, you'd go back to the .\Examples directory in a Command Prompt and run the following command:

Paraffin.exe -update ExampleFragment.wxs

The ExampleFragment.PARAFFIN file looks like the following:

<?xml version="1.0" encoding="utf-8"?>
<
Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
  <!--
<CommandLineOptions>
  <Producer>Autogenerated by Paraffin -
              Wintellect - John Robbins -
              john@wintellect.com</Producer>
  <WARNING>Manual changes to this file may cause
           incorrect behavior.</WARNING>
  <CreatedOn>10/17/2007 6:21 PM</CreatedOn>
  <Directory>.\</Directory>
  <Custom>EXAMPLE</Custom>
  <DirAlias>..\Example\</DirAlias>
  <Increment>1</Increment>
  <Guids>true</Guids>
  <Multiple>false</Multiple>
  <Norecurse>false</Norecurse>
  <ExtensionExcludes>
    <Ext>.WXS</Ext>
  </ExtensionExcludes>
  <DirExcludes />
  <NextDirectoryNumber>1</NextDirectoryNumber>
  <NextComponentNumber>3</NextComponentNumber>
</CommandLineOptions>
-->
  <
Fragment>
    <
ComponentGroup Id="group_EXAMPLE">
      <
ComponentRef Id="comp_EXAMPLE_0" />
      <
ComponentRef Id="comp_EXAMPLE_2" />
    </
ComponentGroup>
    <
DirectoryRef Id="TARGETDIR">
      <
Directory Id="dir_Example_0" Name="Example">
        <
Component Id="comp_EXAMPLE_2"
                   DiskId="1"
                  
KeyPath="yes"
                  
Guid="6743A4B6-455C-4F75-9B55-86F59C6DFE03">
          <
File Id="file_EXAMPLE_2"
                
Name="ADVANC_1.CHM"
                
LongName="AdvancedHelp.chm"
                
Source="..\Example\AdvancedHelp.chm" />
        </
Component>
        <
Component Id="comp_EXAMPLE_0"
                  
DiskId="1"
                  
KeyPath="yes"
                  
Guid="DE4C9C18-1B4B-42E0-A199-E530462A7561">
          <
File Id="file_EXAMPLE_0"
                
Name="HelpFile.chm"
                
Source="..\Example\HelpFile.chm" />
        </
Component>
      </
Directory>
    </
DirectoryRef>
  </
Fragment>
</
Wix>

As you can see, PARAFFIN.EXE did the right operations and removed the Component and File elements associated with ReadmeFirst.txt, added those for AdvancedHelp.chm, and left all the others alone. Once you've read over the changes in the .PARAFFIN file, you can either do a compare and merge in the changes or just rename the .PARAFFIN file to the .WXS file. If you're looking for an excellent standalone difference and merge tool, I highly recommend SourceGear's outstanding (and free) DiffMerge.

One big hint when using PARAFFIN.EXE is that you should run any updates from the same directory as you did when initially creating it. If you look closely at the comment element for the above files, you'll see that I store the Directory element exactly as it was passed in. I played around with storing calculated values, but would always run into potential hard coded path values. In the end I felt the best solution was to avoid the hard coding.

If you want to see a complete example of a WiX installation that was developed with PARAFFIN.EXE, see the .\Install directory in the code download. That is an installation for the PARAFFIN project itself. I first ran the batch file FirstParaffinRun.cmd to create the fragment files for the .\Install and .\Paraffin directories. As I built up the installation and the code, I ran UpdateParaffinRun.cmd to get any additional files added into my two fragments.

The only requirement for PARAFFIN.EXE is that you have the .NET Framework 3.5 installed on the machine. I built the code with Visual Studio 2008 Beta 2. As you'll see in the next paragraph, there's literally no way I will work with XML again without Linq for XML and the awe inspiring XElement class and friends.

Originally, I started thinking about implementing PARAFFIN.EXE with Visual Studio 2005 and .Net 2.0. As I was struggling through the standard XmlDocument classes, I realized it was going to be quite a bit of work to get everything implemented. Fortunately, Visual Studio 2008 Beta 2 shipped so I could look at Linq as a solution. As I worked my way through some prototyping I realized that Linq and Linq for XML had to be one of the biggest boosts in productivity I've seen in years. According to the new Code Metrics in Visual Studio 2008, there are only 533 lines of code in PARAFFIN.EXE. As an interesting aside, 257 of the 533 lines in PARAFFIN.EXE are related to command line argument processing. My guess is that I would have had at least 1,500 lines of code using .NET 2.0.

Most of the code is straightforward. In fact, it only took me a day to implement the new .WXS fragment creation code. Updating existing fragments took about two days. In looking at the different ways to coordinate walking both the directory structure and the XML structure, I felt it was easiest to simply walk both of them at the same time instead of using any sort of two pass system.

As I enumerate the subdirectories, I use a Linq query to look for the matching Directory element from the current position in the input XML file. Once I have the Directory node, I do a similar operation to look for the files on disk as well as in the input XML file. The biggest method in the project is UpdateFilesInDirectoryNode, (in Main.CS) which does all the work to coordinate between the files on disk and what was in the input .WXS fragment. It's worth reading through the code for that method to see how I used Linq queries for filtering out excluded extensions and looking for a file in the XML document.

PARAFFIN.EXE has certainly made maintaining my WiX installations far easier and I hope it will for yours. While PARAFFIN.EXE has worked for me, I'm sure it could use more testing. Please report any bugs you find, or feature enhancement requests, either as comments to this blog entry or to me directly at john@wintellect.com.

You can download the code and PARAFFIN.EXE here. Please note that you need the .NET Framework 3.5 installed on your machine for PARAFFIN.EXE to work.

Edit May 16, 2009: Updated the Paraffin download link to point to the updated 3.0 version.


82 Comments

  • Gravatar Image
    John Robbins' Blog : WiX: The Pain of WiX (Part 2 of 3) October 21, 2007 8:25 PM

    PingBack from http://www.wintellect.com/cs/blogs/jrobbins/archive/2007/10/19/wix-the-pain-of-wix-part-2-of-3.aspx

  • Gravatar Image
    Jason Haley October 22, 2007 10:08 AM

  • Gravatar Image
    Denis October 22, 2007 2:29 PM

    The link to the download is not working.

  • Gravatar Image
    jrobbins October 23, 2007 12:17 AM

    Denis,

    Thanks! I screwed up the download link. Sorry! It fixed it.

    -John.

  • Gravatar Image
    Christopher Painter October 23, 2007 10:07 AM

    Can Paraffin handle deprecated components? ( I.e. when a file disapears from the directory link a 0 byte file and set the transitive bit with a NOOP condition instead of removing the component element ).

    I need this feature in any tool that I use so that minor uprades will properly remove obsolete files.

  • Gravatar Image
    Scott October 23, 2007 11:18 PM

    How is this different than the mallow tool that was developed a while back (Feb 2005)? In my previous company we were using that instead of tallow for large projects. The original post which describes it is here (http://osdir.com/ml/windows.devel.wix.user/2005-02/msg00115.html)
    , and it is mentioned on the wikipedia article as well.

  • Gravatar Image
    jrobbins October 24, 2007 1:06 AM

    Christopher: I sent you a mail on the WiX User mailing list asking for more information about what you need.

    Scott: Mallow is fine, but it doesn't include the element nor does it have a way to generate unique names for Component and File Id attributes. It almost worked for me, but I really wanted those two features. Also, I wanted an excuse to do a real project with Linq for XML. :)

    - John.

  • Gravatar Image
    Christopher Painter October 24, 2007 7:52 AM

    Checkout http://geekswithblogs.net/Vagmi.Mudumbai/archive/2006/06/11/81426.aspx

    The concept is it's not enough to remove the component because during an upgrade the component would get orphaned and remain forever. You want the new MSI to remember the component and have it uninstall it.

    I need this because I maintain installs that are ASP.NET Websites with thousands of files that frequently change. I want an automated process that keeps up with these changes while not breaking the component rules so that any newer install can upgrade any older install and `it just works`.

    Currently I do this, but it's a manual process of:

    1) Hope developer tells me about changes ( they don't )
    2) Build the package
    3) If missing file errors, check with developer to see if it's on purpose. If so, follow Vagmi's deprecated component pattern.
    4) Run audit script against build area and package to see if there are new files the install doesn't know about. Check with developer to see if it's on purpose. If so, author new files into install.
    5) Repeat until no discrepencys.

    The concept is build automation should output nothing that it shouldn't and the install should consume 100% of it and minor upgrades should just work.

  • Gravatar Image
    Brad Butts October 26, 2007 9:47 AM

    Finally someone has articulated some of my packaging pain-points! Thanks for the post, John. At my company, we deploy DLLs internally for developers to use and give them the source code, too. I've been toying with the idea of extending Tallow such that I can point it at a SLN file and have it build a WiX fragment of the entire source code structure for the solution: CSPROJ files, CS files, sub-dirs...the works. Any thoughts on that?

  • Gravatar Image
    jrobbins October 28, 2007 2:53 AM

    Brad,

    Actually, building a .WiX fragment from a .SLN/.CSPROJ would be quite easy. The VS automation model exposes everything in the project so it would simply be a matter of enumerating the items and building the .WXS file. Very interesting idea!

    - John.

  • Gravatar Image
    jrobbins October 28, 2007 2:58 AM

    Chris,

    Ah, now I see what you want. While I don't know when I'll get to the implementation I'll definitely consider it. If someone else wants to jump in and add it, you've got the code.

    Thanks a million for the link. I didn't know the exact steps for how to keep your component rules nice and clean.

    -John.

  • Gravatar Image
    ShayEr October 29, 2007 4:42 AM

    The Wix3 has an object module that will eliminate the use XmlDoc.
    You create the objects, init their props according to the Wix Doc. and then serialize the root object. This will create you a proper wxs scheme.

  • Gravatar Image
    loctus October 30, 2007 8:06 PM

    Paraffin currently doesn't handle directories and subdirectories that contain characters such as (-) that isn't ASCII characters A-Z, a-z, digits, underscore, or periods. This causes the directory id to compile with errors.

    For example, a directory of name "testing-123" would create a
    Compile error of not a legal identifier.


    Another bug that happens is when I use the alias parameter, source begins with double backward slashes.
    Example -alias bitmaps

    Not a big deal since it still works.


    Only issue is with the illegal identifier naming.

  • Gravatar Image
    John Robbins' Blog November 8, 2007 9:20 PM

    A big thanks to "Loctus" reporting a bug in PARAFFIN.EXE my WiX TALLOW.EXE replacement tool. I was allowing

  • Gravatar Image
    loctus November 13, 2007 7:51 PM

    Thanks for the update. The '-' has been fixed, but something like "vc++" doesn't work.

  • Gravatar Image
    Anonymous November 30, 2007 1:21 PM

    John,

    Thanks for writing this tool. How does it compare to Heat, from the
    WiX 3 toolset?

    Also, a couple of things I'm interested in, and have semi-hacked into
    the source (not yet suitable to give back) include:
    1. Change TARGETDIR to INSTALLDIR (or other choice)
    2. Generation of multiple ComponentGroup elements from a single
    tree. I need this in order to provide flexible configuration from one
    .wxs file (e.g. all vs examples vs documentation vs source etc)

    One other thing -- using -alias, the path ends up looking like
    "alias\\rest of path" That is, two backslashes end up in the path.
    This does not appear to be in code you control, though.

    George

  • Gravatar Image
    jrobbins December 2, 2007 9:18 PM

    gmfienberg,

    PARAFFIN does similar things as Heat does in that it makes it easy to handle files changing in your install. Heat looks pretty nice, but, I needed something that worked against the stable release of WiX 2.0.

    I'd love to see your tweaked code! Shoot it to me in a mail and I'll get your changes integrated into PARAFFIN.

    PARAFFINs up to 1.02 and I fixed the double slash problem.

    -John.

  • Gravatar Image
    Kevin Miller December 10, 2007 1:03 PM

    Now that our journey has begun and we have a basic Wix installer under our belt , we need to get the

  • Gravatar Image
    John Robbins' Blog April 19, 2008 7:19 PM

    Last year I released a tool to help make maintaining WiX 2.0-based installations easier called Paraffin

  • Gravatar Image
    loctus April 30, 2008 3:17 PM

    It is great you updated paraffin. Does the fix include directory names that have symbols such as "+" ? Paraffin leaves the "+" symbol when it creates the directory id name.

  • Gravatar Image
    Cohen yaniv June 3, 2008 10:13 AM

    Hi mate,
    got this annoying error

    "Could not load file or assembly 'System.Xml.Linq, Version=3.5.0.0 ... "

    i have installed Framework 3.5 and still nothing...

    can you please help?

  • Gravatar Image
    MFL November 4, 2008 1:26 PM

    Do you have a version that would support WIX 3.0?

    the LongName attribute is not working when my master wxs uses wix 3.0

    Thanks

  • Gravatar Image
    Ajay D November 6, 2008 6:26 PM

    Hello John - I downloaded your code bits and modified a bit to remove LongName attibute (it was giving compile errors if both name and longname attributes exist) and used latest xml namepace which is


    Thanks,
    -Ajay

  • Gravatar Image
    savaş oyunları December 27, 2008 6:51 PM

    ı have followed your writing for a long time.really you have given very successful information.
    In spite of my english trouale,I am trying to read and understand your writing.
    And ı am following frequently.I hope that you will be with us together with much more scharings.
    I hope that your success will go on.

  • Gravatar Image
    Frank February 17, 2009 8:42 AM

    Hello guys,
    When I executed Paraffin.exe -update ExampleFragment.wxs effectively updates the changes in the directory when add or remove files, but I have one question for this. Why the files that are .dll changes the GUI value?

  • Gravatar Image
    Christopher Painter February 19, 2009 11:35 PM

    Wow, when I first read this thread I was thinking strictly about process workflow and component rules. After spending the last 4 days in training updating my skills to .NET 3.5 including Linq for XML, I'm really excited to finally look into this code.

    Here's what I'm thinking I want to do:

    Create a VS ADDIN for launching parrafin on the currently selected WXS file in Votive.

    Have Parrafin scan a directory and the fragment and report any discrepancys.

    Have the user confirm the adds and deletes he wants done.

    Parrafin does the work and saves the file.

    Votive reloads the file and the developer can diff against source control before checking in.

    Thoughts?

  • Gravatar Image
    Christopher Painter February 19, 2009 11:36 PM

    One more thought. How much work would it be to preserve additional element and attributes.

    That is to say, someone uses parrafin to generate a fragment and then manualy decorates the xml with additional metadata such as a shortcut or serviceinstall element. Then have a subsequent run of parrafin preserve that information provided that the element/file isn't being added or removed.

  • Gravatar Image
    Akash February 25, 2009 9:41 AM

    Hello John -
    I ve downloaded paraffin and used it to harvest files used in my setup
    and i found the following things after when i tried to build my setup

    1. both name and longname attributes exist in DIRECTORIES as well as in FILES.

    which makes it impossible to build ....also includes lots of pain to remove it MANUALLY :)

    is there a way out ??

    Thanks,
    Akash

  • Gravatar Image
    jrobbins February 25, 2009 10:46 AM

    Akash,

    You've missed the point of Paraffin. It's designed to take a tree of directories and files you want to install in that same order and build a WiX fragment out of them.

    If you just want the files, you'll have to do that manually. Even HEAT, which comes with WiX 3.0 does not support what you want to do.

    - John Robbins

  • Gravatar Image
    Akash February 26, 2009 1:08 AM

    Hi John,

    i did exactly the same as you mentioned above.

    i have used paraffin to create wxs file of the whole directory tree which includes all the files that i need to include in my installer.

    the thing is, in generated Fragment file (WXS), there exists both "name" amd "longname" in FILE as well as DIRECTORY element.

    moreover, there are hudreds of files in my setup. So it makes almost impossible for me to remove it manually.

    Do i need to remove longname manually or do you have other way out of this?

    Please let me know if u am missin something

  • Gravatar Image
    Bill Craun February 26, 2009 10:28 AM

    Hi John,

    I have a 5000+ component installer for a web application with many nested folders of arbitrary depth. I am able to use Paraffin to successfully traverse the hierarchy and create the .wxs file. I had been using a XSL stylesheet to correctly create all of the required 's and the 's in the main .wxs file. This is quite tedious as everything does not transform and compile without human intervention.

    Since has long since been deprecated I am not able to simply reference the fragment file from within my main .wxs file. and can't figure out how to link the two together. I'm wondering if there is a much easier way to merge the two by simply using some kind of element in the main file to reference the contents of the fragment file where I need to. Is this something that you have experience with? In the main .wxs file, I would need to be able to materialize the contents of and all of the and elements from the fragment.

    I have tried to use a Votive project which contains the two .wxs files thinking that they would be correctly compiled and linked together by candle and light, but I cannot get it working without having to manually (or by using XSLT) copy/paste.

    Any thoughts?

    Thanks,
    -bill

  • Gravatar Image
    jrobbins February 26, 2009 10:48 AM

    Akash,

    Are you using the latest version of Paraffin, 3.0? http://www.wintellect.com/CS/blogs/jrobbins/archive/2008/12/22/paraffin-3-0-now-with-full-wix-3-0-support.aspx. It sounds like you are not. Give that a try as it's got full WiX 3.0 support.

    Bill,
    At the top of the generated file Paraffin has a ComponentGroup. You just need to reference that in your main .WXS file and you automatically pull in all the individual ComponentRefs.

    Hope it helps!
    - John Robbins

  • Gravatar Image
    Bill Craun February 27, 2009 11:49 AM

    John,

    Yes, that does help. I was able to figure it out prior to your reply, but I do thank you for getting back with me so soon.

    Take care,
    -bill

  • Gravatar Image
    Bill Craun March 18, 2009 4:33 PM

    Anyone know if any Nant tasks exist for Paraffin? Any interest in having them created if they don't yet exist?

    -bill

  • Gravatar Image
    jrobbins March 18, 2009 4:41 PM

    Hi Bill,

    I don't know of a Nant task for Paraffin. Please feel free to whip one up. :)

    A small caveat to keep in mind: Component Rules are extremely fragile in Windows Installer. If you plan on doing major upgrades for everything in your project, you shouldn't run into problems automating Paraffin as part of your build. However, if you are going to use patches or not rely on major upgrades, automating Paraffin will create a serious bag of hurt in the long run.

    -John Robbins

  • Gravatar Image
    Bill Craun March 19, 2009 9:21 AM

    John,

    Understood. I think I could fully automate my process if Paraffin had additional logic to exclude specific file names from its traversal similar to the way the extension logic (i.e. -ext) works. More importantly, though, I need the ability to pass args that would direct Paraffin to add Permanent="yes" NeverOverwrite="yes" attributes to specific 's. All of the products my client has require certain .config files to remain untouched between upgrades and I currently need to tweak the fragment file after it is generated to include these. There are also several Windows Services that need to be configured by hand, but I suppose this could be remedied by some XSL, but having Paraffin do the heavy lifting would be nice.

    I started to add the Permanent/NeverOverwrite attribute support, but got sidetracked on other things. I don't know if I will be able to get it done myself. Same goes for the Nant tasks.

    Anyway, thanks for the info.

  • Gravatar Image
    Gulfam Murad May 14, 2009 11:07 AM

    Hi John,

    I am new to Wix and Paraffin. I have successfully generated a .wxs file using paraffin. Now I am having problem merging it into votive's product.wxs. You replied Bill Craun to reference ComponentGroup in the main .wxs. Could you please elaborate it a bit more on how can i do this.

    Thanks
    Gulfam

  • Gravatar Image
    Gulfam Murad May 14, 2009 11:32 AM

    Hi John,

    I am new to Wix and Paraffin. Could you please guide me on how to reference ComponentGroup in your main .wxs, I am having a compilation error
    "error LGHT0094: Unresolved reference to symbol 'WixComponentGroup:group_myProd' in section 'Product:{07AB9189-0478-45E3-ACD8-2D042B649C03}'."

    Thanks.
    Gulfam

  • Gravatar Image
    jrobbins May 14, 2009 6:40 PM

    Gulfam,

    In the .WXS fragment generated by PARAFFIN, you have the following:




    To reference it in your product .WXS do the following:




    Make sure both .WXS files are on the LIGHT.EXE command line.

    -John Robbins

  • Gravatar Image
    Gulfam Murad May 15, 2009 10:35 AM

    Hi John,

    Thanks alot for your response. I am one step ahead now :)

    I am using Visual Studio 2005 (votive) to create WIX Setup. The default product.wxs file generated with the project has namespace "http://schemas.microsoft.com/wix/2006/wi" and the file generated with Paraffin has a different namespace "http://schemas.microsoft.com/wix/2003/01/wi" (the difference is only 2003 and 2006 here). So when I compile "error CNDL0199: wix element has a different namespace" error apears.

    Once I edit the paraffin generated .wxs manually to fix this issue, there are some more error regarding Name and LongName attribute for all the directories, components and files...e.g.

    "error CNDL0035: The Directory/@Name attribute cannot be specified when attribute LongName is present."

    "error CNDL0035: The File/@Name attribute cannot be specified when attribute LongName is present."

    Fixing this issue require manual editing of .wxs file, could you please help me in this.

    Thank you

    -Gulfam



  • Gravatar Image
    jrobbins May 16, 2009 7:17 PM

    Gulfram,

    You are using the old version of Paraffin. Get the newer version here: http://www.wintellect.com/CS/files/folders/7420/download.aspx

    John Robbins

  • Gravatar Image
    Gulfam Murad May 19, 2009 10:28 AM

    yep, my bad... things are working fine now... Thanks.

    by the way, it would be great if paraffin.exe provide:

    - exclude specific files (-ext will exclude all files of that extension)
    - include specific files

    Thank you again John.

    Best Regards,
    Gulfam

  • Gravatar Image
    Kenneth Skovhede May 27, 2009 4:14 PM

    I use parafin regularly, and there is just one thing that annoys me.
    It always includes the root folder in the out.
    My build output looks like:

    App\bin\Release\app.exe

    When I specify "-dir Release", I get a top level directory called "Release" in the installation. This forces me to copy the "Release" folder to a temp location with a proper name.

    Another related issue is that -dir does not correctly decode a path with a space, eg:
    -dir "My Folder\Test"

    Thanks for making the app, you should consider getting the application hosted at sourceforge or google code, that would make it easier to track feature requests and bug reports.

  • Gravatar Image
    Santosh Jena June 17, 2009 8:59 AM

    I used paraffin to create fragment project file and get compilation error as the Fragment doesn't have Name and LongName defined.
    Like this




    I have used below command line -
    Paraffin.exe -dir .\ -custom EXAMPLE -g -alias ..\Example –ext .WXS ExampleFragment.wxs

    For your information I have used Paraffin 3.0.0.
    Have I missed something?

  • Gravatar Image
    jrobbins June 17, 2009 11:47 AM

    Santosh,

    You're using Paraffin 3.0 with WiX 2.0. You need to be using the Paraffin you'll find at this link: http://www.wintellect.com/CS/files/folders/sample_files/entry4332.aspx.

    - John Robbins

  • Gravatar Image
    Magne Borg June 23, 2009 3:24 AM

    Hi John,

    I too am missing the File attribute, like Santosh is.
    I am using WiX 3.0.5217.0 and Paraffin 3.0, but I'm using it with .NET 2.0. Does that matter?

  • Gravatar Image
    Magne Borg June 24, 2009 1:11 AM

    Oops...
    I mean the Name and LongName attribute in the fragment...

  • Gravatar Image
    jrobbins June 24, 2009 1:52 AM

    Magne,

    If you are missing the Name and LongName attributes in the File element, you are using WiX 2.0. My psychic abilities tell me that because WiX 3.0 does not use Name and LongName attributes any more. :)

    - John Robbins.

  • Gravatar Image
    Magne Borg June 24, 2009 5:38 AM

    John,

    Thanks for the quick answer :-)

    Ok, I think I see what's going on here. I'm just talking about the file that Paraffin generated. That file doesn't have the Name attribute. But I haven't tried to use it in my WiX project yet because I thought there was something wrong with it since the Name attribute was missing. I didn't know that WiX 3.0 doesn't need the Name attribute any more. Thanks for clarifying that :-)

    However, WiX 3.0 still supports the Name attribute if you want a different filename than that from the Source attribute. Take a look at the online help for WiX 3.0: http://wix.sourceforge.net/manual-wix3/wix_xsd_file.htm

    Sorry for wasting your time :-)

  • Gravatar Image
    jrobbins June 24, 2009 12:13 PM

    Magne,

    You're not wasting my time at all! I'm thrilled you're using Paraffin.

    Yes, I figured most people wanted the same name of the file as the Source attribute. :) I guess if you wanted to change the name you could do some XSLT magic on the Paraffin produced file.

    Hope it helps!
    -John Robbins

  • Gravatar Image
    Eric August 5, 2009 11:29 AM

    Hi! Thanks for this tool.

    I am in the middle of setting up a WiX based deployment and this is so much nicer than hand editing or working with Heat.

    One thing I would request.

    Would it be possible to make PARAFFIN skip over folders that are empty either because they really are empty, or because everything in them has been excluded?

    This is different from excluding a folder, because if you exclude a folder, it's excluded even if something useful winds up in there. If PARAFFIN decides that a folder node is going to wind up empty on the fly, and excludes it, that saves you from having to worry about the wxs if you should suddenly have desired content in that folder.

    Hope I'm being clear.

  • Gravatar Image
    Santosh August 10, 2009 10:44 AM

    Kindly suggest for the below issue facing during Paraffin -update.

    1. Fragment generated in one machine harvested by C:\Users\Apps\Server
    2. Same fragment is not usefull to "-update" in other machines where "C:\Users\Apps\Server" this directories is not present.

    Paraffin gives error "A call into Windows failed unexpectedly". This is because Fragment contains a Tag from which it updates the file/dir list.

    Can this be environment variable? Our source dir is dynamic.

  • Gravatar Image
    jrobbins August 10, 2009 11:21 AM

    Santosh,

    Use the -alias switch to do what you want.

    John Robbins

  • Gravatar Image
    Santosh August 10, 2009 12:10 PM

    Alias comes into picture only on tag.

    I refered to present in <!--<CommandLineOptions> tag.

  • Gravatar Image
    jrobbins August 10, 2009 12:18 PM

    Santosh,

    Oh, I see. I would suggest *NOT* changing the harvesting directory. That's the only way Paraffin knows which files belong to which directory. Everything in Paraffin is keyed off the directory. Sorry.

    - John Robbins

  • Gravatar Image
    jrobbins August 12, 2009 3:02 PM

    Eric,

    I've been thinking about your suggestion of skipping empty folders and I can't see a good way of implementing it. I think it would add a lot of complexity to Paraffin because of the recursive nature of the tool. Think of the scenario where directory A has everything excluded, but contains B, which has stuff you want included.

    With the extension and directory match excluding, I think I got the majority of what people will be needing. In your case, which is a bit unique, I'd have a PowerShell script run before Paraffin that deletes the files you don't want included. That's what I do on one of my installers and it made life really simple.

    Thanks for the suggestion!

    -John Robbins

  • Gravatar Image
    Magne August 14, 2009 8:19 AM

    Hi John,

    I've been using Paraffin in a few projects now and I really like it, nice work!

    I have one suggestion or maybe there already is a solution for it.
    When I run Paraffin in a directory, say the output directory of a Visual Studio project (which is set to the bin directory in this example):
    Paraffin.exe -dir ..\..\WinService\OT.OTTBackupServer.Service\bin\.

    Is there a way of setting the Name attribute of the Directory generated to something other than the auto generated Name "bin"?
    The result of the above command results in the following:

    ...


    ...

    I would prefer the Name to be simply a dot (.), so that all the files are installed directly in the INSTALLDIR and not in the bin directory.
    Do you understand what I mean?

    Kenneth Skovhede is talking about the same thing above but I can't see any comments from you on this.

    Thanks,
    Magne

  • Gravatar Image
    jrobbins August 14, 2009 11:01 AM

    Magne,

    Thanks for the kind words about Paraffin! I really appreciate them.

    To avoid the extra directory under make sure you're using the -norootdirectory switch. That tells Paraffin to leave the initial out and put those files under the node.

    Get the latest Paraffin here: http://www.wintellect.com/CS/files/folders/8198/download.aspx.

    Thanks for using Paraffin!

    -John Robbins

  • Gravatar Image
    Eric September 11, 2009 3:55 PM

    Found an issue when doing an update on a wxs file.

    The previous run had generated an empty, self-closing directory node, with no components. In this case, the UpdateFilesInDirectoryNode proc threw a null reference exception on foreach ( var attrib in intputCompElem.Attributes ( ) ) because intput (sic) was null as there was no component element in the XML.

    Would you consider a verbose or logging mode to help track down the problem when PARAFFIN fails for whatever reason? I was able to add some debugging code to help find this, but a -v switch would be useful.

  • Gravatar Image
    Eric September 11, 2009 4:01 PM

    Hi John-

    Thanks for considering my folder skipping scenario.

    Without digging into your code myself, wouldn't a depth-first recursion solve the issue of determining if a folder is empty? If you recurse the folder structure to the bottom and build the structure upwards based on inclusion/exclusion rules (and actual content). Wouldn't that make it easy to determine if a folder hierarchy needs to be built?

    In you example about A excluding everything but A includes B which contains wanted files. If you dig all the way down to B first, and that recursion returns the nodes for B, then you know you need to include A, because even tho A doesn't directly contain anything, it DOES contain B, which has needed content, so A is included too.

    Again, hope a textual explanation is clear for you. If I'm barking up a different tree than you, I apologize.

  • Gravatar Image
    jrobbins September 11, 2009 6:22 PM

    Eric,

    THANKS! I appreciate the bug report. I'm going on vacation, but will get that fixed as soon as I get back. Good idea for the -v switch. I'll add tracing to the code as well.

    Neat idea on the depth-first recursion. That would make it much easier to implement the directory skipping. Unfortunately, that'd take a complete rewrite of Paraffin as it assumes adding nodes/files in a first come-first serve direction. I'll keep this idea on the list as several folks have asked for much stronger filtering such as wildcards and such. If I tackle those, it might be a good time to look at your approach.

    Thank you, and everyone else, who uses Paraffin. I really appreciate it!

    - John Robbins

  • Gravatar Image
    jrobbins September 26, 2009 2:43 PM

    Eric,

    I'm back from vacation. :) Using Paraffin 3.11, I can't duplicate the bug you are talking about. What version are you using? If you're not using 3.11, please try and duplicate the bug with it and give me a repro case. Get the latest Paraffin from here: http://www.wintellect.com/CS/files/folders/8198/download.aspx.

    Thanks!
    - John Robbins

  • Gravatar Image
    Chunyan October 7, 2009 9:23 AM

    Hi John,

    I would like to use Paraffin.exe to generate the .wxs files. However, I have several directories need to process. Therefore I would like to write a batch file like your FirstParaffinRun.cmd. As your instruction, I must switch to the specific directory, then run Paraffin command. Is it possible to run Paraffin.exe outside the target directory, but set some switch in the command?

    Thanks!

    Chunyan

  • Gravatar Image
    jrobbins October 7, 2009 7:46 PM

    Chunyan,

    Yes, Paraffin runs fine from a different directory. The key with Paraffin is that you will need to always do the update runs from the same location. Create your initial file with the -dir switch, which will be embedded into the .WXS file as part of the settings comments. If you do the update from the same directory, Paraffin will properly update.

    Hope it helps!
    - John Robbins

  • Gravatar Image
    Chunyan October 8, 2009 3:58 AM

    Hi John,

    Thank you very much for your reply. Paraffin is a great executable. I have figured out the Paraffin running from other location issue. It is fine.

    However, I still have a critical question. My case is:

    I want to get the files from source PathS, and intall them to INSTALLDIR\PathA\PathB. If I set the Paraffin command as:
    Paraffin.exe -dir "PathA\PathB" .....

    There is error message: can not find PathA\PathB.

    It is obviously, because I want to install files there. It doesn't exist in source.

    If the Paraffin command is:
    Paraffin.exe -dir "PathS" .....

    There is no error. However, the wxs fragment looks like:





    ................

    It means when I build this wxs and run the generated msi, it will install files to PathS, which is not I want. I only want to install the files to PathA\PathB. The wxs fragment should be like:



    ................

    How to realize this by using Paraffin?



  • Gravatar Image
    jrobbins October 8, 2009 12:22 PM

    Chunyan,

    Paraffin has to make some assumptions about your file layout and that means the layout on disk is how you want them installed.

    You're going to have to run Paraffin on PathS to generate the file. In your main installer .WXS file you'll have to do the values like you want and include the to the Paraffin produced file.

    Paraffin just gives you a .WXS for the files as it finds them on disk. If you want those installed in a different layout, you have to do that yourself.

    Hope it helps!
    - John Robbins

  • Gravatar Image
    Chunyan October 16, 2009 6:59 AM

    Hi John,

    Thanks for your answer. As you suggested I did some work in main .WXS to define the directory. Then use parameters -dirref and -norootdirectory. So that the PARAFFIN generated .WXS will use the directory as I defined in main .WXS. And the problem is resolved.

    However, I have another problem. There is one file, which is included in PARAFFIN generated .WXS file, like:


    But I will use this file in my .WXS file as Custom Action:


    Before I included this RUN.exe manuelly in my .WXS file. And the custion action always works. However, since I use PARAFFIN and still use this RUN.exe, this custom action will not work some times. And there is error message:

    There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vender.

    If I command out the line of this file in PARAFFIN generated file, and add it manuelly to my .WXS file, it works again, even I use the same content as in PARAFFIN generated file.

    It is really strange. Could you tell me how to resolve it?

    Thanks again.

    Chunyan

  • Gravatar Image
    Chunyan October 16, 2009 8:53 AM

    Hi John,

    In my last post I said that there is problem about using PARAFFIN that custom action can not run.

    The root cause is clear. It is not because of PARAFFIN. I should do SetTargetPath event when I tried to change the default path.

    So the problem has been resolved. Sorry for disturbing you.

    Chunyan

  • Gravatar Image
    Nicholas Piasecki October 29, 2009 2:55 PM

    This tool just saved me approximately one (1) butt load of time.

    Thank you so much for taking the time to create this tool and post it to your blog.

  • Gravatar Image
    jrobbins October 29, 2009 3:33 PM

    Nicholas,

    WOW! Thanks for completely making my day. Especially since I helped save an excellent unit of measure. :D

    - John Robbins

  • Gravatar Image
    Dmitry November 26, 2009 4:38 AM

    Great tool. But need one small option Id for Cab.
    I exctract huge directories with SDK and want to put it in single Cab


  • Gravatar Image
    jrobbins November 30, 2009 11:54 AM

    Dmitry,

    I'm not sure what you're asking for. Do you have an example?

    - John Robbins

  • Gravatar Image
    Harjit Batra February 1, 2010 11:25 AM

    The download link in the original post points to v3.0 of Paraffin:

    You can download the code and PARAFFIN.EXE here. Please note that you need the .NET Framework 3.5 installed on your machine for PARAFFIN.EXE to work.

    Elsewhere in the comments & replies you have a more update version, v3.11:

    Get the latest Paraffin from here: http://www.wintellect.com/CS/files/folders/8198/download.aspx.

    Could you please keep the download link in the main article updated? It would save scanning from the bottom and looking for the last link you've provided! ;-)

    Thanks a lot for making your work available to all the rest of us!

  • Gravatar Image
    lewis March 4, 2010 4:23 PM

    I understand the that component id must be unique, but could you put in an option to use the filename for the id (and let me sort though the errors), or use the filename_# when there are duplicates.

    I would make it much easier to read.

  • Gravatar Image
    Nicholas Guy March 5, 2010 5:34 AM

    Hi John,

    I was looking for some license info here and in the downloaded zip. Is there any?

    Cheers.

  • Gravatar Image
    jrobbins March 10, 2010 11:39 PM

    Harjit,

    Sorry for the hassles. I'll get the file situation straightened out.

    Lewis,

    Interesting idea. An even better approach will be available to us with WiX 3.5: you no longer need GUIDS. That'll eliminate the issue.

    Nicholas,

    The license is you can do whatever you want with Paraffin, just provide attribute. Also, if you find a bug, please report it!

    Thanks all for using Paraffin!
    - John Robbins

  • Gravatar Image
    Greg Pearce October 29, 2010 8:14 PM

    I read your blog about components and such, and read this paragraph there: (and I Quote):

    "While I can't stop you from running PARAFFIN.EXE from your build and creating all your .WXS fragments every time you build, I would strongly recommend you don't do that because you'll have different GUIDs for your components and completely break all component rules."

    I *know* I shouldn't run paraffin on every build because this breaks "component rules" ... I know ... but! ... does this really matter when doing major upgrades?

    Don't major upgrades dump all the old stuff and installs all the new stuff all the time? I thought that is how that goes...

    There is no chance that we'll ever support a minor upgrade...

    Thanks!

  • Gravatar Image
    jrobbins November 1, 2010 2:26 PM

    Greg,

    It's plenty fine to run Paraffin as part of your build if you are completely and totally guaranteed to *ALWAYS AND FOREVER* do nothing but major upgrades. However, you've locked yourself out of any form of patching ever in the future.

    That said, I gave up on doing patches long ago and only do major upgrades. Patching is so amazingly complicated to get right that other than working on something the size of Office and Windows, I can't see why anyone would do it. With that said, I still take the few minutes to manually update any .WXS files with Paraffin because as we all know designs and requirements change and I don't want to lose the flexibility on my projects for developers who come after me.

    There's my $0.02. :)
    - John Robbins

  • Gravatar Image
    gdavis May 23, 2011 1:31 PM

    Ditto the request to update the link on the original post to the 3.1 version.

    Had to read through all comments to find that the -norootdirectory option had already been implemented and was available in that version.

  • Gravatar Image
    jrobbins May 23, 2011 7:48 PM

    gdavis,

    To get all the Paraffin articles in newest to oldest order, simply use the Paraffin tag on all my blog posts: http://www.wintellect.com/CS/blogs/jrobbins/archive/tags/Paraffin/default.aspx.

    - John Robbins

  • Gravatar Image
    Greg Pearce September 21, 2012 11:57 AM

    I’m using paraffin Version 3.6.0.0 with excellent success, and thanks for all the work you’ve put into this.
    I’m doing something a little unorthodox possibly – and I’m having trouble figuring out why this doesn’t work.
    I have a BIG wxs fragment file that was generated using heat. Since it generated all the guids and component IDs for our product, I want to maintain those IDs for obvious reasons. So I am trying to fake paraffin into thinking that this is a paraffin generated file which I can then “-update” when necessary.
    The dir structure is exactly the same from when the file was generated using heat, to now, when I am using paraffin to generate a new fragment file, with the comment header sections in it. Then I go into the newly generated paraffin output, replace all the component refs and file refs and dir refs etc., with what came out of the file generated by heat.
    I did this with success for a directory structure with another fragment file in this same project and it worked beautifully.
    But with this current fragment file I’m trying to convert to paraffin format, every component dir file and guid is regenerated like it never existed before when I try to update this file.
    I was wondering if there is some logging facility in paraffin that I could look at after the update that might give me a clue as to why it is regenerating the whole thing.
    Is there some switch or something I can do to cause paraffin to output any diagnostics? (I don’t have the source code (yet!), as I’m not a VB/.NET guy).
    Thanks ahead of time, and again, for your hard work on this program.
    Greg

  • Gravatar Image
    Niels January 4, 2013 8:18 AM

    Have you tried to work with the Wix team to integrate this functionality into TALLOW?
    This shows the strength and weakness of open source. You can create something that adds on the original project, but if you don't merge your changes/additions, users of the original project don't benefit from your work (unless they know where to get your tool).

Have a Comment?

Archives

Blogs