Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.
Sign upBranch:master
<?xml version='1.0' encoding='utf-8'?> |
<xs:schemaxmlns:html='http://www.w3.org/1999/xhtml' |
xmlns:wix='http://schemas.microsoft.com/wix/2006/wi' |
xmlns:xs='http://www.w3.org/2001/XMLSchema' |
xmlns:xse='http://schemas.microsoft.com/wix/2005/XmlSchemaExtension' |
targetNamespace='http://schemas.appsecinc.com/wix/SystemToolsExtension' |
xmlns='http://schemas.appsecinc.com/wix/SystemToolsExtension'> |
<xs:annotation> |
<xs:documentation> |
Windows Installer XML System Extension |
This extension significantly simplifies various system tasks that aren't natively supported by Windows installer. |
</xs:documentation> |
</xs:annotation> |
<xs:importnamespace='http://schemas.microsoft.com/wix/2006/wi' /> |
<xs:elementname='CopyFile'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Product' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Module' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Fragment' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
Copies a file outside of component rules. |
par Example: |
code |
<Wix .. xmlns:AppSecIncSystemTools='http://schemas.appsecinc.com/wix/SystemToolsExtension'> |
<Product ..> |
.. |
<Component .. > |
<File Name='test1.txt' src='test1.txt' /> |
<File Name='test2.txt' src='test2.txt' /> |
</Component> |
.. |
<AppSecIncSystemTools:CopyFile Source='[#test1]' Target='[#test1] (Copy)' CopyOnInstall='yes' /> |
<AppSecIncSystemTools:CopyFile Source='[#test2]' Target='[#test2] (Copy)' CopyOnInstall='yes'> |
COPY_CONDITIONAL_FILES = 1 |
</AppSecIncSystemTools:CopyFile> |
</Product> |
</Wix> |
endcode |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:annotation> |
<xs:documentation> |
Condition that determines if the file should be copied. Must be blank or evaluate to true |
for the file to be copied. |
</xs:documentation> |
</xs:annotation> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the file copy operation (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Source'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the source file to be copied.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Target'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the output target.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CopyOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Copy file at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CopyOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Copy file at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Overwrite'use='optional'> |
<xs:annotation> |
<xs:documentation>Specifies the overwrite behavior when the target file exists.</xs:documentation> |
</xs:annotation> |
<xs:simpleType> |
<xs:restrictionbase='xs:NMTOKEN'> |
<xs:enumerationvalue='yes' /> |
<xs:enumerationvalue='no' /> |
<xs:enumerationvalue='error' /> |
</xs:restriction> |
</xs:simpleType> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='MoveFile'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Product' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Module' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Fragment' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
Moves a file outside of component rules. |
par Example: |
code |
<Wix .. xmlns:AppSecIncSystemTools='http://schemas.appsecinc.com/wix/SystemToolsExtension'> |
<Product ..> |
.. |
<Component .. > |
<File Name='test1.txt' src='test1.txt' /> |
<File Name='test2.txt' src='test2.txt' /> |
</Component> |
.. |
<AppSecIncSystemTools:MoveFile Source='[#test1]' Target='[#test1] (Moved)' MoveOnInstall='yes' /> |
<AppSecIncSystemTools:MoveFile Source='[#test2]' Target='[#test2] (Moved)' MoveOnInstall='yes'> |
MOVE_CONDITIONAL_FILES = 1 |
</AppSecIncSystemTools:MoveFile> |
</Product> |
</Wix> |
endcode |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:annotation> |
<xs:documentation> |
Condition that determines if the file should be moved. Must be blank or evaluate to true |
for the file to be moved. |
</xs:documentation> |
</xs:annotation> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the file move operation (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Source'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the source file to be moved.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Target'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the output target.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='MoveOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Move file at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='MoveOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Move file at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Overwrite'use='optional'> |
<xs:annotation> |
<xs:documentation>Specifies the overwrite behavior when the target file exists.</xs:documentation> |
</xs:annotation> |
<xs:simpleType> |
<xs:restrictionbase='xs:NMTOKEN'> |
<xs:enumerationvalue='yes' /> |
<xs:enumerationvalue='no' /> |
<xs:enumerationvalue='error' /> |
</xs:restriction> |
</xs:simpleType> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='DeleteFile'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Product' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Module' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Fragment' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
Deletes a file outside of component rules. |
par Example: |
code |
<Wix .. xmlns:AppSecIncSystemTools='http://schemas.appsecinc.com/wix/SystemToolsExtension'> |
<Product ..> |
.. |
<AppSecIncSystemTools:DeleteFile File='[INSTALLLOCATION]OldFile.txt' DeleteOnInstall='yes' CheckIfExists='yes' /> |
</Product> |
</Wix> |
endcode |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:annotation> |
<xs:documentation> |
Condition that determines if the file should be deleted. Must be blank or evaluate to true |
for the file to be deleted. |
</xs:documentation> |
</xs:annotation> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the file deleted operation (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='File'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the file to be deleted.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='DeleteOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Delete a file at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='DeleteOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Delete a file at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CheckIfExists'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation> |
Check whether a file exists before deleting it. |
If CheckIfExists is 'no' and the file doesn't exist, the custom action will fail. |
</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='CompareVersion'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Product' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Module' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Fragment' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
The extension provides a simple method of correctly comparing two versions in dotted form. |
It sets a property if the version is between the minimum and maximum versions. |
par Example: |
The following example uses a registry search to get the version of an installed |
program, then uses SystemTools::CompareVersion to check that a suitable version is installed. |
code |
<Wix .. xmlns:AppSecIncSystemTools='http://schemas.appsecinc.com/wix/SystemToolsExtension'> |
<Product ..> |
.. |
<Property> |
<RegistrySearch Type='raw' |
Root='HKLM' |
Key='SOFTWAREMicrosoftWindowsCurrentVersionUninstall{FFFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}' |
Name='DisplayVersion' /> |
</Property> |
<AppSecIncSystemTools:CompareVersion InstalledVersion='[PROGRAM_VERSION]' MinimumVersion='3.9' Property='ProgramVersionCorrect' /> |
<Condition Message='Incorrect version!'> |
ProgramVersionCorrect OR Installed |
</Condition> |
.. |
</Product> |
</Wix> |
endcode |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the version compare (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='InstalledVersion'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>The version to be checked</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='MinimumVersion'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>The minimum version.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='MaximumVersion'type='xs:string'use='optional'> |
<xs:annotation> |
<xs:documentation>The maximum version.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Property'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>The property to be set if the installed version lies between the minimum and maximum versions.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='Execute'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Component' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
The extension simplifies authoring MSI packages that need semi-silent command-line execute behavior. |
Execute will run any number of commands after InstallFiles, while ref ScheduleExecute lets you specify the runtime |
behavior and additional runtime conditions just like for any regular custom action. |
An optional condition that combines with options may be specified. |
par Example: |
code |
<Component Guid='ca70ba08-0c57-4fa2-b6c1-57a00123e391'> |
<File Name='SystemToolsMsi.wxs' Source='SystemToolsMsi.wxs' /> |
<AppSecInc:Execute CommandLine='cmd.exe /C copy SystemToolsMsi.wxs SystemToolsMsi_Copy.wxs /y' ErrorMessage='Failed to copy file.' ExecuteOnInstall='yes' ContinueOnError='yes' /> |
<AppSecInc:Execute CommandLine='cmd.exe /C del SystemToolsMsi_Copy.wxs' ErrorMessage='Failed to delete file.' ExecuteOnUnInstall='yes' ContinueOnError='yes' /> |
</Component> |
endcode |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:annotation> |
<xs:documentation> |
Condition that determines if the command is executed. If nested under a component, the condition is |
combined with the parent's conditions. |
</xs:documentation> |
</xs:annotation> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the execute statement (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Directory'type='xs:string'use='optional'> |
<xs:annotation> |
<xs:documentation>Optional directory in which to execute the command.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CommandLine'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Command-line to execute.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ErrorMessage'type='xs:string'use='optional'> |
<xs:annotation> |
<xs:documentation>Optional error message to display instead of a raw error.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ReturnCode'type='xs:integer'use='optional'> |
<xs:annotation> |
<xs:documentation>Optional return code that indicates success of the process, defaults to zero.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ContinueOnError'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Continue on error.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Execute command at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Execute command at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnRollback'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Execute command at rollback time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='ScheduleExecute'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Component' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
To manually schedule an ref Execute action, use ScheduleExecute. This creates a custom action invoking Win32_Execute_Deferred with |
the ID of the ScheduleExecute declaration. Explicit options, including ExecuteOnInstall and ExecuteOnUnInstall still apply and |
ScheduleExecute may also be nested under a component to inherit the component's condition. |
par Example: |
code |
<AppSecInc:ScheduleExecute CommandLine='cmd.exe /C copy Source.txt Target.txt' ExecuteOnInstall='yes' /> |
<AppSecInc:ScheduleExecute CommandLine='cmd.exe /C del Target.txt' ExecuteOnUnInstall='yes' /> |
<AppSecInc:ScheduleExecute CommandLine='cmd.exe /C del Target.txt' ExecuteOnRollback='yes' /> |
.. |
<InstallExecuteSequence> |
<Custom Action='Scheduled_copy' After='InstallFiles'>NOT Installed</Custom> |
<Custom Action='Scheduled_delete' After='InstallFiles'>Installed</Custom> |
<Custom Action='Scheduled_rollback' After='InstallFiles'>NOT Installed</Custom> |
</InstallExecuteSequence> |
endcode |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:annotation> |
<xs:documentation> |
Condition that determines if the command is executed. If nested under a component, the condition is |
combined with the parent's conditions. |
</xs:documentation> |
</xs:annotation> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the execute statement (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Directory'type='xs:string'use='optional'> |
<xs:annotation> |
<xs:documentation>Optional directory in which to execute the command.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CommandLine'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Command-line to execute.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ErrorMessage'type='xs:string'use='optional'> |
<xs:annotation> |
<xs:documentation>Optional error message to display instead of a raw error.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ReturnCode'type='xs:integer'use='optional'> |
<xs:annotation> |
<xs:documentation>Optional return code that indicates success of the process, defaults to zero.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ContinueOnError'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Continue on error.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Execute command at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Execute command at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnRollback'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Execute command at rollback time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='TemplateFile'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Component' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
Implements formatting of a template file. |
The extension allows processing of template files in-place or into a new file. |
To evaluate a property called PROPERTYNAME in a template file, write [PROPERTYNAME]. |
Non-declared properties are not evaluated. Declared properties with empty values are evaluated to their empty value. |
An optional condition that combines with options may be specified as a Condition node under TemplateFile. |
par Example: |
code |
<SystemTools:TemplateFile Source='[#File_template]' Target='[INSTALLLOCATION]File.txt' ExecuteOnInstall='yes'> |
<SystemTools:TemplateFileProperty Name='INSTALLLOCATION' Value='[INSTALLLOCATION]' /> |
<SystemTools:TemplateFileProperty Name='TEST' Value='test' /> |
<SystemTools:TemplateFileProperty Name='Filename' Value='File.txt' /> |
</SystemTools:TemplateFile> |
endcode |
In addition to properties specified by TemplateFileProperty, built-in properties are available. Those are not all |
MSI properties, only those that were declared at build time. If the property has changed during installation, its old |
value is provided by default: overwrite the property value with the current one by explicitly declaring |
TemplateFileProperty with a value. |
code |
<SystemTools:TemplateFileProperty Name='PROPERTY1' Value='[PROPERTY1]' /> |
endcode |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:choiceminOccurs='0'maxOccurs='unbounded'> |
<xs:elementref='TemplateFileProperty'/> |
<xs:elementref='wix:Condition' /> |
</xs:choice> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the template file (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Source'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the template file to be processed.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Target'type='xs:string'use='optional'> |
<xs:annotation> |
<xs:documentation>Target file to be written. When omitted, the source file is processed in-place and overwritten.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Process the template file at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Process the template file at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='ExecuteOnReInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Process the template file at reinstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<!-- |
<xs:attribute name='ExecuteOnRollback' use='optional' type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Process the template file at rollback time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
--> |
</xs:complexType> |
</xs:element> |
<xs:elementname='TemplateFileProperty'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentref='TemplateFile' /> |
</xs:appinfo> |
<xs:documentation> |
Publishes a single property for a template file. |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the property (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Name'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the property to be processed.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Value'type='xs:string'use='optional'> |
<xs:annotation> |
<xs:documentation>Value of the property.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='CopyFiles'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Product' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Module' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Fragment' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
Copies a set of files outside of component rules, with subdirectories. |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:annotation> |
<xs:documentation> |
Condition that determines if the files should be copied. Must be blank or evaluate to true |
for the files to be copied. |
</xs:documentation> |
</xs:annotation> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the files copy operation (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Source'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Directory containing files to be copied.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Wildcard'type='xs:string'use='optional'default='*.*'> |
<xs:annotation> |
<xs:documentation>Wildcard of files to be copied.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Target'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the target directory.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CopyOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Copy file at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CopyOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Copy file at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Recurse'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation> |
Recurse into subdirectories. Behaves like xcopy, copying files that match Wildcard from |
subdirectories. |
</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<!-- |
<xs:attribute name='CreateEmptyDirectories' use='optional' type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Create empty subdirectories.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
--> |
<xs:attributename='Overwrite'use='optional'> |
<xs:annotation> |
<xs:documentation>Specifies the overwrite behavior when the target file exists.</xs:documentation> |
</xs:annotation> |
<xs:simpleType> |
<xs:restrictionbase='xs:NMTOKEN'> |
<xs:enumerationvalue='yes' /> |
<xs:enumerationvalue='no' /> |
<xs:enumerationvalue='error' /> |
</xs:restriction> |
</xs:simpleType> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='MoveFiles'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Product' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Module' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Fragment' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
Moves a set of files outside of component rules, with subdirectories. |
Operates on a best-effort basis, ie. neither source nor target directories need to exist for the operation |
to succeed. Does not move empty directories, only creates target directories that have files. |
The move file operation will fail and the installation will rollback on first error. |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:annotation> |
<xs:documentation> |
Condition that determines if the files should be moved. Must be blank or evaluate to true |
for the files to be moved. |
</xs:documentation> |
</xs:annotation> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the files move operation (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Source'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Directory containing files to be moved.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Wildcard'type='xs:string'use='optional'default='*.*'> |
<xs:annotation> |
<xs:documentation>Wildcard of files to be moved.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Target'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Name of the target directory.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='MoveOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Move file at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='MoveOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Move file at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Recurse'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation> |
Recurse into subdirectories. Behaves like xcopy, moving files that match Wildcard from |
subdirectories, then deletes the individual files that have been moved. |
</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='DeleteEmptyDirectories'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Delete leftover empty subdirectories.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<!-- |
<xs:attribute name='CreateEmptyDirectories' use='optional' type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Create empty subdirectories.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
--> |
<xs:attributename='Overwrite'use='optional'> |
<xs:annotation> |
<xs:documentation>Specifies the overwrite behavior when the target file exists.</xs:documentation> |
</xs:annotation> |
<xs:simpleType> |
<xs:restrictionbase='xs:NMTOKEN'> |
<xs:enumerationvalue='yes' /> |
<xs:enumerationvalue='no' /> |
<xs:enumerationvalue='error' /> |
</xs:restriction> |
</xs:simpleType> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='DeleteFiles'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Product' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Module' /> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='Fragment' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
Deletes a set of files outside of component rules, with subdirectories. |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:simpleContent> |
<xs:extensionbase='xs:string'> |
<xs:annotation> |
<xs:documentation> |
Condition that determines if the files should be deleted. Must be blank or evaluate to true |
for the files to be deleted. |
</xs:documentation> |
</xs:annotation> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the files delete operation (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Path'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Path containing files to be deleted.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Wildcard'type='xs:string'use='optional'default='*.*'> |
<xs:annotation> |
<xs:documentation>Wildcard of files to be deleted.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='DeleteOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Delete file at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='DeleteOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Delete file at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Recurse'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation> |
Recurse into subdirectories. Deletes files, directories and subdirectories. |
</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='DeleteEmptyDirectories'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Delete leftover empty subdirectories.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
</xs:extension> |
</xs:simpleContent> |
</xs:complexType> |
</xs:element> |
<xs:elementname='RegistryKeyCopy'> |
<xs:annotation> |
<xs:appinfo> |
<xse:parentnamespace='http://schemas.microsoft.com/wix/2006/wi'ref='RegistryKey' /> |
</xs:appinfo> |
<xs:documentation> |
<![CDATA[ |
Defines a registry key copy and restore operation that can be scheduled across a major upgrade. |
par Example: |
The following example will backup the HKEY_LOCAL_MACHINESoftwareAppSecIncSystemToolsMsi key before it's written by |
the installer and roll back the change if installation fails. |
code |
<Component Guid='A9A913DB-CDA9-486c-B4C6-2A109661AEBD'> |
<RegistryKey Action='create' Root='HKLM' Key='SOFTWAREAppSecIncSystemToolsMsi'> |
<RegistryValue Name='ProductCode' Value='[ProductCode]' Action='write' Type='string' /> |
<AppSecInc:RegistryKeyCopy TargetRoot='HKEY_LOCAL_MACHINE' TargetPath='SOFTWAREAppSecIncSystemToolsMsiBackup' |
CopyOnInstall='yes' RestoreOnRollback='yes' Overwrite='yes' CheckIfExists='yes' /> |
</RegistryKey> |
</Component> |
endcode |
Note that Windows Installer already performs the restore operation, but it is not designed to work across a major |
upgrade. The default scheduling of this extension simply enables registry key backup. In order to perform a |
backup and rollback in a major upgrade scneario you must schedule the backup custom action before a previous |
version of the product is uninstalled. |
code |
<Custom Action='Win32_RegistryCopy_Deferred_Install' Before='RemoveExistingProducts'>UpgradingCondition</Custom> |
endcode |
The extension will now backup the registry key before uninstall happens, then restore it on rollback of the major |
upgrade in an event of failure. |
]]> |
</xs:documentation> |
</xs:annotation> |
<xs:complexType> |
<xs:choiceminOccurs='0'maxOccurs='unbounded'> |
<xs:elementref='wix:Condition' /> |
</xs:choice> |
<xs:attributename='Id'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Identifier for the registry key copy (primary key).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='TargetRoot'default='HKEY_LOCAL_MACHINE'type='RegistryKeyType'> |
<xs:annotation> |
<xs:documentation>Target registry root.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='TargetPath'type='xs:string'use='required'> |
<xs:annotation> |
<xs:documentation>Target registry key path.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CheckIfExists'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Check whether the source registry key exists before performing a copy operation.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='Overwrite'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Overwrite target key if it exists.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CopyOnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Copy registry key at install time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='CopyOnUnInstall'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Copy registry key at uninstall time.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='RemoveSource'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Remove the source registry key after copy (ie. move).</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
<xs:attributename='RestoreOnRollback'use='optional'type='YesNoType'> |
<xs:annotation> |
<xs:documentation>Restore registry key contents on rollback.</xs:documentation> |
</xs:annotation> |
</xs:attribute> |
</xs:complexType> |
</xs:element> |
<xs:simpleTypename='YesNoType'> |
<xs:annotation> |
<xs:documentation>Values of this type will either be 'yes' or 'no'.</xs:documentation> |
</xs:annotation> |
<xs:restrictionbase='xs:NMTOKEN'> |
<xs:enumerationvalue='no' /> |
<xs:enumerationvalue='yes' /> |
</xs:restriction> |
</xs:simpleType> |
<xs:simpleTypename='RegistryKeyType'> |
<xs:annotation> |
<xs:documentation>Windows registry key types.</xs:documentation> |
</xs:annotation> |
<xs:restrictionbase='xs:NMTOKEN'> |
<xs:enumerationvalue='HKEY_LOCAL_MACHINE' /> |
<xs:enumerationvalue='HKEY_CURRENT_USER' /> |
<xs:enumerationvalue='HKEY_CURRENT_CONFIG' /> |
<xs:enumerationvalue='HKEY_CLASSES_ROOT' /> |
<xs:enumerationvalue='HKEY_USERS' /> |
</xs:restriction> |
</xs:simpleType> |
</xs:schema> |
Copy lines Copy permalink
I am trying to edit an XML file with Wix. I am using the WixUtilExtension bundled with Wix 3.7. The xml file is a settings file created in Visual Studio 2010 for a C# application. In this file, I am using an element which is used to store multiple string values in an array. This is the content of the unaltered settings file:
I want to add <string>
elements to the <ArrayOfString>
element in this file. One way to do this is by using an <XmlConfig>
element from the wix/UtilExtension namespace. I have added this element to the component which holds the config file like this:
This results in the addition of one <string>
element to the <ArrayOfString>
element. To add another <string>
element to the settings file, another XmlConfig element has to be added to the <Component>
element of the setup project with a different Id attribute and a higher value for the Sequence attribute like this:
After installation of the msi, the <ArrayOfString>
element in the settings file looks like this:
I have found out that it is possible to set the Value attribute of an <XmlConfig>
attribute to the value of a property like this:
This is good. I would like the user to be able to add multiple values in the installation process dynamically so that a variable amount of <string>
elements can be added to the settings file.My first approach was to use a <?foreach?>
statement like this:
There are a few problems with this approach:
- The foreach statement uses a preprocessor variable which cannot be set to the value of a property.
- The value of the Sequence attribute stays the same.
I would like the user to store the values for the string elements in a Property which separates the values by semicolons and then parse them in a foreach statement like this:
This throws the following error:
Is there any way I can create a variable amount of elements with the XmlFile or the XmlConfig element? Is the only solution to this problem a CustomAction?
3 Answers
As an addition to BdN3504's answer.. instead of the whole
thing. I would suggest the use of
This ensures that the XmlConfig table is included in the output MSI, even if it is empty.(I would have just put this as a comment. but I don't have the reputation apparently)
Based on Rob's answer, here is my new approach to adding multiple elements to an XML config file with Wix. I did not want to write C++ code, that is why I used DTF in my CustomAction.
I am going to describe how to turn a string containing multiple elements using a delimiter into multiple XML elements.
First there needs to be a property in the setup file containing the delimited string.
This property could be populated by the user in a dialog, of course.
Next, a CustomAction has to be written. To make use of the DTF, a reference to the Microsoft.Deployment.WindowsInstaller.dll has to be added to the C# CustomAction project. The namespace Microsoft.Deployment.WindowsInstaller should be included with a using directive in that project. My CustomAction looks like this:
Here, at first the Property StringArray is read into a local variable which is converted to a string array. The following line establishes a connection to the current database used by the installer. A handle on the table XmlConfig is created, which is the table where the XML elements are added to. To insert the right values into that table, it is best to create an installer file which contains such a table and then take a look at that table in an editor like orca or InstEd.
In the xpath, backslashes have to be escaped by using double backslashes. The id variable holds the name of the temporary record, using a simple string and a number works flawlessly. The sequence has to be incremented for each element. I could not find any documentation on the values of the flags column, but I have found out that its value is set to 273 for elements that are created and 289 for elements that get deleted.
Once the record is filled with the correct values, it gets added to the XmlConfig table by using the InsertTemporary method of the view object. This is done for each element found in the delimited string.
A problem I have come across is that this CustomAction fails, if the XmlConfig table does not exist. To counter this problem I have added the following code to the setup file, which adds an element to the XML file and immediately deletes that element. I guess there could be a cleaner solution, but this was the easiest one for me.
Finally, the CustomAction has to be added to the setup project. By adding a reference to the CustomAction project in the setup project, the location of the binary can be specified like this:
Of the Author. The DELLORTO TUNING MANUAL. 2.1 Carburettor diagram and principal parts. Throttle valve (see figure 28) make the pump start to work. Dellorto phbh 28 manual.
The CustomAction has to be executed immediately, otherwise it won't be able to access the session variable:
To determine the right position for the CustomAction in the installation sequence, I relied on this article by Bob Arnson.
Yes, this is possible but if you want to have this determined at install time then the preprocessor is not an option. The preprocessor executes during the build process.
To get what you want, you'll need to write another custom action that takes the arbitrarily long set of user data and adds temporary rows to the XmlConfig
table. The WcaAddTempRecord()
function in srccawcautilwcawrap.cpp
can do the work. The srccawixcadllRemoveFoldersEx.cpp
is a pretty good example of using WcaAddTempRecord()
to add rows to the RemoveFile
table. You'll want to do similarly.
Not the answer you're looking for? Browse other questions tagged wixapp-configelements or ask your own question.
We've been using WiX for a while now, and despite the usual gripes about ease of use, it's going reasonably well. What I'm looking for is useful advice regarding:
- Setting up a WiX project (layout, references, file patterns)
- Integrating WiX into solutions, and build/release processes
- Configuring installers for new installations and upgrades
- Any good WiX hacks you'd like to share
si618
locked by WillDec 13 '12 at 21:54
This question exists because it has historical significance, but it is not considered a good, on-topic question for this site, so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. More info: help center.
Read more about locked posts here.
31 Answers
Keep variables in a separate
wxi
include file. Enables re-use, variables are faster to find and (if needed) allows for easier manipulation by an external tool.Define Platform variables for x86 and x64 builds
Store the installation location in the registry, enabling upgrades to find the correct location. For example, if a user sets custom install directory.
Note: WiX guru Rob Mensching has posted an excellent blog entry which goes into more detail and fixes an edge case when properties are set from the command line.
Examples using 1. 2. and 3.
and
The simplest approach is always do major upgrades, since it allows both new installs and upgrades in the single MSI. UpgradeCode is fixed to a unique Guid and will never change, unless we don't want to upgrade existing product.
Note: In WiX 3.5 there is a new MajorUpgrade element which makes life even easier!
Creating an icon in Add/Remove Programs
On release builds we version our installers, copying the msi file to a deployment directory. An example of this using a wixproj target called from AfterBuild target:
Use heat to harvest files with wildcard (*) Guid. Useful if you want to reuse WXS files across multiple projects (see my answer on multiple versions of the same product). For example, this batch file automatically harvests RoboHelp output.
There's a bit going on,
robocopy
is stripping out Subversion working copy metadata before harvesting; the-dr
root directory reference is set to our installation location rather than default TARGETDIR;-var
is used to create a variable to specify the source directory (web deployment output).Easy way to include the product version in the welcome dialog title by using Strings.wxl for localization. (Credit: saschabeaumont. Added as this great tip is hidden in a comment)
Save yourself some pain and follow Wim Coehen's advice of one component per file. This also allows you to leave out (or wild-card
*
) the component GUID.Rob Mensching has a neat way to quickly track down problems in MSI log files by searching for
value 3
. Note the comments regarding internationalization.When adding conditional features, it's more intuitive to set the default feature level to 0 (disabled) and then set the condition level to your desired value. If you set the default feature level >= 1, the condition level has to be 0 to disable it, meaning the condition logic has to be the opposite to what you'd expect, which can be confusing :)
si618
Checking if IIS is installed:
Checking if IIS 6 Metabase Compatibility is installed on Vista+:
Keep all IDs in separate namespaces
- Features begin with
F.
Examples: F.Documentation, F.Binaries, F.SampleCode. - Components begin with
C.
Ex: C.ChmFile, C.ReleaseNotes, C.LicenseFile, C.IniFile, C.Registry - CustomActions are
CA.
Ex: CA.LaunchHelp, CA.UpdateReadyDlg, CA.SetPropertyX - Files are
Fi.
- Directories are
Di.
- and so on.
I find this helps immensely in keeping track of all the various id's in all the various categories.
Fantastic question. I'd love to see some best practices shown.
I've got a lot of files that I distribute, so I've set up my project into several wxs source files.
I have a top level source file which I call Product.wxs which basically contains the structure for the installation, but not the actual components. This file has several sections:
The rest of the .wix files are composed of Fragments that contain ComponentGroups which are referenced in the Feature tag in the Product.wxs. My project contains a nice logical grouping of the files that I distribute
This isn't perfect, my OO spider sense tingles a bit because the fragments have to reference names in the Product.wxs file (e.g. the DirectoryRef) but I find it easier to maintain that a single large source file.
![File type identifier File type identifier](https://user-images.githubusercontent.com/16729806/35086165-ae24bca6-fc7f-11e7-9fee-29bb8741c3b5.png)
I'd love to hear comments on this, or if anyone has any good tips too!
Add a checkbox to the exit dialog to launch the app, or the helpfile.
..
If you do it this way, the 'standard' appearance isn't quite right. The checkbox is always a gray background, while the dialog is white:
One way around this is to specify your own custom ExitDialog, with a differently-located checkbox. This works, but seems like a lot of work just to change the color of one control. Another way to solve the same thing is to post-process the generated MSI to change the X,Y fields in the Control table for that particular CheckBox control. The javascript code looks like this:
Running this code as a command-line script (using cscript.exe) after the MSI is generated (from light.exe) will produce an ExitDialog that looks more professional:
Creating Live, Test, Training, .. versions using the same source files.
In a nutshell: Create unique UpgradeCode for each installer and automagically define the first character of each Guid for each installer, leaving the remaining 31 unique.
Prerequisites
Assumptions
- WiX variables are used to define UpgradeCode, ProductName, InstallName.
- You already have a working installer. I wouldn't attempt this until you do.
- All your Components are kept in one file (Components.wxs). This process will work if you have multiple files, there will just be more work to do.
Directory Structure
- Setup.Library
- All wxs files (Components, Features, UI Dialogs, ..)
- Common.Config.wxi (ProductCode='*', ProductVersion, PlatformProgramFilesFolder, ..)
- Setup.Live (wixproj)
- Link all Setup.Library files using 'Add Existing File' -> 'Add As Link' (the little down arrow button right next to the Add button in Visual Studio)
- Config.wxi (has unique UpgradeCode, ProductName, InstallName, ..)
- Setup.Test, ..
- as per live but Config.wxi is configured for Test environment.
Process
- Create Setup.Library directory and move all your wxs and wxi files (except Config.wxi) from existing project.
- Create Setup.Live, Setup.Test, etc as per normal wixproj.
- Add BeforeBuild target in wixproj in Setup.Live, etc to perform MSBuild Community Task FileUpdate to modify Guids (I used A for Live, B for Test and C for training)
- Add AfterBuild target to revert Components.wxs Guids back to 0.
- Verify with Orca that each component in each MSI has the modified guid.
- Verify that original guids are restored.
- Verify that each MSI is installing (and upgrading) correct product and location.
Example Config.wxi
Example Config.Common.wxi
Example Components.wxs
Note: I would now suggest leaving the Guid attribute out of Component (equivalent of *
), using one file per component and setting the file as the keypath. This removes the need for calling ModifyComponentsGuids
and RevertComponentsGuids
targets shown below. This might not be possible for all your components though.
Example Setup.Live.wixproj
Final thoughts
- This process should also work for creating different installers for different merge modules (Live, Test, .. as features) for the same installer. I went with different installers as it seemed a safer option, there is more risk that someone might upgrade Live instead of Training if they're on the same box and you just use features for the different merge modules.
- If you use your MSI to perform upgrades as well as new installs i.e. the major upgrade only approach, and you save your installation location in the registry, remember to create a variable for the key name for each install.
- We also create variables in each Config.wxi to enable unique virtual directory names, application pools, database names, et cetera for each installer.
UPDATE 1:Auto-generating component Guids removes the need for calling FileUpdate task if you create component with Guid='*' for each file, setting the file as the keypath.
UPDATE 2: One of the issues we've come up against is if you don't auto-generate your component Guid's and the build fails, then the temp files need to be manually deleted.
UPDATE 3: Found a way to remove reliance on svn:externals and temporary file creation. This makes the build process more resilient (and is best option if you can't wildcard your Guids) and less brittle if there is a build failure in light or candle.
UPDATE 4: Support for Multiple Instances using instance transforms is in WiX 3.0+, definitely also worth a look.
si618
Using the Msi Diagnostic logging to get detailed failure Informationmsiexec /i Package.msi /l*v c:Package.log
Where is the name of your package and is where you want the output of the log
Wix Intro Video
Oh and Random Wix intro video featuring 'Mr. WiX' Rob Mensching is 'conceptual big picture' helpful.
Use Javascript CustomActions because they're soooo easy
People have said that Javascript is the wrong thing to use for MSI CustomActions. Reasons given: hard to debug, hard to make it reliable. I don't agree. It's not hard to debug, certainly no harder than C++. Its just different. I found writing CustomActions in Javascript to be super easy, much easier than using C++. Much faster. And just as reliable.
There's just one drawback: Javascript CustomActions can be extracted via Orca, whereas a C/C++ CA would require reverse-engineering. If you consider your installer magic to be protected intellectual property, you will want to avoid script.
If you use script, you just need to start with some structure. Here's some to get you started.
Javascript 'boilerplate' code for CustomAction:
Then, register the custom action with something like this:
You can, of course, insert as many Javascript functions as you like, for multiple custom actions. One example: I used Javascript to do a WMI query on IIS, to get a list of existing websites, to which an ISAPI filter could be installed. This list was then used to populate a listbox shown later in the UI sequence. All very easy.
On IIS7, there is no WMI provider for IIS, so I used the shell.Run()
approach to invoke appcmd.exe to perform the work. Easy.
Related question: About Javascript CustomActions
Peter Tate has already shown how you can define reusable ComponentGroup definitions in separate wix fragments. Some additional tricks related to this:
Directory Aliasing
The component group fragments don't need to know about directories defined by the main product wxs. In your component group fragment you can talk about a folder like this:
Then the main product can alias one of its directories (e.g. 'productInstallFolder') like this:
Dependency Graph
ComponentGroup elements can contain ComponentGroupRef child elements. This is great if you have a big pool of reusable components with a complex dependency graph between them. You just set up a ComponentGroup in its own fragment for each component and declare the dependencies like this:
If you now reference component group 'B' in your setup because it is a direct dependency of your application, it will automatically pull in component group 'A' even if the application author never realized that it was a dependency of 'B'. It 'just works' as long as you don't have any circular dependencies.
Reusable wixlib
The above dependency graph idea works best if you compile the big-pool-o-reusable-components into a reusable wixlib with lit.exe. When creating an application setup, you can reference this wixlib much like a wixobj file. The candle.exe linker will automatically eliminate any fragments that are not 'pulled in' by the main product wxs file(s).
I'm surprised no one has mentioned using T4 to generate the WXS file during build. I learned about this by way of Henry Lee @ New Age Solutions.
Essentially, you create a custom MSBuild task to execute a T4 template, and that template outputs the WXS just before the Wix project is compiled. This allows you to (depending on how you implement it) automatically include all assemblies output from compiling another solution (meaning that you no longer have to edit the wxs ever time you add a new assembly).
Using Heat.exe to smash face and inflict 'Epic Pwnage' on painfully large installs
Expanding on Si's and Robert-P's answers about heat.
Translation:(Using heat to avoid typing individual files into the project by hand and for automating builds for an overall easier process.)
WiX 2.0 Heat Syntax detailed
For newer versions (not all that different from older versions but there are potentially annoying syntax changes..) go to the directory Heat is in from the cmd.exe and just type in heat but I have a example one right here for help with newer versions if needed.
Adding the following to your Build Event in visual studio 2010.
(Right Click Project->Properties ->Build Events-> Pre-Build Events)$(WIX)binheat.exe' dir '$(EnviromentVariable)' -cg GroupVariable -gg -scom -sreg -sfrag -srd -dr INSTALLLOCATION -var env.LogicPath -out '$(FragmentDir)FileName.wxs
Generates Guids when heat is run(as in when you execute the command above)
Dont grab 'COM files'
Dont grab 'Registry Files'
Dont grab 'Fragments'
Dont grab the 'root Dir'
The Wolf of Wall Street (2013) 2013 (tt0993846) Jordan Belfort is a Long Island penny stockbroker who served 22 months in prison for defrauding investors in a. The wolf of wall street torrent download 1080p kickass.
dir indicates you want Heat to look in a folder
The name of the variable you would add to the Preprocessor variables in the (Right click project, Go to properties) project properties->Build section where it says Define preprocessor variables (assumes visual studio 2010)
No double quotes but end with a semicolon
The ComponentGroup that will be referenced from the fragment created to the main wxs file
The fragment directory where the output wxs fragment will be stored
The the name of the file
Full tutorial here, So freakin helpful
Part 1Part 2
Terrance
Including COM Objects:
heat
generates all most (if not all) the registry entries and other configuration needed for them. Rejoice!
Including Managed COM Objects (aka, .NET or C# COM objects)
Using heat
on a managed COM object will give you an almost complete wix document.
If you don't need the library available in the GAC (ie, globally available: MOST of the time you do not need this with your .NET assemblies anyway - you've probably done something wrong at this point if it's not intended to be a shared library) you will want to make sure to update the CodeBase
registry key to be set to [#ComponentName]
. If you ARE planning on installing it to the GAC (eg, you've made some new awesome common library that everyone will want to use) you must remove this entry, and add two new attributes to the File
element: Assembly
and KeyPath
. Assembly should be set to '.net' and KeyPath
should be set to 'yes'.
However, some environments (especially anything with managed memory such as scripting languages) will need access to the Typelib as well. Make sure to run heat
on your typelib and include it. heat
will generate all the needed registry keys. How cool is that?
Installing to C:ProductName
Formatted File Recovery Software
Some applications need to be installed to C:ProductName
or something similar, but 99.9% (if not 100%) of the examples in the net install to C:Program FilesCompanyNameProductName
.
The following code can be used to set the TARGETDIR
property to the root of the C:
drive (taken from the WiX-users list):
NOTE: By default, TARGETDIR
does not point to C:
! It rather points to ROOTDRIVE
which in turn points to the root of the drive with the most free space (see here) - and this is not necessarily the C:
drive. There might be another hard drive, partition, or USB drive!
![Formatted Formatted](https://d2x3xhvgiqkx42.cloudfront.net/12345678-1234-1234-1234-1234567890ab/9432a2ad-f01d-4a3d-ae53-370c37e15e62/2018/01/16/6955b06d-39bd-4ed6-9675-fa833995783b.png)
Then, somewhere below your <Product ..>
tag, you need the following directory tags as usual:
Environmental Variables
When compiling your Wxs documents to wixobj code, you can make use of environmental variables to determine various information. For example, lets say you want to change which files get included in a project. Lets say you have an environmental variable called RELEASE_MODE, that you set right before you build your MSI (either with a script or manually, it doesn't matter) In your wix source, you can do something like:
and then later in your code, use it in place to on the fly change your wxs document, eg:
Using the RobM special 'Remember Property' pattern
Creating Custom Action for WIX written in managed code (C#) without Votive
Editing Dialogs
One good ability to edit dialogs is using SharpDevelop in a version 4.0.1.7090 (or higher). With help of this tool a standalone dialog (wxs files from WiX sources like e.g. InstallDirDlg.wxs) can be opened, previewed and edited in Design view.
Setting the IIS enable32BitAppOnWin64 flag http://trycatchfail.com/blog/post/WiX-Snippet-change-enable32BitAppOnWin64.aspx
EdmundYeung99
Modify the 'Ready to install?' dialog (aka VerifyReadyDlg) to provide a summary of choices made.
It looks like this:
alt text http://i46.tinypic.com/s4th7t.jpg
Do this with a Javascript CustomAction:
Javascript code:
Declare the Javascript CA:
Attach the CA to a button. In this example, the CA is fired when Next is clicked from the CustomizeDlg:
Related SO Question: How can I set, at runtime, the text to be displayed in VerifyReadyDlg?
Put Components which may be patched individually inside their own Fragments
It goes for both making product installers and patches that if you include any component in a fragment, you must include all of the components in that fragment. In the case of building an installer, if you miss any component references, you'll get a linking error from light.exe. However, when you make a patch, if you include a single component reference in a fragment, then all changed components from that fragment will show up in your patch.
like this:
instead of this:
Also, when patching using the 'Using Purely WiX' topic from the WiX.chm help file, using this procedure to generate the patch:
it's not enough to just have the 1.1 version of the product.wixpdb built using the components in separate fragments. So be sure to correctly fragment your product before shipping.
Dave Andersen
Printing EULA from Wix3.0 and later
1) When you compile your wix source code, the light.exe must reference the WixUIExtension.dll in command line. Use the command line switch -ext for this.
2) If when you add the reference to the WixUIExtension.dll, your project fails to compile, this is most likely because of clashes of Dialog IDs, i.e. your project was using the same IDs of dialogs as some standard dialogs in WixUIExtension.dll, give different IDs to your dialogs. This is quite common problem.
3) Your license dialog must have ScrollableText control with the id 'LicenseText'. Wix searches for exactly this name of control when it prints.
and a PushButton which refers to the custom action
4) Define CustomAction with the like this:
Note: BinaryKey is different in Wix3.0 comparing to Wix2.0 and must be exactly 'WixUIWixca' (case sensitive).
When user presses the button he/she will be presented with the standard Select Printer Dialog and will be able to print from there.
We display the product version somewhere (tiny) in the first screen of the GUI. Because people tend to make mistakes in picking the right version every time. (And keep us developers searching for ages.)
We've set up TFSBuild to also generate transforms (.mst files) with the configuration for our different environments. (We know about all environments we need to deploy to).
Since the original weblog post by Grant Holliday is down, I copy pasted its contents here:
MSBuild task to generate MSI Transform files from XMLMarch 11 2008
In my previous post I described how you can use MSI Transform (*.mst) files to separate environment-specific configuration settings from a generic MSI package.
Although this provides a level of flexibility in your configuration, there are two down-sides of Transform files:
- They’re a binary format
- You can’t “edit” or “view” a transform file. You have to apply it or re-create it to see what changes it includes.
Fortunately we can use the Microsoft Windows Installer Object Library (c:windowssystem32msi.dll) to open MSI “databases” and create transform files.
Credits go again to Alex Shevchuk – From MSI to WiX – Part 7 – Customising installation using Transforms for showing us how to achieve this with VbScript. Essentially all I’ve done is taken Alex’s example and using Interop.WindowsInstaller.dll I’ve implemented an MSBuild task.The MSBuild Task
Download the source code & example transforms.xml here (~7Kb Zipped VS2008 Solution)
Before deploying an install package I always control the content of it.
It's just a simple call at the command line (according to Terrences post) open command line and enter
This will extract package contents to an subdir 'Extract' with the current path.
Instead of ORCA use InstEd which is a good tool for viewing MSI tables. Also it has the ability to diff two packages by Transform -> Compare To..
Additionally a Plus version with additional functionality is available. But also the free version offers a good alternative for Orca.
user432758
Registering .NET assemblies for COM Interop with x86/x64 compatibility
NB This fragment is essentially the same as REGASM Assembly.dll /codebase
A couple of things are going on in this sample so here's the code and I'll explain it afterwards..
If you were wondering, this is actually for an ASCOM Telescope Driver.
First, I took advice from above and created some platforma variables in a seperate file, you can see those scattered through the XML.
The if-then-else part near the top deals with x86 vs x64 compatibility. My assembly targets 'Any CPU' so on an x64 system, I need to register it twice, once in the 64-bit registry and once in the 32-bit Wow6432Node
areas. The if-then-else sets me up for this, the values are used in a foreach
loop later on. This way, I only have to author the registry keys once (DRY principle).
The file element specifies the actual assembly dll being installed and registered:
Nothing revolutionary, but notice the Assembly='.net'
- this attribute alone would cause the assembly to be put into the GAC, which is NOT what I wanted. Using the AssemblyApplication
attribute to point back to itself is simply a way of stopping Wix putting the file into the GAC. Now that Wix knows it's a .net assembly, though, it lets me use certain binder variables within my XML, such as the !(bind.assemblyFullname.filDriverAssembly)
to get the assembly full name.
Set the DISABLEADVTSHORTCUTS
property to force all advertised shortcuts in your installer to become regular shortcuts, and you don't need to include a dummy reg key to be used as the keypath.
I think Windows Installer 4.0 or higher is a requirement.
It's a nice structure but based on my experience I wonder how you address these conditions:
A. Your installs all appear to land in the same destination. If a user needs to install all 3 versions at once will your process allow this. Can they unambiguously tell which version of every executable they are triggering?
B. How do you handle new files that exist in TEST and/or TRAINING but not yet in LIVE?
Here's a way to help large web projects verify that the number of deployed files matches the number of files built into an MSI (or merge module). I've just run the custom MSBuild task against our main application (still in development) and it picked up quite a few missing files, mostly images, but a few javascript files had slipped through to!
This approach (peeking into File table of MSI by hooking into AfterBuild target of WiX project) could work for other application types where you have access to a complete list of expected files.
Performing a forced reinstall when an install doesn't allow uninstall or reinstall and doesn't roll back.
VBscript script used for overriding an install that isn't uninstalling for whatever reason.
Terrance
Create a UI that has a custom action that will set a variable and the UI will disable/enable the next button (or similar) based upon the variable set in the custom action.
Not as straight-forward as you would think, not too difficult just not documented anywhere!
Daniel Powell