📜 ⬆️ ⬇️

Creating an installer using WiX. Part 2

Last time we learned how to create a simple installer . Before moving on, from simple to complex, let's learn how to manage this most difficult. Namely, we will learn how to break a project into parts in order to simplify maintenance and making changes.



The first project we had consisted of a single file in which all instructions for the installer were written. Install one file (calculator). Now imagine a more serious project, including, for example, 10, 20, or even 100 files. If we include the description of these files in the project file, then later, when we need to change something, we will understand that it is very difficult to search for something specific in this heap.
')
Taking the previous project as a basis, we will move the description of the files to be installed beyond the limits of the project file Product.wxs . To do this, add the Files.wxs file to the project, define the following content for it:

<? xml version ="1.0" ? >
< Wix xmlns ="http://schemas.microsoft.com/wix/2006/wi" >

< Fragment >

< DirectoryRef Id ="INSTALLLOCATION" >
< Component Id ="ProductComponent" Guid ="b11556a2-e066-4393-af5c-9c9210187eb2" >
< File Id ='Calc' DiskId ='1' Source ='C:\WINDOWS\system32\calc.exe' />
</ Component >
</ DirectoryRef >

</ Fragment >
</ Wix >

* This source code was highlighted with Source Code Highlighter .



Remove the component description from the Product.wxs file so that you do not get an error message during the project build process.

It was
< Directory Id ="INSTALLLOCATION" Name ="$(var.ProductName)" >
< Component Id ="ProductComponent" Guid ="b11556a2-e066-4393-af5c-9c9210187eb2" >
< File Id ='Calc' DiskId ='1' Source ='C:\WINDOWS\system32\calc.exe' />
</ Component >
</ Directory >

* This source code was highlighted with Source Code Highlighter .



It became
< Directory Id ="INSTALLLOCATION" Name ="$(var.ProductName)" />
* This source code was highlighted with Source Code Highlighter .



Two new keys < Fragment > and < DirectoryRef > appeared in the code.

< Fragment > contains inside a snippet of code that will be included in the project during assembly.
< DirectoryRef > link to the Directory section. Allows you to make, for example, the description of the components outside the < Directory > key.

By the way, the keys of the form < * Ref > simplify the process of splitting a project into fragments, and help streamline the code. In addition to < DirectoryRef > there are links < FeatureRef > , < ComponentRef > and others.

To complicate the project a bit, add a notepad installation to it. Modify the code as follows:

< DirectoryRef Id ="INSTALLLOCATION" >
< Component Id ="ProductComponent" Guid ="b11556a2-e066-4393-af5c-9c9210187eb2" >
< File Id ='Calc' DiskId ='1' Source ='C:\WINDOWS\system32\calc.exe' />
< File Id ='Notepad' DiskId ='1' Source ='C:\WINDOWS\system32\notepad.exe' />
</ Component >
</ DirectoryRef >

* This source code was highlighted with Source Code Highlighter .



Have added. What confuses? Path to each file. And what if the files are transferred? And what if there are 100 of them? A replacement search will help, but this is not our method. Let's get acquainted with the new parameter of the < DirectoryRef > - FileSource key . This parameter allows you to set the base path. Let's rewrite taking into account new knowledge, at the same time and DiskId = '1' we will take out the definition of the component. Why should it be specified each time if all child elements use the same value?

< DirectoryRef Id ="INSTALLLOCATION" FileSource ="C:\WINDOWS\system32\" >
< Component Id ="ProductComponent" Guid ="b11556a2-e066-4393-af5c-9c9210187eb2" DiskId ='1' >
< File Id ='Calc' Name ='calc.exe' />
< File Id ='Notepad' Name ='notepad.exe' />
</ Component >
</ DirectoryRef >

* This source code was highlighted with Source Code Highlighter .



Notice that the Source parameter of the < File > keys has been changed to Name . Those. we specified to search by file name inside the specified directory, and not by the absolute path of the file. If this is not done then we will receive an error message “cannot find the specified file”.

Notepad added, add a shortcut to it. We find the creation of a shortcut for the calculator and see the porridge. The component for creating a shortcut is described inside the directory. We take out the creation of shortcuts in a separate file. To do this, add the file Shortcuts.wxs to the project:

<? xml version ="1.0" encoding ="UTF-8" ? >
< Wix xmlns ="http://schemas.microsoft.com/wix/2006/wi" >
< Fragment >

< DirectoryRef Id ="ApplicationProgramsFolder" >
< Component Id ="ApplicationShortcutCalc" Guid ="4CEBD68F-E933-47f9-B02C-A4FC69FDB551" >

< Shortcut Id ="ShortcutCalc"
Name ="Calc"
Description ="$(var.ProductName)"
Target ="[INSTALLLOCATION]Calc.exe"
WorkingDirectory ="INSTALLLOCATION" />

< Shortcut Id ="ShortcutNotepad"
Name ="Notepad"
Description ="$(var.ProductName)"
Target ="[INSTALLLOCATION]Notepad.exe"
WorkingDirectory ="INSTALLLOCATION" />

< RemoveFolder Id ="ApplicationProgramsFolder" On ="uninstall" />
< RegistryValue Root ="HKCU" Key ="Software\$(var.Manufacturer)\$(var.ProductName)" Name ="installed" Type ="integer" Value ="1" KeyPath ="yes" />

</ Component >
</ DirectoryRef >

</ Fragment >
</ Wix >

* This source code was highlighted with Source Code Highlighter .



If we now try to build the project, we get the error message: Undefined preprocessor variable '$ (var.ProductName)'

That's right, when processing the Shortcuts.wxs file, nothing is known about the variables declared in the Product.wxs file. What to do?

In addition to fragments, WiX allows you to use include files. The contents of such a file can be determined as follows:

<? xml version ="1.0" encoding ="utf-8" ? >
< Include >
<!-- -->
</ Include >

* This source code was highlighted with Source Code Highlighter .



Unlike the fragment, inclusions will not be included in the assembly automatically until you include it in any file yourself. In order to understand what an inclusion is, let's move the definition of variables from the Product.wxs file into a separate file. To do this, add a new file named Variables.wxi to the project, and transfer the variable declaration to it:

<? xml version ="1.0" encoding ="utf-8" ? >
< Include >

<? define ProductName ="SetupProject2" ? >
<? define ProductVersion ="1.0.0.0" ? >
<? define ProductCode ="b7bc7c6f-9a4e-4973-be84-eca8e3427c97" ? >
<? define UpgradeCode ="06a81104-1e30-463d-87e1-e8a79b4c682a" ? >
<? define Manufacturer ="MyCompany" ? >

</ Include >

* This source code was highlighted with Source Code Highlighter .



And the definition of variables in the Product.wxs file is replaceable with:

<? include Variables . wxi ? >
* This source code was highlighted with Source Code Highlighter .



Just do not forget to add the same line to the file Shortcuts.wxs . After that, the installation package should be assembled without errors.

There was one file Product.wxs became four files. For a simple installation package, it is possible that such a partitioning does not make sense, especially if this package is written at one time. For a large project involving the installation of dozens of files, the creation of shortcuts - the separation is vital. Otherwise, in such a project, as they say - the devil's leg will break. Another advantage of using fragments is the ability to reuse ready-made code.

Next time we will add the ability to select components for installation in our package and add a “self-made” window in which the user can change the installation options.

Sources and project for Visual Studio can be downloaded here.

Source: https://habr.com/ru/post/69129/


All Articles