<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Joy of Setup &#187; custom actions</title>
	<atom:link href="http://www.joyofsetup.com/tag/custom-actions/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.joyofsetup.com</link>
	<description>Bob Arnson's blog about setup and servicing</description>
	<lastBuildDate>Tue, 29 Jun 2010 02:41:43 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Lux unit testing, now with extra mutations</title>
		<link>http://www.joyofsetup.com/2010/03/30/lux-unit-testing-now-with-extra-mutations/</link>
		<comments>http://www.joyofsetup.com/2010/03/30/lux-unit-testing-now-with-extra-mutations/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 03:19:50 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[WiX]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2010/03/30/lux-unit-testing-now-with-extra-mutations/</guid>
		<description><![CDATA[I’m currently spending a lot of time working with custom actions, removing them where I can and improving them where they’re still necessary. The biggest change I’m making is to make the custom actions data driven using the immediate/deferred/rollback custom action triad. One of the advantages in doing so is that I can use Lux [...]]]></description>
			<content:encoded><![CDATA[<p>I’m currently spending a lot of time working with custom actions, removing them where I can and improving them where they’re still necessary. The biggest change I’m making is to make the custom actions <a href="http://robmensching.com/blog/posts/2007/9/13/Zataoca-Custom-actions-should-be-data-driven">data driven</a> using the immediate/deferred/rollback custom action triad. One of the advantages in doing so is that I can use <a href="http://www.joyofsetup.com/2010/02/08/introducing-lux-declarative-unit-testing-for-custom-actions/">Lux</a> to help test my work. One of the advantages of <em>that</em> is that real-world experience is the best way to improve tools.</p>
<p>One of the challenges of developing data-driven custom actions is testing all the combinations of state that affect the custom action data immediate custom actions pass to deferred and rollback custom actions. Because Lux test packages don’t modify the machine, testing the full set of possible states is difficult. Providing known state is a strength of traditional unit-testing techniques, however; if your custom action code is well factored, it should be a simple task to provide a test double that <a href="http://c2.com/cgi-bin/wiki?ArrangeActAssert">arranges</a> hard-coded state information that you can then test against.</p>
<p>Naturally, I wanted to figure out how I could provide the best of both worlds in Lux. Here’s what I came up with: test mutations. From the doc:</p>
<blockquote><p>Test mutations let you author unit tests with different expected results. The mutation id is passed as the value of the WIXLUX_RUNNING_MUTATION property. Your custom action, typically in an &#8216;#ifdef DEBUG&#8217; block, retrieves the WIXLUX_RUNNING_MUTATION property and mock different behavior based on the mutation. To author test mutations, use the Mutation element with UnitTest elements as children. For example: </p>
<p>&lt;lux:Mutation Id=&quot;SimulateDiskFull&quot;&gt;     <br />&#160; &lt;lux:UnitTest &#8230; /&gt;      <br />&lt;/lux:Mutation&gt;</p>
<p>Nit runs the test package once for each mutation, setting the WIXLUX_RUNNING_MUTATION property to one mutation id at a time. Tests that aren&#8217;t children of a mutation are run every time.</p>
</blockquote>
<p>Test mutations are a fairly simple change but one I hope simplifies combining traditional unit-testing techniques with declarative assertions.</p>
<p>Lux’s test mutations will ship in the next weekly release of WiX.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2010/03/30/lux-unit-testing-now-with-extra-mutations/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing Lux: Declarative unit testing for custom actions</title>
		<link>http://www.joyofsetup.com/2010/02/08/introducing-lux-declarative-unit-testing-for-custom-actions/</link>
		<comments>http://www.joyofsetup.com/2010/02/08/introducing-lux-declarative-unit-testing-for-custom-actions/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 02:18:49 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[WiX]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2010/02/08/introducing-lux-declarative-unit-testing-for-custom-actions/</guid>
		<description><![CDATA[The Cambridge-based WiX East Virtual Team have is pleased to announce its first major contribution to WiX: The Lux unit-testing framework. Lux will be available in the next weekly release of WiX v3.5. Unit-testing custom actions with Lux Custom actions are a frequent cause of installation failures so it&#8217;s important to test them thoroughly. Custom [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://microsoftcambridge.com/Default.aspx">Cambridge</a>-based WiX East Virtual Team have is pleased to announce its first major contribution to WiX: The Lux unit-testing framework. Lux will be available in the next <a href="http://wix.sourceforge.net/releases/">weekly release</a> of WiX v3.5.</p>
<h3>Unit-testing custom actions with Lux</h3>
<p>Custom actions are a frequent cause of installation failures so it&#8217;s important to test them thoroughly. Custom actions themselves usually aren&#8217;t tested. The traditional testing approach is to run functional tests on an entire installer and to cover as many scenarios and platform combinations as possible. </p>
<h4>Custom action patterns</h4>
<p>WiX compiler extensions provide one way of improving custom action quality: Because compiler extensions run at build time instead of install time, they can perform all sorts of data validation and conversion on strongly-typed authoring before converting it to rows and columns of custom tables in the MSI package. </p>
<p>Immediate custom actions then read those custom tables, check current state (for example, component action state, the state of the machine itself), and serialize the resulting data into a custom action data property. Immediate custom actions are the place to do the logic that needs live state and cannot be determined at build time by a compiler extension. Because immediate custom actions run in the security context of the installing user and outside an installation transaction, they generally do not have permissions to modify the machine and if they fail, the installation simply ends without the need to do any cleanup or rollback. </p>
<p>Deferred custom actions read the custom action data property set by immediate custom actions to know what to do. One way to improve custom action reliability is to make as few decisions as possible in deferred custom actions; instead, implement all the logic in compiler extensions and immediate custom actions and have deferred custom actions simply read the custom action data property in a loop to modify the machine. </p>
<p>The WiX custom actions that modify the machine use this pattern. For example, XmlConfig authoring is validated by the WixUtilExtension compiler extension and translated to rows and columns in the XmlConfig table. The SchedXmlConfig immediate custom action reads the XmlConfig table, constructs a custom action data property based on the XmlConfig table and machine&#8217;s state (including checking component state and storing existing file data to support rollback), then schedules the ExecXmlConfig deferred custom action to execute the XML changes and the ExecXmlConfigRollback rollback custom action to roll back the changes. </p>
<h4>Testing with Lux</h4>
<p>Lux is a WiX extension (and associated tools) that let you write data-driven unit tests for your custom actions. The executive summary: Lux runs your immediate custom actions then validates they set properties to the values you expect. </p>
<p>While it&#8217;s a simple approach, if your custom actions are factored as discussed above, validating the properties set by immediate custom actions can validate all the interaction between your custom actions, the MSI package, and MSI itself. </p>
<p>If your custom actions aren&#8217;t factored as discussed&#8211;for example, if your deferred custom actions expect only an installation directory and have logic to construct file paths from it&#8211;then it&#8217;s likely that your immediate custom actions don&#8217;t have a lot of logic that&#8217;s useful to test. </p>
<p>Lux does not help you test the custom action code that actually modifies the machine; for that, continue to use other unit-test frameworks and automated tests. By working only with immediate custom actions, Lux can let MSI run the custom actions as-is, eliminating the need to write custom <a href="http://xunitpatterns.com/Test%20Double.html">test doubles</a> for the MSI API. Lux runs from a per-user package so unless you run the tests from an elevated command prompt, none of the custom actions get elevated privileges and therefore cannot modify the machine. </p>
<p>Here&#8217;s how Lux works: </p>
<ol>
<li>You write your unit tests using XML in WiX source files. </li>
<li>The Lux extension converts the XML to a table in a test .msi package. </li>
<li>The Lux custom action runs after all other immediate custom actions and evaluates your unit tests. </li>
</ol>
<h3>Authoring unit tests</h3>
<p>Lux supports the following unit tests:</p>
<ul>
<li>Property values </li>
<li>Expressions </li>
<li>Multi-value properties </li>
<li>Name/value-pair properties </li>
</ul>
<p>Note that you should always author unit tests in fragments separate from your custom action authoring or any other product authoring. If you mix unit tests with other authoring, WiX includes the unit-test data in your &quot;real&quot; installers.</p>
<h4>Property value tests</h4>
<p>A simple test lets you specify a property to test, a value to test against, and the operator to compare with (which defaults to &quot;equal&quot;).</p>
<pre>&lt;Fragment&gt;
  &lt;lux:UnitTest CustomAction=&quot;TestCustomActionSimple&quot; Property=&quot;SIMPLE&quot; Value=&quot;[INSTALLLOCATION]&quot; Operator=&quot;equal&quot; /&gt;
&lt;/Fragment&gt;</pre>
<p>When the test runs, Lux compares the value of the SIMPLE property against the (formatted) value [INSTALLLOCATION]. If the two match (because the operator is &quot;equal&quot;), the test passes. Legal values of the Operator attribute are:</p>
<dl>
<dt><dfn>equal</dfn></dt>
<dd>(Default) Compares Property to Value and succeeds if they are equal. </dd>
<dt><dfn>notEqual</dfn></dt>
<dd>Compares Property to Value and succeeds if they are NOT equal. </dd>
<dt><dfn>caseInsensitiveEqual</dfn></dt>
<dd>Compares Property to Value and succeeds if they are equal (ignoring case). </dd>
<dt><dfn>caseInsensitiveNotEqual</dfn></dt>
<dd>Compares Property to Value and succeeds if they are NOT equal (ignoring case). </dd>
</dl>
<h4>Test conditions</h4>
<p>Conditions let you validate code paths in your custom action. For example, if your custom action behaves differently on Windows XP than it does on Windows Vista and later, you can create two tests with mutually exclusive conditions:</p>
<pre>&lt;Fragment&gt;
  &lt;lux:UnitTest CustomAction=&quot;TestCustomActionSimple&quot; Property=&quot;SIMPLE&quot; Value=&quot;[INSTALLLOCATION]&quot;&gt;
    &lt;lux:Condition&gt;&lt;![CDATA[VersionNT &lt; 600]]&gt;&lt;/lux:Condition&gt;
  &lt;/lux:UnitTest&gt;
  &lt;lux:UnitTest CustomAction=&quot;TestCustomActionSimple&quot; Property=&quot;SIMPLE&quot; Value=&quot;[INSTALLLOCATION]&quot;&gt;
    &lt;lux:Condition&gt;&lt;![CDATA[VersionNT &gt;= 600]]&gt;&lt;/lux:Condition&gt;
  &lt;/lux:UnitTest&gt;
&lt;/Fragment&gt;</pre>
<p>If a test has a condition, the test runs only if its condition is true.</p>
<h4>Expression tests</h4>
<p>Expression tests let you test any valid MSI expression. If the expression is true, the test passes. If the expression is false or invalid, the test fails.</p>
<pre>&lt;Fragment&gt;
  &lt;lux:UnitTest CustomAction=&quot;TestCustomActionSimple&quot;&gt;
    &lt;lux:Expression&gt;NOT MsiSystemRebootPending AND SIMPLE&lt;/lux:Expression&gt;
  &lt;/lux:UnitTest&gt;
&lt;/Fragment&gt;</pre>
<h4>Multi-value property tests</h4>
<p>Because deferred custom actions can access only a single custom-action data property, custom actions that need more than one piece of data encode it in a single string. One way is to have the immediate custom action separate multiple elements with a known separator character, then have the deferred custom action split the string at those separate characters. Lux supports such separators using the ValueSeparator and Index attributes.</p>
<pre>&lt;Fragment&gt;
  &lt;lux:UnitTest CustomAction=&quot;TestCustomActionMultiValue&quot; Property=&quot;MULTIVALUE&quot; ValueSeparator=&quot;*&quot;&gt;
    &lt;lux:Condition&gt;VersionNT&lt;/lux:Condition&gt;
    &lt;lux:UnitTest Index=&quot;0&quot; Value=&quot;1&quot; /&gt;
    &lt;lux:UnitTest Index=&quot;1&quot; Value=&quot;[INSTALLLOCATION]&quot;&gt;
      &lt;lux:Condition&gt;NOT Installed&lt;/lux:Condition&gt;
    &lt;/lux:UnitTest&gt;
    &lt;lux:UnitTest Index=&quot;2&quot; Value=&quot;WIXEAST&quot; /&gt;
  &lt;/lux:UnitTest&gt;
&lt;/Fragment&gt;</pre>
<p>A condition under the parent UnitTest element applies to all individual unit tests. Override it with a Condition child element.</p>
<h4>Name/value-pair property tests</h4>
<p>Another way of providing multiple values to a deferred custom action is to combine name/value pairs into a single string. Lux supports name/value-pair properties using the NameValueSeparator and Index attributes.</p>
<pre>&lt;Fragment&gt;
  &lt;lux:UnitTest CustomAction=&quot;TestCustomActionNameValuePairs&quot; Property=&quot;NAMEVALUEPAIRS&quot; NameValueSeparator=&quot;#&quot;&gt;
    &lt;lux:UnitTest Index=&quot;InstallationRoot&quot; Value=&quot;[INSTALLLOCATION]&quot; /&gt;
    &lt;lux:UnitTest Index=&quot;Developers&quot; Operator=&quot;caseInsensitiveNotEqual&quot; Value=&quot;WIXEAST&quot; /&gt;
  &lt;/lux:UnitTest&gt;
&lt;/Fragment&gt;</pre>
<h3>Building test packages</h3>
<p>Lux unit tests run from a minimal package that includes just your unit tests and the resources they need to run. Because Lux runs only immediate custom actions, it doesn&#8217;t need a full, per-machine package that includes all the files and other resources to be installed. Such a minimal package saves build time but does require that your WiX source code be well modularized with fragments. For example, you should always author unit tests in fragments separate from any other authoring. If you mix unit tests with other authoring, WiX includes the unit-test data in your &quot;real&quot; installers. Likewise, any other WiX authoring included in unit-test fragments is included in test packages.</p>
<p>Lux comes with a tool that simplifies the creation of test packages. Its name is lux.exe. To use lux.exe: </p>
<ol>
<li>Compile the source file containing your unit tests. </li>
<li>Run lux.exe on the .wixobj file and specify a source file for the test package. </li>
<li>Compile the test package source. </li>
<li>Link the test package .wixobj with the unit tests .wixobj. </li>
</ol>
<p>For example:</p>
<pre>candle -ext WixLuxExtension CustomActions.wxs
lux CustomActions.wixobj -out LuxSample1_test.wxs
candle -ext WixLuxExtension LuxSample1_test.wxs
light -ext WixLuxExtension LuxSample1_test.wixobj CustomActions.wixobj -out LuxSample1_test.msi</pre>
<p>Lux also includes an MSBuild task and .targets file to let you build test packages from the same .wixproj you use to build your installers. To build a test package, build the BuildTestPackage target using MSBuild 3.5:</p>
<pre>%WINDIR%\Microsoft.NET\Framework\v3.5\MSBuild.exe /t:BuildTestPackage</pre>
<h3>Running unit tests</h3>
<p>After building the test package, you can run it with logging enabled to capture test results:</p>
<pre>msiexec /l test1.log /i bin\Debug\LuxSample1_test.msi</pre>
<p>Search the log for <b>WixRunImmediateUnitTests</b> to see test results and other logging from the Lux custom action.</p>
<h4>Nit: The Lux test runner</h4>
<p>Lux also includes Nit, a console program that monitors the logging messages emitted by unit tests and reports success or failure. To use Nit on your test packages, just specify their filenames as arguments to nit.exe. For example:</p>
<pre>nit LuxSample1_test.msi</pre>
<p>Lux also lets you run Nit on your test packages from the same .wixproj you use to build your installers. To run a test package under Nit, build the Test target using MSBuild 3.5:</p>
<pre>%WINDIR%\Microsoft.NET\Framework\v3.5\MSBuild.exe /t:Test</pre>
<p>The test package will be built before the tests are run, if necessary. The output looks like the following, with failing tests highlighted in red as build errors:</p>
<pre>Test:
  Microsoft (R) Windows Installer Xml Unit Test Runner version 3.5.1204.0
  Copyright (C) Microsoft Corporation. All rights reserved.

  Test luxB21F0D12E0701DBA30FFB92A532A5390 passed: Property 'SIMPLE' matched expected value '[INSTALLLOCATION]'.
  Test TestConditionBeforeVista passed: Property 'SIMPLE' matched expected value '[INSTALLLOCATION]'.
  Test TestConditionVistaOrLater passed: Property 'SIMPLE' matched expected value '[INSTALLLOCATION]'.
  Test TestExpressionTruth passed: Expression 'NOT MsiSystemRebootPending AND SIMPLE' evaluated to true.
nit.exe : error NIT8103: Test luxA6D27EC5903612D7F3786FF71952E314 failed: Property 'MULTIVALUE' expected value '2' but actual value was '1'.
  Test lux210257649C16AFA33793F1CDDF575505 passed: Property 'MULTIVALUE' matched expected value '[INSTALLLOCATION]'.
nit.exe : error NIT8103: Test lux402940A90D3ADAD181D599AB8C260FA0 failed: Property 'MULTIVALUE' expected value 'xxxWIXEAST' but actual value was 'WIXEAST'.
  Test lux453EC8DB458A8F66F0D22970CFF2AE99 passed: Property 'NAMEVALUEPAIRS' matched expected value '[INSTALLLOCATION]'.
  Test lux20CB4F88795F22D15631FD60BA03AFEB passed: Property 'NAMEVALUEPAIRS' matched expected value 'WIXWEST'.
nit.exe : error NIT8102: 2 tests failed. 7 tests passed.
Done Building Project &quot;C:\Delivery\Dev\wix35\src\lux\samples\LuxSample1\LuxSample1.wixproj&quot; (Test target(s)) -- FAILED.

Build FAILED.

&quot;C:\Delivery\Dev\wix35\src\lux\samples\LuxSample1\LuxSample1.wixproj&quot; (Test target) (1) -&gt;
(Test target) -&gt;
  nit.exe : error NIT8103: Test luxA6D27EC5903612D7F3786FF71952E314 failed: Property 'MULTIVALUE' expected value '2' but actual value was '1'.
  nit.exe : error NIT8103: Test lux402940A90D3ADAD181D599AB8C260FA0 failed: Property 'MULTIVALUE' expected value 'xxxWIXEAST' but actual value was 'WIXEAST'.
  nit.exe : error NIT8102: 2 tests failed. 7 tests passed.

    0 Warning(s)
    3 Error(s)

Time Elapsed 00:00:07.87</pre>
<h3>FAQ</h3>
<dl>
<dt>Are these really unit tests? They look a lot like <a href="http://fit.c2.com/">Fit tests</a>. </dt>
<dd>Fit tests are tabular and data-driven, so they have a lot in common with Lux&#8217;s unit tests. But fit tests are focused on high-level outputs, whereas unit tests are low-level developer tests. </dd>
<dt>Using the custom action code as-is sounds good, but are there any limitations with that approach? </dt>
<dd>Yes. Because you are running the actual custom action, any code paths that rely on machine state reflect the state of the machine you run the tests on. For example, code that has different behavior on different versions of Windows runs only one way, just like it does in a normal installer. You can add debug code that looks for the presence of the WIXLUXTESTPACKAGE property; it&#8217;s set to 1 in a test package. </dd>
<dt>I have unit tests that fail because directory properties are being returned as empty strings. Why? </dt>
<dd>The most likely cause is that your directories are defined as children of your installer&#8217;s Product element. Lux.exe builds its own Product element to product a minimal test package, so none of the resources defined in your Product are available to the unit tests. The simplest solution is to move those resources to their own Fragment. </dd>
<dt>Do I have to write my custom actions in C++? </dt>
<dd>No, Lux works with any immediate custom actions, regardless of the language they&#8217;re written in, including MSI type 51 property-setting custom actions. </dd>
</dl>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2010/02/08/introducing-lux-declarative-unit-testing-for-custom-actions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Verbose logging from WcaUtil</title>
		<link>http://www.joyofsetup.com/2008/07/15/verbose-logging-from-wcautil/</link>
		<comments>http://www.joyofsetup.com/2008/07/15/verbose-logging-from-wcautil/#comments</comments>
		<pubDate>Tue, 15 Jul 2008 16:02:31 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[WiX]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2008/07/15/verbose-logging-from-wcautil/</guid>
		<description><![CDATA[WcaUtil is a static library of convenience functions for writing custom actions in native C++. One of the more useful functions is WcaLog, which writes messages into the Windows Installer log. The first argument to WcaLog is the level of the message: LOGMSG_TRACEONLY: Written to the log only in debug builds for debugging custom actions. [...]]]></description>
			<content:encoded><![CDATA[<p>WcaUtil is a static library of convenience functions for writing custom actions in native C++. One of the more useful functions is WcaLog, which writes messages into the Windows Installer log. The first argument to WcaLog is the level of the message:</p>
<ul>
<li>LOGMSG_TRACEONLY: Written to the log only in debug builds for debugging custom actions.</li>
<li>LOGMSG_VERBOSE: Written to the log only when verbose logging is enabled.</li>
<li>LOGMSG_STANDARD: Always written to the log.</li>
</ul>
<p>WcaLog considers verbose logging enabled whenever any of the following is true:</p>
<ul>
<li>LOGVERBOSE property: There&#8217;s a property in your package named LOGVERBOSE, regardless of its value.</li>
<li><a href="http://msdn.microsoft.com/en-us/library/aa370322(VS.85).aspx">MsiLogging property</a>: There&#8217;s a property in your package named MsiLogging that contains a <strong>V</strong> character.</li>
<li><a href="http://msdn.microsoft.com/en-us/library/aa369776.aspx">Logging policy</a>: The logging policy is set and contains a <strong>V</strong> character.</li>
</ul>
</p>
</p>
<p>Otherwise, messages tagged with LOGMSG_VERBOSE will be ignored.</p>
<p>The second argument is a <a href="http://msdn.microsoft.com/en-us/library/56e442dc.aspx">printf-style format string</a> so there are a variable number of arguments (zero or more) after it which specify the values referred to in the format string. For example:</p>
<blockquote><p>WcaLog(LOGMSG_VERBOSE, &quot;App: %S found running, %d processes, setting &#8216;%S&#8217; property.&quot;, wzApplication, cProcessIds, wzProperty);</p>
</blockquote>
<p>Note that WcaLog uses ANSI strings for the format string and its arguments, so if you want to log a Unicode string, you need to use the <strong>%ls</strong> or <strong>%S</strong> <a href="http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx">field characters</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2008/07/15/verbose-logging-from-wcautil/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Testing your deferred and rollback custom actions</title>
		<link>http://www.joyofsetup.com/2008/06/18/testing-your-deferred-and-rollback-custom-actions/</link>
		<comments>http://www.joyofsetup.com/2008/06/18/testing-your-deferred-and-rollback-custom-actions/#comments</comments>
		<pubDate>Thu, 19 Jun 2008 06:06:33 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[WiX]]></category>
		<category><![CDATA[Windows Installer]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2008/06/18/testing-your-deferred-and-rollback-custom-actions/</guid>
		<description><![CDATA[When you include deferred custom actions &#8212; that somehow modify the machine &#8212; in your setup, you have two big responsibilities: Provide rollback custom actions that &#34;undo&#34; what the deferred CAs do so that the installation transaction is actually transactional. Test. Test. Test. OK, so numbers 2 through 4 are kinda the same but not [...]]]></description>
			<content:encoded><![CDATA[<p>When you include deferred custom actions &#8212; that somehow modify the machine &#8212; in your setup, you have two big responsibilities:</p>
<ol>
<li>Provide rollback custom actions that &quot;undo&quot; what the deferred CAs do so that the installation transaction is actually transactional. </li>
<li>Test. </li>
<li>Test. </li>
<li>Test. </li>
</ol>
<p>OK, so numbers 2 through 4 are kinda the same but not really: Even a simple installation (say, without patching or upgrades) has three different scenarios you need to test when you have deferred/rollback custom actions:</p>
<ol>
<li>Installation rollback. </li>
<li>Repair rollback. </li>
<li>Uninstallation rollback. </li>
<li>All of the above. </li>
</ol>
<p>The right behavior for each kind of rollback is usually the opposite action. Rolling back installation is uninstallation. Rolling back uninstallation is installation. Rolling back repair is usually installation. Mixing installation, repair, and uninstallation is possible if your package has user-selectable features and users go into maintenance mode to turn on and off features. And, of course, it&#8217;s always an option from the msiexec.exe command line using the ADDLOCAL/ADDSOURCE/ADDDEFAULT, REMOVE, and REINSTALL properties.</p>
<h2>Testing rollback means testing failure</h2>
<p>Windows Installer initiates rollback when an action fails, so to test rollback you need to cause a failure. WiX includes an easy way to trigger failure: The WixFailWhenDeferred custom action, part of WixUtilExtension, triggers a failure when it&#8217;s executed. Include it in your package by referencing WixUtilExtension (in your Votive .wixproj or via the -ext switch to the light.exe command line) and adding a CustomActionRef to your package authoring:</p>
<blockquote><p>&lt;CustomActionRef Id=&quot;WixFailWhenDeferred&quot; /&gt;</p>
</blockquote>
<p>WixFailWhenDeferred automatically schedules itself in InstallExecuteSequence before InstallFinalize, with a condition of:</p>
<blockquote><p>WIXFAILWHENDEFERRED=1</p>
</blockquote>
<p>The condition means that you can have one package to test all the different possible combinations of &quot;normal&quot; installation and rollback. Just pass the WIXFAILWHENDEFERRED=1 property value on the msiexec.exe command line to trigger rollback. For example:</p>
<blockquote><p>msiexec /qb- /i intermediate.msi /L*vx installfail.log WIXFAILWHENDEFERRED=1      <br />msiexec /qb- /i intermediate.msi /L*vx install.log       <br />msiexec /qb- /fvamus intermediate.msi /L*vx repairfail.log WIXFAILWHENDEFERRED=1       <br />msiexec /qb- /fvamus intermediate.msi /L*vx repair.log       <br />msiexec /qb- /x intermediate.msi /L*vx uninstallfail.log WIXFAILWHENDEFERRED=1       <br />msiexec /qb- /x intermediate.msi /L*vx uninstall.log</p>
</p>
</p>
</blockquote>
<p>WixFailWhenDeferred has been in WiX v3 weekly releases since April.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2008/06/18/testing-your-deferred-and-rollback-custom-actions/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Google Earth setup experience</title>
		<link>http://www.joyofsetup.com/2008/04/16/google-earth-setup-experience/</link>
		<comments>http://www.joyofsetup.com/2008/04/16/google-earth-setup-experience/#comments</comments>
		<pubDate>Thu, 17 Apr 2008 06:32:12 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[Windows Installer]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2008/04/16/google-earth-setup-experience/</guid>
		<description><![CDATA[Google announced the release of Google Earth 4.3 today. Given the recent release of their WiX-based setup for the Google App Engine SDK, I had to give it a shot. (It helps that my day job also deals with 3-D terrain imagery.) When you click the link to “Download Google Earth 4.3” (and accept the [...]]]></description>
			<content:encoded><![CDATA[<p>Google <a href="http://googleblog.blogspot.com/2008/04/whole-new-world-to-explore.html">announced</a> the release of <a href="http://earth.google.com/">Google Earth 4.3</a> today. Given the recent release of their <a href="http://robmensching.com/blog/archive/2008/04/07/Google-App-Engine-delivered-to-Windows-by-WiX.aspx">WiX-based setup</a> for the <a href="http://code.google.com/appengine/">Google App Engine SDK</a>, I had to give it a shot. (It helps that my day job also deals with 3-D terrain imagery.)</p>
<p>When you click the link to “Download Google Earth 4.3” (and accept the EULA), you download not Google Earth but “Google Updater.exe.” Run it and it starts downloading the Google Earth installer.</p>
<p>Personally, I much prefer to download the <em>actual</em> installers for the software I use. Some of it’s purely practical: I can stick it on a network and put it on multiple computers (EULA permitting, of course) without waiting for multiple downloads. Perhaps more importantly, for the paranoid among us, is the ability to virus-scan the installers. (Google Updater requests elevation, so it has admin rights to install multiple packages.)</p>
<p>Google Updater also runs as a startup app, optionally showing an icon in the increasingly-unusable system tray. (Yes, I know it’s technically the “<a href="http://en.wikipedia.org/wiki/Windows_Taskbar">notification area</a>,” but come on, who calls it that?) I don’t think I need 24/7 instant access to software that doesn’t get updated that often. In fact, I’m sure I don’t.</p>
<p>Naturally, installing a packaging system with update capabilities is a boon to many users (and Google itself, of course, which has a nicely visible entry point to suggest additional apps for download). Apple does it with iTunes and Microsoft does it with Windows Live. Luckily, Google Updater has its own entry in Add/Remove Programs so you can remove it without impact to Google Earth.</p>
<h2>Google Earth installer</h2>
<p>The Google Earth installer is built with InstallShield, using its support for “dynamic file linking.” (If you haven’t used it, think of running Heat or Tallow with every build.) Interestingly, it uses the CAQuietExec custom action from WiX and has wixca.dll in the Binary table.</p>
<p>The .msi package fails ICE validation, with errors in ICE03, ICE15, ICE34, ICE38, ICE43, ICE44, ICE57, ICE64, and ICE99, and warnings in ICE45, ICE60, ICE82, ICE86, and ICE91.</p>
<p>There are 36 custom actions, some of which are mildly disturbing:</p>
<ul>
<li>registerFlashSOL is a deferred, no-impersonate custom action that runs an included .exe with a “-install” command-line switch. Oh joy: self-reg.</li>
<li>InstallToolBarCA is an immediate custom action that runs an installed .exe. It’s not scheduled and is only available from the UI sequence – the one that’s suppressed because Google Updater runs the installation silently.</li>
<li>SetGEUserStats is another custom action run only from the suppressed – but still included – UI sequence.</li>
<li>SET_RES_READ_ONLY sets QtExecCmdLine to run the WiX CAQuietExec custom action. What is it hiding? It’s running attrib.exe to turn off the read-only attribute on a recursive set of files/directories. Doesn’t the File table let you control the read-only attribute? Yes, it does, but apparently not when you use InstallShield’s dynamic file linking to harvest a directory tree at build time. In a previous life, I used that functionality and turned off the read-only attributes in the build script before harvesting. Doing it as part of installation is bad karma on Google’s part.</li>
</ul>
<p>Overall, it’s not a bad installer, but I hope Google cleans it up a bit before it loses the “beta” label.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2008/04/16/google-earth-setup-experience/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Two great tastes: Agile development and distributed, declarative setup</title>
		<link>http://www.joyofsetup.com/2008/02/13/two-great-tastes-agile-development-and-distributed-declarative-setup/</link>
		<comments>http://www.joyofsetup.com/2008/02/13/two-great-tastes-agile-development-and-distributed-declarative-setup/#comments</comments>
		<pubDate>Wed, 13 Feb 2008 15:21:31 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[WiX]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2008/02/13/two-great-tastes-agile-development-and-distributed-declarative-setup/</guid>
		<description><![CDATA[I&#8217;ve had the good fortune to work on several agile software-development teams over the years. If you&#8217;ve ever hated having software you&#8217;ve developed sit on the shelf for months or years until the next release, shipping several times a year feels good. Shipping almost every month is even better. Shipping almost every week is phenomenal. [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had the good fortune to work on several agile software-development teams over the years. If you&#8217;ve ever hated having software you&#8217;ve developed sit on the shelf for months or years until the next release, shipping several times a year feels good. <a href="http://msdn2.microsoft.com/en-us/vstudio/aa700819.aspx">Shipping almost every month</a> is even better. <a href="http://wix.sourceforge.net/releases/">Shipping almost every week</a> is phenomenal.</p>
<p>Most of the <a href="http://agilemanifesto.org/principles.html">principles of the agile manifesto</a> reinforce the idea that shipping software often is how to best deliver customer value. To ship often, you need predictability:</p>
<ul>
<li>Finish all the work associated with a feature.
<li>Make sure it&#8217;s of ship quality.</li>
</ul>
<h1>Done versus done-done</h1>
<p>The waterfall model of designing, then coding, then throwing over the wall to test, then fixing bugs, then throwing over the other wall to setup&#8211;yes, of course I&#8217;m going to talk about setup&#8211;is just procrastinating. Sure, it&#8217;s more fun to start working on the next new thing, but it&#8217;s just postponing the work required to get a feature <em>really</em> done and ready to ship.</p>
<p>Setup development, like testing, is often considered one of the &#8220;taxes&#8221; of software development that is best put off as long as possible. But if you want to deliver shippable software on a rapid schedule, paying taxes late doesn&#8217;t work; you might get to <a href="http://www.americaslibrary.gov/cgi-bin/page.cgi/jb/progress/taxday_1">April 15th</a> and discover that you have more bugs than you can fix by midnight. Instead, you pay your taxes as you go along so there are no surprises when you get to the last day and you want to ship.</p>
<p>Rather than developers considering themselves &#8220;done&#8221; when they&#8217;ve written some code and debugged it, developers need to get &#8220;done done&#8221; by providing code, unit tests, acceptance tests, and setup.</p>
<p>WiX supports &#8220;done done&#8221; by easily integrating into the development build cycle. Every member of an agile team can author setup. That prevents the lone setup developer, who probably supports multiple product teams, from being a bottleneck.</p>
<p>Plus, if developers are responsible for their own setup authoring, they&#8217;re less likely to push bad design decisions onto the setup developer&#8217;s shoulders.</p>
<h1>Keep quality high and take the weekends off</h1>
<p>Agile methodologies bring a whole set of tools and processes to help keep quality high and ready to &#8220;ship on a dime,&#8221; like:</p>
<ul>
<li>Test-driven development to produce high-quality designs and code
<li>Automated acceptance testing to reduce the need for armies of testers to validate the whole system at the end</li>
</ul>
<p>Add some setup flavor:</p>
<ul>
<li>Make sure that &#8220;done&#8221; for every feature includes its setup authoring.</li>
<li>Run your automated acceptance tests from official setup packages, not from local builds.</li>
<li>Build upgrades and patches and create automated tests to ensure you can service the product.</li>
<li>Use only fully declarative custom actions&#8211;they make it easier to handle patching, upgrades, and repair.</li>
</ul>
<p>Frequent, automated testing tells you if your code (and setup) do what they&#8217;re supposed to (or not&#8211;at least as far as the tests are concerned). Adding setup into the testing mix helps ensure that your setup is ready too.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2008/02/13/two-great-tastes-agile-development-and-distributed-declarative-setup/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Managed custom actions in MySQL Connector/NET</title>
		<link>http://www.joyofsetup.com/2008/02/11/managed-custom-actions-in-mysql-connectornet/</link>
		<comments>http://www.joyofsetup.com/2008/02/11/managed-custom-actions-in-mysql-connectornet/#comments</comments>
		<pubDate>Tue, 12 Feb 2008 05:21:51 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[Windows Installer]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2008/02/11/managed-custom-actions-in-mysql-connectornet/</guid>
		<description><![CDATA[Reggie Burnett, creator and developer of MySQL&#8217;s Connector/NET ADO.NET provider, announced an alpha release of the MySQL Connector/NET. Among the new features: Perfmon counters are now created using Wix code instead of a managed custom action. This seems to help the problem where some installation were failing becausing of being unable to register the counters. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.reggieburnett.com/Default.aspx">Reggie Burnett</a>, creator and developer of MySQL&#8217;s Connector/NET ADO.NET provider, <a href="http://www.reggieburnett.com/archive/2008/02/11/mysql-connectornet-5.2.0-alpha-has-been-released.aspx">announced</a> an alpha release of the MySQL Connector/NET. Among the new features:</p>
<blockquote><p>Perfmon counters are now created using Wix code instead of a managed custom action.  This seems to help the problem where some installation were failing becausing of being unable to register the counters.</p></blockquote>
<p>Great job! Now, about the two remaining managed custom actions and the H2Reg CAs that don&#8217;t have rollback&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2008/02/11/managed-custom-actions-in-mysql-connectornet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Semi-custom actions</title>
		<link>http://www.joyofsetup.com/2007/07/01/semi-custom-actions/</link>
		<comments>http://www.joyofsetup.com/2007/07/01/semi-custom-actions/#comments</comments>
		<pubDate>Sun, 01 Jul 2007 23:51:06 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[Windows Installer]]></category>
		<category><![CDATA[custom actions]]></category>
		<category><![CDATA[Flight Simulator]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2007/07/01/semi-custom-actions/</guid>
		<description><![CDATA[I was working on my current double-secret project at work and got a requirement that I knew would need a custom action. The requirement is to add entries to a configuration file without overwriting existing entries. The configuration file (scenery.cfg, for FlightSim fans) is actually in .ini format. Naturally, I looked into using the standard [...]]]></description>
			<content:encoded><![CDATA[<p>I was working on my current <a href="http://www.fsinsider.com/news/Pages/AnnouncingFSXExpansion.aspx">double-secret project</a> at work and got a requirement that I knew would need a custom action. The requirement is to add entries to a configuration file without overwriting existing entries.</p>
<p>The configuration file (scenery.cfg, for FlightSim fans) is actually in .ini format. Naturally, I looked into using the standard <a href="http://msdn2.microsoft.com/en-us/library/aa369282.aspx">IniFile table</a> but it wasn&#8217;t sufficient for my needs. Scenery.cfg has entries that point to scenery data; each entry is numbered to control the priority of the scenery in rendering.</p>
<p>So, for example, given the following tail entries:</p>
<blockquote><p>[Area.114]<br />
Title=Propeller Objects<br />
Local=Scenery\Props<br />
Layer=114<br />
Active=TRUE<br />
Required=TRUE</p>
<p>[Area.115]<br />
Title=Addon Scenery<br />
Local=Addon Scenery<br />
Layer=115<br />
Active=TRUE<br />
Required=FALSE</p></blockquote>
<p>New entries would start out like this:</p>
<blockquote><p>[Area.116]<br />
Title=Test1<br />
Local=MyScenery\Test1<br />
Layer=116<br />
Active=TRUE<br />
Required=FALSE</p></blockquote>
<p>Unfortunately, scenery.cfg is different among the various editions and languages of FlightSim, so the entry numbers aren&#8217;t static. (Also, users can add third-party scenery and we can&#8217;t overwrite those entries.) Though the <a href="http://msdn2.microsoft.com/en-us/library/aa369282.aspx">IniFile table</a> supports formatted strings, adding scenery entries would require string manipulation and math operators. While those might make for interesting MSI features, they don&#8217;t exist today.</p>
<p>So I started planning to write a deferred custom action and its matching rollback CA. Neither is too difficult &#8212; Win32 still supports API functions to add and remove .ini file entries. (Amusingly, the SDK doc groups them together with <a href="http://msdn2.microsoft.com/en-us/library/ms724875.aspx">Registry Functions</a>.)</p>
<p>Still, I&#8217;m a strong believer in not doing more work than necessary. (I prefer to think of it as efficiency rather than laziness.) MSI already handles the deferred and rollback aspects of modifying .ini files via the IniFile table and <a href="http://msdn2.microsoft.com/en-us/library/aa372884.aspx">WriteIniValues</a> and <a href="http://msdn2.microsoft.com/en-us/library/aa371205.aspx">RemoveIniValues</a> standard actions. If I could plug in dynamic data, I&#8217;d be able to write a simpler immediate CA rather than two more complicated deferred/rollback CAs.</p>
<h2>Efficiency through transience</h2>
<p>As you probably suspect by now, MSI has just such support. Immediate CAs can add <em>temporary</em> tables, rows, and columns to the active database. By adding temporary rows to standard tables, immediate CAs can determine <em>at install time </em>what data should be installed.</p>
<p>It&#8217;s important to note that temporary rows are&#8230;well&#8230;temporary. There&#8217;s not a whole lot of doc in the MSI SDK about temporary rows in general but <a href="http://msdn2.microsoft.com/En-US/library/aa372891.aspx">one mention</a> points out their temporary nature:</p>
<blockquote><p>A custom action can be used to add rows to the Registry table during an installation, uninstallation, or repair transaction. These rows do not persist in the Registry table and the information is only available during the current transaction. The custom action must therefore be run in every installation, uninstallation, or repair transaction that requires the information in these additional rows. The custom action must come before the RemoveRegistryValues and WriteRegistryValues actions in the action sequence.</p></blockquote>
<p>So that&#8217;s the recipe: An immediate CA runs, reads whatever data it needs from a custom table, using component states to decide what data should be written to temporary rows, and writes the rows (to the Registry or IniFile tables, for example). No deferred or rollback CAs are required, because MSI handles that.</p>
<p>WiX&#8217;s wcautil library makes this kind of CA easy to write. The WcaOpenExecuteView function executes a query and returns a view handle. WcaFetchRecord fetches the next record from the view. The WcaGetRecordInteger, WcaGetRecordString, and WcaGetRecordFormattedString functions get column values from the record. The best is WcaAddTempRecord which does all the work of adding a temporary row. It&#8217;s a fairly straightforward function but as no other CA in WiX uses it, here&#8217;s an example:</p>
<blockquote><p>hr = WcaAddTempRecord(&amp;hIniTableView, &amp;hIniColumns,<br />
// the table<br />
L&#8221;IniFile&#8221;,<br />
// the column number of the key we want &#8220;uniquified&#8221;<br />
1,<br />
// the number of columns we&#8217;re adding<br />
8,<br />
// primary key<br />
L&#8221;AcesSceneryConfig&#8221;,<br />
// FileName &#8212; always scenery.cfg<br />
L&#8221;scenery.cfg&#8221;,<br />
// DirProperty &#8212; set by AppSearch in extension .wixlib<br />
L&#8221;ACESSCENERYCFGDIR&#8221;,<br />
// Section &#8212; [Area.&lt;n&gt;]<br />
pwzArea,<br />
// Key<br />
L&#8221;Title&#8221;,<br />
// Value<br />
wzTitle,<br />
// Action<br />
msidbIniFileActionAddLine,<br />
// Component_<br />
wzComponent);</p></blockquote>
<p>The first two parameters are pointers to MSIHANDLEs. You initialize them to NULL and the first time you call WcaAddTempRecord, it initializes them. The first handle is to a view on the table you&#8217;re inserting into. The second is a handle to information about the columns in the table. By passing them in and out as arguments, you can let WcaAddTempRecord initialize them once then re-use the same handles. WcaAddTempRecord doesn&#8217;t know when you&#8217;re done adding records, so you&#8217;re responsible for calling <a href="http://msdn2.microsoft.com/en-us/library/aa370067.aspx">MsiCloseHandle</a> on both handles.</p>
<p>The fourth parameter is named uiUniquifyColumn and is the column number of a column that must have a unique value, like the primary key of a table. Yes, somebody made <em>uniquify</em> a verb; as far as I can tell, <a href="http://robmensching.com/blog/">Rob</a>&#8216;s to blame. Anyway, what uiUniquifyColumn does is add a semi-random value to the value you pass in as the value for the specified column. (Remember that column numbers start at one, not zero.) That ensures the temporary rows you&#8217;re adding won&#8217;t conflict with existing rows. As the rows are temporary, there&#8217;s no <a href="http://blogs.msdn.com/windows_installer_team/archive/2007/03/07/arbitrary-labels-used-as-primary-keys-must-not-be-changed-between-versions.aspx">harm in using non-deterministic IDs</a>.</p>
<p>The other parameters are straightforward: the table name, the number of columns, and the value of each column. Note that by default the number of columns you pass in must match the number of columns in the table. If you want to pass in fewer than the actual number of columns, you need to pass in your own view of the table, via a query that selects just the columns you&#8217;re interested in.</p>
<h2>Risks</h2>
<p>Because the data you&#8217;re adding is processed during the install transaction, then dropped, a bug in the CA could orphan the data those rows represent during uninstallation. The easiest way to mitigate this risk is to run the immediate CA during every transaction and use the install state and action state of a component to determine whether to write the temporary rows. You can write the temporary rows only when the component state is changing (i.e., being installed, being removed, being repaired). For example:</p>
<blockquote><p>er = ::MsiGetComponentStateW(WcaGetInstallHandle(), wzComponent, &amp;isInstalled, &amp;isAction);<br />
if (WcaIsInstalling(isInstalled, isAction) || WcaIsReInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction))<br />
{ &#8230; }</p></blockquote>
<p>By triggering off any change in component state, the CA supports installation, uninstallation, repair, and also is smart enough to <em>not</em> do anything when the component isn&#8217;t being installed. That lets you avoid adding any conditions to the CA scheduling itself.</p>
<h2>Extra credit</h2>
<p>Naturally, a WiX compiler extension lets users easily author data into the custom table. Also, there&#8217;s no reason you have to limit yourself to standard tables: You can just easily add temporary rows to the XmlConfig table to have the WiX XmlConfig custom action modify XML files in ways you couldn&#8217;t with just XPath and formatted properties alone.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2007/07/01/semi-custom-actions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apple Safari setup built with WiX</title>
		<link>http://www.joyofsetup.com/2007/06/11/apple-safari-setup-built-with-wix/</link>
		<comments>http://www.joyofsetup.com/2007/06/11/apple-safari-setup-built-with-wix/#comments</comments>
		<pubDate>Mon, 11 Jun 2007 20:14:08 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[WiX]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2007/06/11/apple-safari-setup-built-with-wix/</guid>
		<description><![CDATA[Apple&#8217;s Safari browser is now available in public beta on Windows. A little spelunking shows that it uses Windows Installer packages and that they&#8217;re built with WiX. Sadly, they didn&#8217;t use WixUI.&#60;g&#62; On a more serious-but-sad note, the packages have ICE validation errors (other than the typical ones), contain VBScript custom actions, and the main [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.apple.com/safari/">Apple&#8217;s Safari browser is now available in public beta on Windows.</a> A little spelunking shows that it uses Windows Installer packages and that they&#8217;re built with WiX. Sadly, they didn&#8217;t use WixUI.&lt;g&gt;</p>
<p>On a more serious-but-sad note, the packages have ICE validation errors (other than the typical ones), contain VBScript custom actions, and the main Safari package uses a custom action to install the Apple Software Updater package (instead of using a chainer). Already <a href="http://discussions.apple.com/thread.jspa?threadID=992912&amp;tstart=0">there&#8217;s a forum report</a> of a <a href="http://www.joyofsetup.com/2007/06/07/when-vbscript-and-jscript-custom-actions-are-even-more-evil/">2738 error</a> with the VBScript CA. And I guess the only way to report bugs is via forum posts&#8230;? It&#8217;s not clear. The &#8220;Report Bugs to Apple&#8221; command on the Help menu seems focused on rendering problems. Too bad. After all, <a href="http://msdn2.microsoft.com/en-us/library/aa302186.aspx#wixsetup_topic2">Setup Development Is Just Development</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2007/06/11/apple-safari-setup-built-with-wix/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>When VBScript and JScript custom actions are even more evil than usual</title>
		<link>http://www.joyofsetup.com/2007/06/07/when-vbscript-and-jscript-custom-actions-are-even-more-evil/</link>
		<comments>http://www.joyofsetup.com/2007/06/07/when-vbscript-and-jscript-custom-actions-are-even-more-evil/#comments</comments>
		<pubDate>Fri, 08 Jun 2007 06:34:45 +0000</pubDate>
		<dc:creator>Bob Arnson</dc:creator>
				<category><![CDATA[Windows Installer]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[custom actions]]></category>

		<guid isPermaLink="false">http://www.joyofsetup.com/2007/06/07/when-vbscript-and-jscript-custom-actions-arent-utterly-evil/</guid>
		<description><![CDATA[As everyone knows, script custom actions are inherently evil. A security addition to Windows Installer 4.0 in Windows Vista means that script CAs are even more likely to fail; see Heath&#8217;s blog entry on the issue and Aaron&#8217;s follow-up. But did you know that script CAs, evil that they are, nonetheless ship in Orca, MsiVal2, [...]]]></description>
			<content:encoded><![CDATA[<p>As everyone knows, <a href="http://blogs.msdn.com/robmen/archive/2004/05/20/136530.aspx">script custom actions are inherently evil</a>. A security addition to Windows Installer 4.0 in Windows Vista means that script CAs are even more likely to fail; see <a href="http://blogs.msdn.com/heaths/archive/2007/05/31/windows-installer-errors-2738-and-2739-with-script-custom-actions.aspx">Heath&#8217;s blog entry on the issue</a> and <a href="http://blogs.msdn.com/astebner/archive/2007/06/07/3151752.aspx">Aaron&#8217;s follow-up</a>.</p>
<p>But did you know that script CAs, evil that they are, nonetheless ship in Orca, MsiVal2, and even the WiX toolset? Shocking but true. The <a href="http://msdn2.microsoft.com/en-US/library/aa372423.aspx">Internal Consistency Evaluators</a> (ICEs) are implemented as custom actions in .cub files that are MSI databases with a vastly different schema you&#8217;re used to seeing. A couple of ICEs are written in VBScript so a misregistered VBScript engine will cause those ICEs to fail. As WiX v3 runs validation by default during linking (and on-demand using the Smoke tool), failed ICEs fail your setup build.</p>
<p>Of 98 ICEs in the version of Darice.cub in the Windows Vista SDK, only four are written in VBScript &#8212; yet that&#8217;s all it takes to fail your build.</p>
<p>If you run into the problem, check out the workaround Aaron offers before you take the drastic step of disabling validation.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joyofsetup.com/2007/06/07/when-vbscript-and-jscript-custom-actions-are-even-more-evil/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
