Continuing from Part 3, we look at providing a user interface to get information from the user and apply that to our structure and definitions.
Step 7: User Interface
WiX comes with a set of pre-defined dialogs that you can read about in Using the WixUI dialog library. This covers a lot of the typical dialogs you would expect to provide for a standard exe installer, but does not currently provide everything we need for querying the user about the installation of our web application.
So what do we need in addition to the standard dialogs? Well, the answer is somewhat subjective. However, my personal take on this is as follows:-
- I want to prompt the user to pick from one of the existing web sites. I do not want to muck around with creating a web site; this can/should be achieved using the standard IIS management tools.
- I also want to prompt the user for a name that we can use for the virtual directory, application and application pool.
- Given the above two, we can show the user the calculated target path (physical path for the selected web site plus the specified virtual directory name). They can adjust this if they wish at this point.
And that’s it. Very quick and simple. Item 2 is the one that people seem to have varying opinions on, and again this is both subjective and context specific.
These days when we install a web application, we create an application pool specifically for the application rather than sharing it…and normally the default security settings are appropriate. Hence, the relatively simple approach taken here.
There are other examples out there that discuss allowing the user to pick an existing application pool, and define all the settings required to create a new application pool, but I think you need to strike a balance between what we provide in the installer, and the management tools themselves. In case you are interested, here are some of the relevant bookmarks:-
Anyway, moving on…
Add a reference to WixUIExtension, and then add the following two lines to Product.wxs:
Product.wxs Modification
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION"/>
<UIRef Id="WixUI_WebUI" />
What this does it tie up our INSTALLLOCATION path defined on our earlier directory definition to the property used on the standard WixUI_InstallDir dialog. We then define a reference to the UI we want to use, as it’s neater to put the UI definition in a separate file.
Create a WiX file called MyUI, and fill it in as follows:
MyUI.wxs
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<WixVariable Id="WixUIBannerBmp" Value="Images\ps_wix_banner.jpg" />
<WixVariable Id="WixUIDialogBmp" Value="Images\ps_wix_welcome.jpg" />
<WixVariable Id="WixUILicenseRtf" Value="End User License Agreement.rtf" />
<UI Id="WixUI_WebUI">
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
<Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
<Property Id="WixUI_Mode" Value="InstallDir" />
<DialogRef Id="BrowseDlg" />
<DialogRef Id="DiskCostDlg" />
<DialogRef Id="ErrorDlg" />
<DialogRef Id="FatalError" />
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<DialogRef Id="PrepareDlg" />
<DialogRef Id="ProgressDlg" />
<DialogRef Id="ResumeDlg" />
<DialogRef Id="UserExit" />
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction"
Value="WixUIValidatePath" Order="3">1</Publish>
<Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog"
Value="InvalidDirDlg" Order="4"><![CDATA[WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
<Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog"
Value="Return" Order="999">1</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog"
Value="LicenseAgreementDlg">NOT Installed</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog"
Value="VerifyReadyDlg">Installed AND PATCH</Publish>
<Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog"
Value="WelcomeDlg">1</Publish>
<Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog"
Value="InstallationAddress">LicenseAccepted = "1"</Publish>
<!-- Custom: Select existing web site, and specify VD name -->
<Publish Dialog="InstallationAddress" Control="Back" Event="NewDialog"
Value="LicenseAgreementDlg" Order="1">1</Publish>
<Publish Dialog="InstallationAddress" Control="Next" Event="DoAction"
Value="UpdatePropsWithSelectedWebSite" Order="1">1</Publish>
<Publish Dialog="InstallationAddress" Control="Next" Event="NewDialog"
Value="InstallDirDlg" Order="2">1</Publish>
<!-- Changed InstallDirDlg back button to navigate to InstallationAddress -->
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog"
Value="InstallationAddress">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath"
Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction"
Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog"
Value="InvalidDirDlg" Order="3"
><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog"
Value="VerifyReadyDlg" Order="4"
>WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty"
Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog"
Value="BrowseDlg" Order="2">1</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog"
Value="InstallDirDlg" Order="1">NOT Installed</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog"
Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog"
Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog"
Value="MaintenanceTypeDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog"
Value="VerifyReadyDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog"
Value="VerifyReadyDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog"
Value="MaintenanceWelcomeDlg">1</Publish>
<Property Id="ARPNOMODIFY" Value="1" />
</UI>
<UIRef Id="WixUI_Common" />
</Fragment>
</Wix>
This may look a bit daunting, but it’s basically a copy of the content contained in the standard defined UI WiX source files (take a look under C:\Program Files (x86)\Windows Installer XML v3.5\wix35-sources\src\ext\UIExtension\wixlib – or your local equivalent).
The only bits that differ are that we’ve defined our own images for the welcome and banner, provided our own licence text, and put a custom dialog entry in the middle (InstallationAddress) with the Next and Back buttons either side adjusted to include our new entry in the sequence.
Before we look at the custom dialog itself, take note of the DoAction event we have defined: it will call UpdatePropsWithSelectedWebSite when Next is clicked. This method is defined in a custom action assembly that we’ve yet to create…more later…
Create another Wix File called InstallationAddressDlg, and paste in the following content:
InstallationAddressDlg
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<CustomAction Id="UpdatePropsWithSelectedWebSite" BinaryKey="WebSiteCA"
DllEntry="UpdatePropsWithSelectedWebSite" Execute="immediate"
Return="check" />
<Binary Id="WebSiteCA" SourceFile="$(var.IISCA.TargetDir)$(var.IISCA.TargetName).CA.dll" />
</Fragment>
<Fragment>
<EnsureTable Id="ComboBox"/>
<Property Id="WEBSITE" Value="1"/>
<Property Id="VD" Value="!(loc.ProductName)"/>
<UI>
<Dialog Id="InstallationAddress" Width="370" Height="270" Title="!(loc.ProductName)">
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17"
Default="yes" Text="!(loc.WixUINext)">
<Condition Action="disable">WEBSITE = "" OR VD = ""</Condition>
<Condition Action="enable"><![CDATA[WEBSITE <> "" AND VD <> ""]]></Condition>
</Control>
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17"
Text="!(loc.WixUIBack)" />
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17"
Cancel="yes" Text="!(loc.WixUICancel)">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
<Control Id="Title" Type="Text" X="15" Y="6" Width="219" Height="28" Transparent="yes"
NoPrefix="yes" Text="!(loc.SelectInstallAddress)" />
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44"
TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" />
<Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Id="SelectWebSiteLabel" Type="Text" X="20" Y="105" Width="290" Height="10"
NoPrefix="yes" Text="!(loc.Site)" />
<Control Id="SelectWebSiteCombo" Type="ComboBox" X="20" Y="117" Width="250" Height="16"
Property="WEBSITE" Sorted="yes" ComboList="yes" />
<Control Type="Text" Id="VirtualDirectoryLabel" Width="290" Height="10" X="20" Y="140"
Text="!(loc.VirtualDirectory)" />
<Control Type="Edit" Id="VirtualDirectoryTextbox" Width="250" Height="15" X="20" Y="152"
Property="VD" />
<Control Type="Text" Id="InfoText1" Width="350" Height="17" X="10" Y="55"
Text="!(loc.Info1)" />
<Control Type="Text" Id="InfoText2" Width="350" Height="17" X="10" Y="75"
Text="!(loc.Info2)" />
</Dialog>
</UI>
</Fragment>
</Wix>
When it comes to creating/modifying these dialogs, I HIGHLY recommend using WiXEdit; it makes the whole process nice and easy 
Again, you can see the reference to the custom action assembly in the top fragment…this will populate our ComboBox with the available web sites. As previously noted, the UpdatePropsWithSelectedWebSite called from the MyUI flow will then update our properties with that selection so we can use it.
In the next post we will look at the creation of the custom assembly so we can tie everything together, but in the meantime I’ll just finish with a screenshot of our custom dialog so you can see where we are heading 

Print | posted on Friday, 25 February 2011 3:22 PM