Posts

Showing posts from 2008

UI Automation for Developers

I'm currently working on a Wix 3.0-based installer with about 6 different wizard dialogs. Testing installers is a lot of work, because it is difficult to arrange for only the part of the installer you are interested in to run. I found myself filling out credentials, picking websites, etc. over and over. The QA organzation at my company uses AutoIt3 , a free UI automation tool with a VB-like syntax, to do UI automation for Windows GUIs, and I thought I would check it out and see if I could quickly record a macro which would get me all the way through the UI sequence of my installer. Sure enough, it was as easy as this: Download and install AutoIt3 Make sure to get the full SciTe editor for AutoIt (it is not included in the basic install). This editor includes a tool called AU3Record which will record your mouse and keyboard interactions with a Windows app and generate the AutoIt script to replay those actions. The tool is installed to: c:\Program Files\AutoIt3\SciTE\ScriptWriter\Au...

Unintuitive error in msi log when DTF is misconfigured

Took me a little headscratching to figure this one out. I was getting an error from my installer with the following text: MSI (s) (A8:50) [14:27:03:446]: Product: MyProduct -- Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. Action CA_ConfigFile_Install_Immediate, entry: CA_ConfigFile_Install_Immediate, library: C:\WINDOWS\Installer\MSI51BF.tmp The problem was not really that a DLL was missing, but that I had a typo in my <CustomAction DllEntry="xxx"> declaration. The typo caused a mismatch between the DllEntry value and the actual name of the .NET method implementing the [CustomAction].

Scheduling a deferred CA from an immediate CA

A pattern which is apparently in wide use in Wix/DTF land is to author the .wxs file to execute only immediate-mode custom actions, and to have these custom actions schedule deferred custom actions. The reasons? The logic for sequencing custom actions in MSI can be quite byzantine because deferred custom actions cannot access msi session state. They can only access state via CustomActionData, and this state must be constructed by a previously-executed immediate custom action. Also, it's just plain easier to code the state-setup and condition logic as .NET code than it is to create a chain of tags and have to maintain their sequencing in the .wxs file. To implement this pattern, simply author an immediate-mode DTF custom action whose implementation does something like this: [CustomAction] public static ActionResult SetupAction( Session session ) { // Prepare custom action data for the deferred custom action CustomActionData data = new CustomActionData(); data["SomePropName...

Wix 3.0 Web Application installer

Going through the exercise of converting a Visual Studio Installer for a web application into a Wix 3.0 installer. I have found several resources which have been invaluable so far: First, is Jon Torresdal's invaluable WiX and DTF series, which has quite detailed instructions on how to develop Wix 3.0 installers in general, and web installers in particular. My application consists of two different IIS applications with several hundred content files. Hand-coding the reference to each file would be unthinkable, and unmaintainable, so I had to come up with a solution which would automate the construction of the Component/File hierarchy from web deployment project's output filesystem structure. I did this by adding a pre-build step to the main Wix project, which does this: - Run a tool which creates two .wxi files by recursing through the web applications filesystem structure. The tool I used is an xml preprocessor based on the one I wrote for CruiseControl.net , however you could ...

Visual Studio Installer die!

I read today that Wix 3.0 is nearing completion and is scheduled to replace Visual Studio Installer (VSI) in VS10.  I've spent better part of a decade spent cursing VSI for doing everything just well enough that it seems like a good idea -- until, that is, it makes your life hell and you have zero options but to abandon the platform entirely. I downloaded InstallAware for Wix, but it only supports Wix 2.0 at this point, so I'm about to embark on an old-school mission to hack together an installer 3.0 by hand.  This after trying to edit a VS2008 VSI project and receiving an opaque COM error which I cannot make go away after a full day of trying. 

Two expressions which should never be used again

1. I'm going postal if I see another tech article whose title apes  the Wizard of Oz "Lions, Tigers , and Bears, Oh My!"   2. Really??? Really??? I've noticed over the past year or two an increasinly regular and disturbing phenomenon where I will be typing away and will spell a word in a pseudo-phoentic way which is miles away from its proper spelling.  Ordinarilly, I'm a pretty fair speller, and when this happens, I will realize it almost immediately and correct it.  I blame Google for making it normal to slice my attention span among 12 different things simultaneously.  Maybe Nicholas Carr is right . 

Typed Data Binding using Expression<T>

Use of System.Linq.Expression seems to be gaining momentum as a general-purpose tool for .NET programming. The first use that came to mind for me was as a mechanism for typed data binding. It has always bothered me that databinding mechanisms rely on the fragile (and unverifiable at compile-time) practice of passing the member in by name: name_textbox.DataBindings.Add("Text", person, "Name"); With the use of a fairly simple extension method, this can be made type-safe: name_textbox.Bind( () => name_textbox.Text, person, () => person.Name ); Here's the helper method: public static void Bind<ControlType, TSet, TGet>( this ControlType control, Expression<Func<TSet>> propSetter, object getter, Expression<Func<TGet>> propGetter) where ControlType : Control { control.DataBindings.Add( _memberName(propSetter), getter, _memberName(propGetter)); } private static string _memberName<TDelegate>( Expre...