Pick your favorite XML editor—for all of the examples, I’ll use notepad--and create a new file called “product.wxs”. Nothing about that name is special, but the .wxs extension lets us know that this is a Windows Installer Xml Source File. Now, let’s add the three lines of text all .wxs files have:
<?xml version='1.0'?> <Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'> </Wix>
That forms the outer skeleton for our source file and, honestly, any other source file we ever want to get compiled. You can feed this empty source file to candle.exe and get out an empty object file. Tell you what, let's do that. Follow the following steps and you should see very similar output:
C:/test> candle product.wxs Microsoft (R) Windows Installer Xml Compiler version 1.0.1220.15022 Copyright (C) Microsoft Corporation 2003. All rights reserved C:/test> type product.wixobj <?xml version="1.0" encoding="utf-8"?><wixObject xmlns="http://schemas.microsoft.com/wix/2003/04/objects" src="C:/test/product.wxs" /> C:/test>
Let's notice a couple things before continuing. First, notice that when there is no error candle doesn't print any text other than its header. In fact, you can even suppress the header output by specifying "-nologo" on the command line. In that case, candle will print nothing unless there is a failure. Second, notice that the path to the original source file is stored in the .wixobj file. This can be useful when tracking down where an error is coming from. In fact, the linker uses that "src" attribute to print more informative error messages when it encounters a problem.
Okay, now that we've seen an empty source file create an empty object file, let's create an installable Windows Installer package. Add the following content to your product.wxs file:
<?xml version='1.0'?> <Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'> <Product Id='12345678-1234-1234-1234-123456789012' Name='Test Package' Language='1033' Version='1.0.0.0' Manufacturer='Microsoft Corporation'> <Package Id='12345678-1234-1234-1234-123456789012' Description='My first Windows Installer package' Comments='This is my first attempt at creating a Windows Installer database' Manufacturer='Microsoft Corporation' InstallerVersion='200' Compressed='yes' /> <Directory Id='TARGETDIR' Name='SourceDir'> <Component Id='MyComponent' Guid='12345678-1234-1234-1234-123456789012' /> </Directory>
<Feature Id='MyFeature' Title='My 1st Feature' Level='1'> <ComponentRef Id='MyComponent' /> </Feature> </Product> </Wix>
This should allow us to create a MSI with a ProductCode of "{12345678-1234-1234-1234-123456789012}" with ProductLanguage of "1033" and a ProductVersion of "1.0.0.0". All of that information is taken from the <Product/> element. The <Package/> element defines all of the information that goes in our MSI's summary information stream. Finally, a simple <Directory/> and <Feature/> tree is created with a single <Component/>. This is enough to get our MSI registered on the machine.
So let's compile, link, and install then take a look at the registered packages for our MSI. Follow the instructions:
Note: This MSI requires admin privileges and will silently fail if you are not installing as an Administrator.
C:/test> candle product.wxs Microsoft (R) Windows Installer Xml Compiler version 1.0.1220.15022 Copyright (C) Microsoft Corporation 2003. All rights reserved product.wxs C:/test> light product.wixobj Microsoft (R) Windows Installer Xml Linker version 1.0.1220.15022 Copyright (C) Microsoft Corporation 2003. All rights reserved C:/test> msiexec /i product.msi C:/test> //delivery/tools/msiconfig.exe . . . {12345678-1234-1234-1234-123456789012} Test Package . . .
You should see your "Test Package" listed with all the other Windows Installer packages installed on your machine. You can also go to Add/Remove Programs in the Control Panel and see "Test Package" registered there. Go ahead and remove the package now, so we don't forget it later.
Great! Now that we have a package that installs and uninstalls properly, let's actually install something. So, create a new text file called "readme.txt" next to your "product.wxs" file and type a message to yourself in there. "Hello, World!" is a favorite. Then, we need to modify the product.wxs to tell it about the file:
<?xml version='1.0'?> <Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'> <Product Id='12345678-1234-1234-1234-123456789012' Name='Test Package' Language='1033' Version='1.0.0.0' Manufacturer='Microsoft Corporation'> <Package Id='12345678-1234-1234-1234-123456789012' Description='My first Windows Installer package' Comments='This is my first attempt at creating a Windows Installer database' Manufacturer='Microsoft Corporation' InstallerVersion='200' Compressed='yes' /> <Media Id='1' Cabinet='product.cab' EmbedCab='yes' /> <Directory Id='TARGETDIR' Name='SourceDir'> <Directory Id='ProgramFilesFolder' Name='PFiles'> <Directory Id='MyDir' Name='TestProg' LongName='Test Program'> <Component Id='MyComponent' Guid='12345678-1234-1234-1234-123456789012'> <File Id='readme' Name='readme.txt' DiskId='1' src='readme.txt' /> </Component> </Directory> </Directory> </Directory> <Feature Id='MyFeature' Title='My 1st Feature' Level='1'> <ComponentRef Id='MyComponent' /> </Feature> </Product> </Wix>
You should be able to compile, link, and install that MSI and see that you do get a directory called "Test Program" in your system's "Program Files" folder. In that "Test Program" directory should be the "readme.txt" file you created with the message to yourself. Spiffy, eh? Again, remember to uninstall the MSI so you can rebuild and install it again later.
Believe it or not, that's all there is to creating a Windows Installer package. Sure, you can add UI and things like that now, but we've covered the basics. Everything just comes down to filling in the right XML elements. So, let's move on and look at creating a Merge Module we can incorporate into our spiffy new package.