I'm new to WIX. I wanted to validate the input controls like Textbox is not null and password and confirm password is same.
I tried to do it in the custom action,but i couldn't send the parameters.
If at all i send the parameter how to the return the values with the to stay in the same installation page.
<Dialog Id="XXX" Width="370" Height="270" Title="Installation">
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" >
<Publish Event="DoAction" Value="CheckingPID">1</Publish>
<Publish Event="SpawnDialog" Value="InvalidPidDlg">PIDACCEPTED = "0"</Publish>
<Control Id="Usernamelbl" Type="Text" X="20" Y="100" Width="95" Height="10" NoPrefix="yes" Property="WIXUI_INSTALLDIR" Text="Username:" />
<Control Id="UsernameVal" Type="Edit" X="125" Y="100" Width="200" Height="17" Property="SETUSERNAME" Indirect="no" Disabled="no" />
</Dialog>
<CustomAction Id="CheckingPID" BinaryKey="CustomActionBinary" Impersonate="no" DllEntry="Validate" Execute="immediate" Return="check"/>
[CustomAction]
public static ActionResult Validate(Session session)
{
MessageBox.Show(Session.CustomActionData["SETUSERNAME"]);
return ActionResult.Success;
}
Is this the right way to validate or any other way to validate.
Thanks in advance
Here is a Working Custom Wix Dialog
This code creates a custom UI Dialog with Custom Actions. Purpose of this Dialog is while we are installing a Desktop Application we can setup Db Connection information.
DbConnectionInfo.wxs
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<Property Id="Server" Value="127.0.0.1" />
<Property Id="Port" Value="XXX" />
<Property Id="Database" Value="DbName" />
<Property Id="User" Value="root" />
<Property Id="Password" Value="1234abcA" />
<UI Id="DbConnectionDlgUI">
<Dialog Id="DbConnectionDlg" Width="400" Height="275" Title="Demo : Database Connection Settings">
<Control Id="headerText" Type="Text" X="140" Y="10" Width="260" Height="40" Transparent="no"
Text="{\WixUI_Font_Title}Database Connection Settings Screen" />
<Control Id="SideBar" Type="Bitmap" Text="WixUIBannerBmp" X="0" Y="0" Height="240" Width="130" Image="yes" />
<Control Id="explanationText" X="140" Y="50" NoWrap="no" RightAligned="no" Transparent="yes"
Type="Text" Width="260" Height="100"
Text="{\WixUI_Font_Normal}Before you can use this Service, you need to provide your My Sql Connection settings which is used getting the email database information. If you choose not to install this application, click on the Cancel button to exit." />
<Control Id="ServerLabel" Type="Text" X="160" Y="120" Height="17" Width="65" Transparent="yes" Text="{\WixUI_Font_Normal}Server:" />
<Control Id="ServerTextBox" Type="Edit" X="230" Y="120" Height="17" Width="60" Property="Server" />
<Control Id="PortLabel" Type="Text" X="295" Y="120" Height="17" Width="21" Transparent="yes" Text="{\WixUI_Font_Normal}Port:" />
<Control Id="PortTextBox" Type="Edit" X="325" Y="120" Height="17" Width="30" Property="Port" />
<Control Id="DatabaseLabel" Type="Text" X="160" Y="140" Height="17" Width="65" Transparent="yes" Text="{\WixUI_Font_Normal}Database:" />
<Control Id="DatabaseTextbox" Type="Edit" X="230" Y="140" Height="17" Width="120" Property="Database" />
<Control Id="UserLabel" Type="Text" X="160" Y="160" Height="17" Width="65" Transparent="yes" Text="{\WixUI_Font_Normal}User:" />
<Control Id="UserTextbox" Type="Edit" X="230" Y="160" Height="17" Width="120" Property="User" />
<Control Id="PasswordLabel" Type="Text" X="160" Y="180" Height="17" Width="65" Transparent="yes" Text="{\WixUI_Font_Normal}Password:" />
<Control Id="PasswordTextbox" Type="Edit" X="230" Y="180" Height="17" Width="120" Property="Password" Password="yes"/>
<Control Id="bottomLine" Type="Line" X="130" Y="239" Width="270" Height="1"/>
<Control Id="Back" Type="PushButton" Text="Back" X="208" Y="248" Height="17" Width="60" >
</Control>
<Control Id="Next" Type="PushButton" Text="Next" X="269" Y="248" Height="17" Width="60" Default="yes">
<Publish Event="DoAction" Value="CreateDbConnectionProperties">1</Publish>
</Control>
<Control Id="Cancel" Type="PushButton" Text="Cancel" X="330" Y="248" Height="17" Width="60" Cancel="yes">
<Publish Event="DoAction" Value="CleanUpAction">1</Publish>
<Publish Event="NewDialog" Value="CancelDlg" Order="2">1</Publish>
</Control>
</Dialog>
</UI>
</Fragment>
<Fragment>
<CustomAction Id="CreateDbConnectionProperties" BinaryKey="CustomActionBinary" DllEntry="CreateDbConnectionProperties" />
</Fragment>
</Wix>
CustomAction.cs
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Deployment.WindowsInstaller;
using System.IO;
namespace Demo.InstallerActions
{
public class CustomlActions
{
private readonly static string AppName = "Demo";
[CustomAction]
public static ActionResult CreateDbConnectionProperties(Session session)
{
session.Log("Saving Db Details Started.");
try
{
string Server = session["Server"].Encrypt(AppConstants.SecurityKey,true);
string Database = session["Database"].Encrypt(AppConstants.SecurityKey, true);
string User = session["User"].Encrypt(AppConstants.SecurityKey, true);
string Password = session["Password"].Encrypt(AppConstants.SecurityKey, true);
string Port = session["Port"].Encrypt(AppConstants.SecurityKey, true);
string[] confData = { Server, Database, User, Password, Port };
string appdataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
if (!Directory.Exists($"{appdataPath}\\{AppName}"))
{
Directory.CreateDirectory($"{appdataPath}\\{AppName}");
}
File.WriteAllLines($"{appdataPath}\\{AppName}\\conf.sys", confData);
session.Log("Db Details Saved");
return ActionResult.Success;
}
catch (Exception ex)
{
session.Log($"Configuration File Creation Failed with Error: {ex.Message}");
return ActionResult.Failure;
}
}
[CustomAction]
public static ActionResult CleanUpAction(Session session)
{
session.Log("Cleanup Started.");
try
{
string appdataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
if (!Directory.Exists($"{appdataPath}\\{AppName}"))
Directory.Delete($"{appdataPath}\\{AppName}", true);
session.Log("Db Details Saved");
return ActionResult.Success;
}
catch (Exception ex)
{
session.Log($"Cleanup Error: {ex.Message}");
return ActionResult.Failure;
}
}
}
}
Related
I am trying to run a custom action at the end of my Wix installer but only if certain conditions are met. The user runs through the installer and they will choose one of two modes that set the property 'ServiceType'. The two values for the property are "RegisterNew" and "LinkExisting". You can see by the log below that when the user selects "LinkExisting" in the UI that it changes the property but the custom action still runs.
MSI (c) (D4:44) [11:20:15:686]: PROPERTY CHANGE: Modifying ServiceType property. Its current value is 'RegisterNew'. Its new value: 'LinkExisting'.
Here is my custom action code:
<InstallExecuteSequence>
<Custom Action="RegisterServiceNameCustomAction" Before="InstallFinalize">
<![CDATA[(ServiceType="RegisterNew") AND (NOT Installed)]]>
</Custom>
</InstallExecuteSequence>
<Fragment>
<Binary Id="RegisterServiceCustomActionBinary" SourceFile="$(var.RegisterServiceCustomAction.TargetDir)$(var.RegisterServiceCustomAction.TargetName).CA.dll" />
<CustomAction Id="RegisterServiceNameCustomAction" BinaryKey="RegisterServiceCustomActionBinary" DllEntry="ShowRegisterService" Execute="deferred" Return="check" />
</Fragment>
Here are the different conditions I have tried:
(ServiceType="RegisterNew") AND (NOT Installed)
<![CDATA[(ServiceType="RegisterNew") AND (NOT Installed)]]>
ServiceType="RegisterNew" AND NOT Installed
Here is the code for my custom Dialog where they are selecting making their selection that will change "ServiceType":
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<UI Id="SelectServiceDlg">
<Property Id="ServiceType" Value="RegisterNew" />
<Dialog Id="SelectServiceDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes">
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="[DialogBitmap]" />
<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="Description" Type="Text" X="25" Y="23" Width="280" Height="40" Transparent="yes" NoPrefix="yes" Text="Determine whether you need to register a new service or link an existing service." />
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="Service Type Selection" />
<Control Id="BothScopes" Type="RadioButtonGroup" X="20" Y="55" Width="330" Height="120" Property="ServiceType">
<RadioButtonGroup Property="ServiceType">
<RadioButton Value="RegisterNew" X="0" Y="0" Width="295" Height="16" Text="Register New Service" />
<RadioButton Value="LinkExisting" X="0" Y="60" Width="295" Height="16" Text="Link Existing Service" />
</RadioButtonGroup>
</Control>
<Control Id="RegisterNewServiceDescription" Type="Text" X="33" Y="70" Width="300" Height="36" NoPrefix="yes" Text="Select this option if you are going to register a new service.">
</Control>
<Control Id="LinkExistingDescription" Type="Text" X="33" Y="130" Width="300" Height="36" NoPrefix="yes" Text="Select this option if you are going to link an existing service to this service.">
</Control>
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" />
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" />
<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>
</Dialog>
</UI>
</Fragment>
</Wix>
Here is an image of the UI:
So my question is why is it executing the custom action even though my condition is specifically checking that property?
After some reading of documentation and looking at all of the "properties" of the tag in WIX I decided to try and set a couple of other values and see what happened. I found that when defining the Property if you mark it as secure it then retains its value throughout the entire install process whereas if it is not secure it does not seem to do that. So now my property definition looks like this:
<Property Id="SERVICE_TYPE" Secure="yes" Value="RegisterNew" />
You'll notice that I had to change the name to call caps because when you mark a property as a secure property then you can not have any lowercase letters in the name.
Here is a snippet from the WIX documentation:
Secure -- YesNoType -- Denotes that the property can be passed to the server-side when doing a managed installation with elevated privileges. See the SecureCustomProperties Property for more information.
WIX Documentation For Property Element
I am trying to make changes to the Windows firewall based on a property that is set in a dialog. I can see in the log that the property is being set correctly but the firewall rules are being created regardless of the value of the property.
My code is...
<Component Id="ChangeFirewall" Guid="*" KeyPath="yes">
<Condition><![CDATA[ChgFirewall = "True"]]></Condition>
<fire:FirewallException Id="FW6501" Name="6501" Port="6501"
Protocol="tcp" Scope="any"/>
<fire:FirewallException Id="FW6502" Name="6502" Port="6502"
Protocol="tcp" Scope="any"/>
<fire:FirewallException Id="FW6505" Name="6505" Port="6505"
Protocol="tcp" Scope="any"/>
</Component>
If ChgFirewall is False why does the firewall get changed?
Update: I have added the code for the dialog that sets the CHGFIREWALL property...
<Dialog Id="FirewallDlg" Width="370" Height="270" Title="[ProductName] Setup" NoMinimize="yes">
<Control Id="Description" Type="Text" X="20" Y="20" Width="280" Height="40" Transparent="yes" NoPrefix="yes">
<Text>This program uses TCP ports 6501, 6501, and 6505 for coordinating information between workstations. These ports must be unblocked for it to work correctly</Text>
</Control>
<Control Id="Instructions" Type="Text" X="20" Y="70" Width="280" Height="30" Transparent="yes" NoPrefix="yes">
<Text>This installer can attempt to automatically modify the Windows Firewall for you, or you may manually modify the firewall settings.</Text>
</Control>
<Control Type="RadioButtonGroup" Property="CHGFIREWALL" Id="CHGFIREWALL" Width="340" Height="44" X="20" Y="120">
<RadioButtonGroup Property="CHGFIREWALL">
<RadioButton Text="Have the installer update the firewwall settings for Guru (Recommended)" Height="13" Value="True" Width="340" X="0" Y="0" />
<RadioButton Text="Manually update the firewall settings" Height="13" Value="False" Width="340" X="0" Y="15" />
</RadioButtonGroup>
</Control>
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next">
<Publish Event="EndDialog" Value="Return"></Publish>
</Control>
<Control Id="CancelButton" Type="PushButton" Text="Cancel" Height="17" Width="56" X="180" Y="243" Cancel="yes">
<Publish Event="EndDialog" Value="Exit" />
</Control>
</Dialog>
Also this is my definition of the property...
<Property Id='CHGFIREWALL' Value='False' Secure='yes'/>
As a first step, UPPERCASE the property and set the attribute 'secure="yes". This ensures that the property is passed properly to the server process as explained in the comments here.
Then the issue is how you set the property? Is is set by a custom action, or do you set it in the Property table or on the command line?
In my installer I want user to connect to database. I support 4 database types in my product.
In the connect to database dialog I created, there is a ComboBox control with all supported database types, Edit control where user suppose to enter the connection string and a PushButton, when pressed it will show connection string text template in Edit control according to selected database type in ComboBox. Now, the problem is:
User clicks Show Template button when MSSQL is selected
User alters manually place holder in text template connection string in Edit
control
User realize that he needs MySQL connection
User change value in ComboBox to MySQL and clicks Show Template button and nothing
happens.
To summarize this, after Edit control were manually altered, the Show Template stops working.
Here is WiX code use:
<Fragment>
<!-- Supported databases templates -->
<Property Id="MSSQLTemplate" Value="Data Source=localhost;Initial Catalog=[database];Integrated Security=yes"/>
<Property Id="MySQLTemplate" Value="Server=localhost;Uid=[username];Pwd=[password];Database=[database];" />
<Property Id="DB2Template" Value="Server=localhost;Uid=[username];Pwd=[password];Database=[database];" />
<Property Id="OracleTemplate" Value="Data Source=[database];User Id=[username];Password=[password];" />
<Property Id="PROP_DATABASE_TYPE">MSSQL</Property>
<Property Id="PROP_CONNECTIONSTRING"></Property>
<Binary Id="CA_DLL" SourceFile="$(var.CustomActions.TargetDir)CustomActions.CA.dll" />
<CustomAction Id="caShowTemplate" BinaryKey="CA_DLL" DllEntry="ShowTemplate" Execute="immediate" />
<UI Id="InstallDlg_UI">
<TextStyle Id="Tahoma_Regular" FaceName="Tahoma" Size="8" />
<Property Id="DefaultUIFont" Value="Tahoma_Regular" />
<Dialog Id="InstallDlg" Width="370" Height="270" Title="Amazing Software" NoMinimize="no">
<!-- Database type -->
<Control Id="lblDatabaseType" Type="Text" X="20" Width="100" Y="60" Height="18" NoPrefix="yes" Text="Database Type" />
<Control Id="cbDatabaseServer" Type="ComboBox" X="120" Width="90" Y="60" Height="18" Property="PROP_DATABASE_TYPE" ComboList="yes" Sorted="yes">
<ComboBox Property="PROP_DATABASE_TYPE">
<ListItem Text="MSSQL" Value="MSSQL" />
<ListItem Text="MySQL" Value="MySQL" />
<ListItem Text="Oracle" Value="Oracle" />
<ListItem Text="DB2" Value="DB2" />
</ComboBox>
</Control>
<Control Id="btnShowTemplate" Type="PushButton" X="215" Y="60" Width="85" Height="17" Text="Show Template">
<Publish Event="DoAction" Value="caShowTemplate" Order="1">1</Publish>
<Publish Property="PROP_CONNECTIONSTRING" Value="[PROP_CONNECTIONSTRING]" Order="2">1</Publish>
</Control>
<!-- Connection string -->
<Control Id="lblConnectionString" Type="Text" X="20" Width="100" Y="85" Height="18" NoPrefix="yes" Text="Connection String" />
<Control Id="tbConnectionString" Type="Edit" X="120" Width="180" Y="85" Height="18" Property="PROP_CONNECTIONSTRING" Text="[PROP_CONNECTIONSTRING]" />
<Control Id="CancelButton" Type="PushButton" Text="Cancel" Height="17" Width="56" X="180" Y="243" Cancel="yes">
<Publish Event="EndDialog" Value="Exit" />
</Control>
</Dialog>
<InstallUISequence>
<Show Dialog="InstallDlg" Before="ExecuteAction" />
</InstallUISequence>
</UI>
</Fragment>
And a custom action written in C#:
[CustomAction]
public static ActionResult ShowTemplate(Session session)
{
string selectedDatabase = string.Format("{0}Template", session["PROP_DATABASE_TYPE"]);
session["PROP_CONNECTIONSTRING"] = session[selectedDatabase];
return ActionResult.Success;
}
What am I doing wrong?
Your code doesn’t have any issue. It is a well-known limitation of WIX UI. Check the below discussions for more details.
http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/UI-Edit-Box-not-updating-td5077648.html
Wix Interactions with Conditions, Properties & Custom Actions
During my setup I give an option to use "windows authentication" OR "server authetication". Everything works fine and db gets installed as long as I do "server authentication" and provide db userId and password.
What do I need to do in order install db using "windows authentication" (in wix)?
thanks
My product.wxs file:
<Product Id="*" Name="MySetup2" Language="1033" Version="1.0.0.0" Manufacturer="Hewlett-Packard Company" UpgradeCode="bf1da750-c2fe-4026-9d2b-9d291a61a8b5">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<Binary Id="success_bmp" SourceFile="$(sys.SOURCEFILEDIR)success.bmp" />
<Binary Id="error_bmp" SourceFile="$(sys.SOURCEFILEDIR)error.bmp" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="MySetup2" Level="1" ConfigurableDirectory="INSTALLDIR">
<ComponentGroupRef Id="ProductComponents" />
<ComponentGroupRef Id='MvcApp'/>
<ComponentRef Id='SqlComponent' />
</Feature>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<Binary Id="CreateTableScript" SourceFile="c:\Temp\MyDb.sql" />
<!-- Specify UI -->
<UIRef Id="MyWebUI" />
<!-- .NET Framework 3.0 SP 1 must be installed -->
<Property Id="FRAMEWORKBASEPATH">
<RegistrySearch Id="FindFrameworkDir" Root="HKLM" Key="SOFTWARE\Microsoft\.NETFramework" Name="InstallRoot" Type="raw"/>
</Property>
<util:User Id="SQLUser" Name="[DATABASE_USERNAME]" Password="[DATABASE_PASSWORD]" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="MySetup2" >
<!--<Component Id="Web.config" Guid="2ED81B77-F153-4003-9006-4770D789D4B6">
<File Id="Web.config" Name="Web.config" Source="$(var.SolutionDir)MvcApplication4\Web.config" DiskId="1" KeyPath="yes" />
<util:XmlFile Id="AppSettingsAddNode" File="[INSTALLDIR]Web.config" Action="createElement" ElementPath="/configuration/appSettings" Name="add" Sequence="1" />
<util:XmlFile Id="AppSettingsKeyAttribute" Action="setValue" File="[INSTALLDIR]Web.config" ElementPath="/configuration/appSettings/add" Name="key" Value="AddedDuringInstall" Sequence="2" />
<util:XmlFile Id="AppSettingsValueAttribute" Action="setValue" File="[INSTALLDIR]Web.config" ElementPath="/configuration/appSettings/add" Name="value" Value="This text was added during installation." Sequence="3" />
</Component>
<Directory Id="binFolder" Name="bin">
<Component Id="MvcApplication4.dll" Guid="7FC6DA37-12E5-463d-8E7E-08F73E40CCF2">
<File Id="MvcApplication4.dll" Name="MvcApplication4.dll" Source="$(var.SolutionDir)MvcApplication4\Bin\MvcApplication4.dll" DiskId="1" KeyPath="yes" />
</Component>
</Directory>-->
</Directory>
</Directory>
<Component Id="SqlComponent" Guid="C50999A0-02FD-42d5-9F65-7375318DD328">
<sql:SqlDatabase Id="SqlDatabase"
Database="[DATABASE_NAME]"
Server="[DATABASE_SERVER]"
CreateOnInstall="yes"
DropOnUninstall="yes"
User="SQLUser">
<sql:SqlScript Id="CreateTableScript" ExecuteOnInstall="yes" BinaryKey="CreateTableScript" />
</sql:SqlDatabase>
</Component>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLDIR">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<!-- <Component Id="ProductComponent"> -->
<!-- TODO: Insert files, registry keys, and other resources here. -->
<!-- </Component> -->
</ComponentGroup>
</Fragment>
When I modified this section and removed "User" tag it works using windows authentication. How do I add this tag OR remove it (Condition) based on UI's selection.
<sql:SqlDatabase Id="SqlDatabase"
Database="[DATABASE_NAME]"
Server="[DATABASE_SERVER]"
CreateOnInstall="yes"
DropOnUninstall="yes"
User="SQLUser">
I solved it and created WIX Database Installer like so:
Product.wxs:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
xmlns:sql="http://schemas.microsoft.com/wix/SqlExtension">
<Product Id="*" Name="MySetup2" Language="1033" Version="1.0.0.0" Manufacturer="Hewlett-Packard Company" UpgradeCode="bf1da750-c2fe-4026-9d2b-9d291a61a8b5">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<Binary Id="success_bmp" SourceFile="$(sys.SOURCEFILEDIR)success.bmp" />
<Binary Id="error_bmp" SourceFile="$(sys.SOURCEFILEDIR)error.bmp" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="MySetup2" Level="1" ConfigurableDirectory="INSTALLDIR">
<ComponentGroupRef Id="ProductComponents" />
<ComponentRef Id='SqlComponent.IntegratedAuthentication' />
<ComponentRef Id='SqlComponent.SQLAuthentication' />
</Feature>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<Binary Id="SqlScriptSQLAuthentication" SourceFile="c:\Temp\MyDb.sql" />
<Binary Id="SqlScriptIntegratedAuthentication" SourceFile="c:\Temp\MyDb.sql" />
<!-- .NET Framework 3.0 SP 1 must be installed -->
<Property Id="FRAMEWORKBASEPATH">
<RegistrySearch Id="FindFrameworkDir" Root="HKLM" Key="SOFTWARE\Microsoft\.NETFramework" Name="InstallRoot" Type="raw"/>
</Property>
<UIRef Id="MyWebUI" />
<util:User Id="SQLUser" Name="[DATABASE_USERNAME]" Password="[DATABASE_PASSWORD]" />
<Property Id='DATABASE_USERNAME'></Property>
<Property Id='DATABASE_PASSWORD'></Property>
<Property Id='DATABASE_NAME'></Property>
<Property Id="DATABASE_SERVER">(local)</Property>
<Property Id="DATABASE_LOGON_TYPE">DatabaseIntegratedAuth</Property>
<Property Id="USEINTEGRATEDSECURITY" Secure="yes"></Property>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="MySetup2" >
</Directory>
</Directory>
<Component Id='SqlComponent.SQLAuthentication' Guid='665D641C-3570-4b96-9CA5-2B4C12594A35' KeyPath='yes'>
<Condition><![CDATA[USEINTEGRATEDSECURITY<>1]]></Condition>
<sql:SqlDatabase Id='SqlDatabase.SQLAuthentication' Database='[DATABASE_NAME]' User='SQLUser' Server='[DATABASE_SERVER]' CreateOnInstall='yes' DropOnUninstall='yes' ContinueOnError='no' />
<sql:SqlScript Id='SqlScriptSQLAuthentication' BinaryKey='SqlScriptSQLAuthentication' SqlDb='SqlDatabase.SQLAuthentication' ExecuteOnInstall='yes' />
</Component>
<Component Id='SqlComponent.IntegratedAuthentication' Guid='E5DF48AE-2338-4029-9FDF-8DAA6AD0216D' KeyPath='yes'>
<Condition>USEINTEGRATEDSECURITY = 1</Condition>
<sql:SqlDatabase Id='SqlDatabase.IntegratedAuthentication' Database='[DATABASE_NAME]' Server='[DATABASE_SERVER]' CreateOnInstall='yes' DropOnUninstall='yes' ContinueOnError='no' />
<sql:SqlScript Id='SqlScriptIntegratedAuthentication' BinaryKey='SqlScriptIntegratedAuthentication' SqlDb='SqlDatabase.IntegratedAuthentication' ExecuteOnInstall='yes' />
</Component>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLDIR">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<!-- <Component Id="ProductComponent"> -->
<!-- TODO: Insert files, registry keys, and other resources here. -->
<!-- </Component> -->
</ComponentGroup>
</Fragment>
</Wix>
Notice "Condition" operator based on Windows authentication vs. Server authentication.
Custom Action:
namespace CustomActions
{
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Security.Principal;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.SqlServer.Management.Smo;
using View = Microsoft.Deployment.WindowsInstaller.View;
public static class CustomActions
{
#region Public Methods and Operators
[CustomAction]
public static ActionResult EnumerateSqlServers(Session session)
{
if (null == session)
{
throw new ArgumentNullException("session");
}
session.Log("EnumerateSQLServers: Begin");
// Check if running with admin rights and if not, log a message to
// let them know why it's failing.
if (false == HasAdminRights())
{
session.Log("EnumerateSQLServers: " + "ATTEMPTING TO RUN WITHOUT ADMIN RIGHTS");
return ActionResult.Failure;
}
ActionResult result;
DataTable dt = SmoApplication.EnumAvailableSqlServers(false);
DataRow[] rows = dt.Select(string.Empty, "IsLocal desc, Name asc");
result = EnumSqlServersIntoComboBox(session, rows);
session.Log("EnumerateSQLServers: End");
return result;
}
[CustomAction]
public static ActionResult VerifySqlConnection(Session session)
{
try
{
//Debugger.Break();
session.Log("VerifySqlConnection: Begin");
var builder = new SqlConnectionStringBuilder
{
DataSource = session["DATABASE_SERVER"],
InitialCatalog = "master",
ConnectTimeout = 5
};
if (session["DATABASE_LOGON_TYPE"] != "DatabaseIntegratedAuth")
{
builder.UserID = session["DATABASE_USERNAME"];
builder.Password = session["DATABASE_PASSWORD"];
}
else
{
builder.IntegratedSecurity = true;
}
using (var connection = new SqlConnection(builder.ConnectionString))
{
if (connection.CheckConnection(session))
{
session["ODBC_CONNECTION_ESTABLISHED"] = "1";
}
else
{
session["ODBC_CONNECTION_ESTABLISHED"] = string.Empty;
}
}
session.Log("VerifySqlConnection: End");
}
catch (Exception ex)
{
session.Log("VerifySqlConnection: exception: {0}", ex.Message);
throw;
}
return ActionResult.Success;
}
#endregion
#region Methods
private static ActionResult EnumSqlServersIntoComboBox(Session session, IEnumerable<DataRow> rows)
{
try
{
//Debugger.Break();
session.Log("EnumSQLServers: Begin");
View view = session.Database.OpenView("DELETE FROM ComboBox WHERE ComboBox.Property='DATABASE_SERVER'");
view.Execute();
view = session.Database.OpenView("SELECT * FROM ComboBox");
view.Execute();
Int32 index = 1;
session.Log("EnumSQLServers: Enumerating SQL servers");
foreach (DataRow row in rows)
{
String serverName = row["Name"].ToString();
// Create a record for this web site. All I care about is
// the name so use it for fields three and four.
session.Log("EnumSQLServers: Processing SQL server: {0}", serverName);
Record record = session.Database.CreateRecord(4);
record.SetString(1, "DATABASE_SERVER");
record.SetInteger(2, index);
record.SetString(3, serverName);
record.SetString(4, serverName);
session.Log("EnumSQLServers: Adding record");
view.Modify(ViewModifyMode.InsertTemporary, record);
index++;
}
view.Close();
session.Log("EnumSQLServers: End");
}
catch (Exception ex)
{
session.Log("EnumSQLServers: exception: {0}", ex.Message);
throw;
}
return ActionResult.Success;
}
private static bool HasAdminRights()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
private static bool CheckConnection(this SqlConnection connection, Session session)
{
try
{
if (connection == null)
{
return false;
}
connection.Open();
var canOpen = connection.State == ConnectionState.Open;
connection.Close();
return canOpen;
}
catch (SqlException ex)
{
session["ODBC_ERROR"] = ex.Message;
return false;
}
}
#endregion
}
}
MyWebUI.wxs
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<EnsureTable Id='ComboBox'/>
<!--The custom action DLL itself.-->
<Binary Id="WebAppCA"
SourceFile="C:\Temp\MvcApplication4a\CustomActions\bin\Debug\CustomActions.CA.dll" />
<!--The custom action to enumerate the web sites and app pools into the
appropriate combo boxes.-->
<CustomAction Id="EnumerateSqlServers"
BinaryKey="WebAppCA"
DllEntry="EnumerateSqlServers"
Execute="immediate"
Return="check" />
<CustomAction Id="VerifySqlConnection"
BinaryKey="WebAppCA"
DllEntry="VerifySqlConnection"
Execute="immediate"
Return="check" />
<!--Make sure the enumerate web sites and app pools custom action gets
called, but only called if we are doing and install.-->
<InstallUISequence>
<Custom Action="EnumerateSqlServers"
After="CostFinalize"
Overridable="yes">NOT Installed</Custom>
</InstallUISequence>
<!-- MyWeb UI -->
<UI Id="MyWebUI">
<UIRef Id="WixUI_FeatureTree" />
<UIRef Id="WixUI_ErrorProgressText" />
<!-- Injection of custom UI. -->
<Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="DatabaseInformationDlg">LicenseAccepted = "1"</Publish>
</UI>
</Fragment>
</Wix>
UIDialogs.wxs:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<UI>
<!--Define the dialog to get the Server and Database name information from the user-->
<Dialog Id="DatabaseInformationDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes">
<Control Id="ServerLabel" Type="Text" X="20" Y="62" Width="80" Height="25" NoPrefix="yes" Text="SQL Database:" />
<Control Id="Server" Type="ComboBox" Height="16" Width="180" X="110" Y="60" Property="DATABASE_SERVER">
<ComboBox Property="DATABASE_SERVER">
<ListItem Text="[DATABASE_SERVER]" Value="[DATABASE_SERVER]" />
</ComboBox>
<Publish Property="LOGON_VALID" Value="0">1</Publish>
</Control>
<Control Id="DatabaseType" Type="RadioButtonGroup" X="20" Y="100" Width="290" Height="40" Property="DATABASE_LOGON_TYPE">
<RadioButtonGroup Property="DATABASE_LOGON_TYPE">
<RadioButton Value="DatabaseIntegratedAuth" X="0" Y="0" Width="290" Height="16" Text="Trusted (Windows Authentication)" />
<RadioButton Value="DatabaseAccount" X="0" Y="20" Width="290" Height="16" Text="Specify Username and Password (SQL Authentication)" />
</RadioButtonGroup>
</Control>
<!-- Login -->
<Control Type="Text" Id="UsernameLabel" Width="50" Height="15" X="40" Y="150" Text="&Login:">
<Condition Action="disable"><![CDATA[DATABASE_LOGON_TYPE <> "DatabaseAccount"]]></Condition>
<Condition Action="enable"><![CDATA[DATABASE_LOGON_TYPE = "DatabaseAccount"]]></Condition>
</Control>
<Control Id="Username" Type="Edit" X="110" Y="145" Width="180" Height="18" Property="DATABASE_USERNAME" Text="{80}">
<Condition Action="disable"><![CDATA[DATABASE_LOGON_TYPE <> "DatabaseAccount"]]></Condition>
<Condition Action="enable"><![CDATA[DATABASE_LOGON_TYPE = "DatabaseAccount"]]></Condition>
<Publish Property="LOGON_VALID" Value="0">1</Publish>
</Control>
<!-- Password -->
<Control Type="Text" Id="PasswordLabel" Width="50" Height="15" X="40" Y="173" Text="&Password:">
<Condition Action="disable"><![CDATA[DATABASE_LOGON_TYPE <> "DatabaseAccount"]]></Condition>
<Condition Action="enable"><![CDATA[DATABASE_LOGON_TYPE = "DatabaseAccount"]]></Condition>
</Control>
<Control Id="Password" Type="Edit" X="110" Y="170" Width="180" Height="18" Property="DATABASE_PASSWORD" Text="{80}" Password="yes" >
<Condition Action="disable"><![CDATA[DATABASE_LOGON_TYPE <> "DatabaseAccount"]]></Condition>
<Condition Action="enable"><![CDATA[DATABASE_LOGON_TYPE = "DatabaseAccount"]]></Condition>
</Control>
<Control Id="Test" Type="PushButton" X="40" Y="197" Width="100" Height="17" Text="Test Connection">
<Condition Action="disable"><![CDATA[DATABASE_SERVER = ""]]></Condition>
<Condition Action="enable"><![CDATA[DATABASE_SERVER <> ""]]></Condition>
<!--test connection-->
<Publish Property="ODBC_SERVER" Value="[DATABASE_SERVER]" Order="1">1</Publish>
<Publish Property="ODBC_SERVER" Value="[ComputerName]" Order="1"><![CDATA[DATABASE_SERVER = "(local)"]]></Publish>
<Publish Property="ODBC_CONNECTION_STRING" Value="Driver=SQL Server;Server=[ODBC_SERVER],1433;Uid=[DATABASE_USERNAME];Pwd=[DATABASE_PASSWORD]" Order="2">1</Publish>
<Publish Event="DoAction" Value="VerifySqlConnection" Order="3">1</Publish>
<Publish Property="LOGON_VALID" Value="1" Order="4"><![CDATA[ODBC_CONNECTION_ESTABLISHED]]></Publish>
<Publish Property="LOGON_VALID" Value="0" Order="4"><![CDATA[NOT ODBC_CONNECTION_ESTABLISHED]]></Publish>
<Publish Property="LOGON_ERROR" Value="Unexpected Error" Order="4"><![CDATA[(NOT ODBC_CONNECTION_ESTABLISHED) AND (ODBC_ERROR = "")]]></Publish>
<Publish Property="LOGON_ERROR" Value="[ODBC_ERROR]" Order="4"><![CDATA[NOT ODBC_CONNECTION_ESTABLISHED]]></Publish>
<Publish Event="SpawnDialog" Value="InvalidLogonDlg" Order="5"><![CDATA[NOT ODBC_CONNECTION_ESTABLISHED]]></Publish>
</Control>
<Control Id="TestResult_Success" Type="Bitmap" X="210" Y="10" Width="24" Height="24" Text="success_bmp">
<Condition Action="hide"><![CDATA[LOGON_VALID <> 1]]></Condition>
<Condition Action="show"><![CDATA[LOGON_VALID = 1]]></Condition>
</Control>
<Control Id="TestResult_Failure" Type="Bitmap" X="210" Y="10" Width="24" Height="24" Text="error_bmp">
<Condition Action="hide"><![CDATA[LOGON_VALID = 1]]></Condition>
<Condition Action="show"><![CDATA[LOGON_VALID <> 1]]></Condition>
</Control>
<!-- Back button -->
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&Back">
<Publish Event="NewDialog" Value="LicenseAgreementDlg">1</Publish>
</Control>
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="&Next">
<Publish Property="DATABASE_LOGON_TYPE" Value="[DATABASE_LOGON_TYPE]">1</Publish>
<Publish Property="DATABASE_SERVER" Value="[DATABASE_SERVER]">1</Publish>
<Publish Property="DATABASE_USERNAME" Value="[DATABASE_USERNAME]"><![CDATA[DATABASE_LOGON_TYPE = "DatabaseAccount"]]></Publish>
<Publish Property="DATABASE_PASSWORD" Value="[DATABASE_PASSWORD]"><![CDATA[DATABASE_LOGON_TYPE = "DatabaseAccount"]]></Publish>
<Publish Property="DATABASE_USERNAME"><![CDATA[DATABASE_LOGON_TYPE <> "DatabaseAccount"]]></Publish>
<Publish Property="DATABASE_PASSWORD"><![CDATA[DATABASE_LOGON_TYPE <> "DatabaseAccount"]]></Publish>
<Publish Property="USEINTEGRATEDSECURITY" Value="0"><![CDATA[DATABASE_LOGON_TYPE = "DatabaseAccount"]]></Publish>
<Publish Property="USEINTEGRATEDSECURITY" Value="1"><![CDATA[DATABASE_LOGON_TYPE <> "DatabaseAccount"]]></Publish>
<Condition Action="disable"><![CDATA[LOGON_VALID <> 1]]></Condition>
<Condition Action="enable"><![CDATA[LOGON_VALID = 1]]></Condition>
<Publish Event="NewDialog" Value="DatabaseNameDlg">1</Publish>
</Control>
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="WixUI_Bmp_Banner" />
<Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes">
<Text>Please enter a SQL instance and database name.</Text>
</Control>
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes">
<Text>{\WixUI_Font_Title}SQL instance and database information.</Text>
</Control>
<Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
</Dialog>
<!-- INVALIDE SQL LOGIN -->
<Dialog Id="InvalidLogonDlg" Width="260" Height="105" Title="Invalid Logon">
<Control Id="Return" Type="PushButton" X="102" Y="77" Width="56" Height="17" Default="yes" Cancel="yes" Text="OK">
<Publish Event="EndDialog" Value="Return">1</Publish>
</Control>
<Control Id="Text" Type="Text" X="48" Y="15" Width="194" Height="50" Text="[ODBC_ERROR]" />
<Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24" FixedSize="yes" IconSize="32" Text="WixUI_Ico_Exclam" />
</Dialog>
<!-- DATABASE NAME -->
<Dialog Id="DatabaseNameDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes">
<!-- Connection String -->
<Control Id="DatabaseStringLabel" Type="Text" X="45" Y="73" Width="100" Height="15" TabSkip="no" Text="Database name:" />
<Control Id="DatabaseStringEdit" Type="Edit" X="45" Y="90" Width="220" Height="18" Property="DATABASE_NAME" Text="{100}" />
<Control Id="DatabaseStringLabel123" Type="Text" X="45" Y="120" Width="100" Height="15" TabSkip="no" Text="Use Win: [USEINTEGRATEDSECURITY]--" />
<!-- Back button -->
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&Back">
<Publish Event="NewDialog" Value="DatabaseInformationDlg">1</Publish>
</Control>
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="&Next">
<Publish Event="NewDialog" Value="CustomizeDlg">
<!--if settings are correct, allow next dialog-->
<![CDATA[DATABASE_NAME <> ""]]>
</Publish>
</Control>
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="WixUI_Bmp_Banner" />
<Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes">
<Text>Please enter database configuration</Text>
</Control>
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes">
<Text>{\WixUI_Font_Title}Database Settings</Text>
</Control>
<Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
</Dialog>
</UI>
</Fragment>
</Wix>
OUTPUT:
a working db installer:
See: SqlDatabase Element (Sql Extension)
Remarks
The User attribute references credentials specified in a User element.
If a user is not specified then Windows Authentication will be used by
default using the credentials of the user performing the install to
execute sql strings, etc.
I'm studying Wix to build product installer. I've customized the UI successfully but be wondering how to link a custom action to control event (i.e PushButton).
I have 2 projects:
Product.Wix.CustomActions
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
session.Log("Begin CustomAction1");
MessageBox.Show("CustomActions1");
return ActionResult.Success;
}
Product.Wix.Setup (referenced to Product.Wix.CustomActions project). In Setup.wxs, I have declared a custom action:
<Binary Id="CustomActions" SourceFile="..\Product.Wix.CustomActions\bin\Debug\Product.Wix.CustomActions.CA.dll" />
<CustomAction Id='Action1' BinaryKey='CustomActions' DllEntry='CustomAction1' Execute='immediate' Return='check' />
I have a custom dialog with Connect button and wiring to the action as below:
<Control Id="Connect" Type="PushButton" X="325" Y="75" Width="30" Height="17" Text="...">
<Publish Event="DoAction" Value="Action1">1</Publish>
</Control>
It does not work as I expected it should pop-up a message box when clicking on the Connect button.
Am not sure whether MessageBox.Show() will work. Also its better to go with WIX dialogs as you can capture the option selected by user on the popup.
Example
<Control Id="TestConn" Type="PushButton" X="265" Y="205" Width="70" Height="18" Text="&Test Connection">
<Publish Event="DoAction" Value="Action1">1</Publish>
<Publish Property="ERRORMSG" Value="CustomActions1">ACCEPTED = "1"</Publish>
<Publish Event="SpawnDialog" Value="InvalidDBConnDlg">ACCEPTED = "0"</Publish>
</Control>
<Dialog Id="InvalidDBConnDlg" Width="260" Height="120" Title="[ProductName]">
<Control Id="OK" Type="PushButton" X="102" Y="90" Width="56" Height="17" Default="yes" Cancel="yes" Text="OK" />
<Control Id="Text" Type="Text" X="48" Y="22" Width="194" Height="60" Text="[MSGVAR]" />
<Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24" ToolTip="Information icon" FixedSize="yes" IconSize="32" Text="WixUI_Ico_Info" />
</Dialog>
Custom Action
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
session["MSGVAR"] = "Some Message";
return ActionResult.Success;
}
The log file shows my custom action assemblies could not be loaded properly. The reason is I have unintentionally removed the section:
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" />
</startup>
from the config file. Added it back and everything works now.