ISWIX, LLC View Christopher Painter's profile on LinkedIn profile for Christopher Painter at Stack Overflow, Q&A for professional and enthusiast programmers

Thursday, August 17, 2006

CustomActionData for InstallScript 12 Only

lysemoose recently mentioned on InstallShield Community that he was trying to prepare for an upgrade to InstallShield 12 by refactoring his InstallScript custom actions to properly use the CustomActionData pattern.

The techniques described for use with InstallShield 12 are not compatible with previous versions of InstallShield. This is because previous versions use a DCOM/ROT singleton object to access the MSI handle from the client side msiexec not the server side msiexec that the custom action is running in.

For an example, populate the Property table with CustomActionData = Hello and try accessing it from an InstallScript deffered CA. You will see in your logfile the server side passing the CustomActionData to the custom action, but then you will see the original data from the property table appear in your MsiGetProperty.

If you replace the InstallScript with VBScript you will see the correct data since session.property uses the correct MSI handle.

This is why InstallShield 12 is such a big deal in getting InstallScript to be truely MSI compliant.

Wednesday, August 16, 2006

More Fun with CoCreateObjectDotNet

Emetrue recently asked on InstallShield Community how to pass managed datatypes rather than primitive strings to managed code custom actions using CoCreateObjectDotNet. The trick is to exploit Interop to create a COM representation of the .Net object then pass it back to the managed code environment.

Try this:

InstallScript:

function MyFunction(hMSI)

OBJECT colors;
OBJECT customaction;

begin

set colors = CoCreateObject( "System.Collections.ArrayList");

colors.Add( "RED" );
colors.Add( "WHITE" );
colors.Add( "BLUE" );

set myObject = CoCreateObjectDotNet("C:\\customaction.dll", "customaction.MyClass" );
customaction.MyMethod( colors);

end;

C#

using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;

namespace customaction
{
public class MyClass
{
public void MyMethod( ArrayList colors )
{
foreach( string color in colors )
{
MessageBox.Show( color );
}
}
}
}

Wednesday, August 2, 2006

Hard Core Setup Engineering In The News

It seems my thoughts on the new InstallScript redesign in IS12 have been noticed by the folks at Macrovision. The article was recently referenced in the Macrovision DevLetter. The folks at Macrovision were kind enough to describe me as an `Eminent Blogger`. While I appreciate the publicity, to quote Stefen Krueger.... `this may be slightly exaggerated`.


Judging by the looks of it, we have quite a few new visitors to the site! Please feel free to submit comments with alternative ideas and/or requests for topics to be discussed! While I do perform moderation, it's only for the occasional troll and spammer. Chances are that your comments will be approved.

Welcome!

Friday, July 28, 2006

Future of Installscript?

Nick Umanski recently asked on InstallShield Community this question:

"I did a Basic MSI course at Macrovision earlier this year and there it was mentioned that Installscript projects would be dropped at some point. This was not an official comment I might add, just some speculation. Does anybody have any knowledge of whether this is going to happen in the near future or not."

My response is:

The use of the word `InstallScript` is overloaded these days. I can think of atleast three possible meanings:

1) Basic MSI with InstallScript Custom Actions
2) InstallScript MSI ... an MSI installation which uses InstallScript as it's External UI handler
3) InstallScript project .. no MSI at all. Completly script/InstallShield framework driven.

#1 is my favorite. Lean and mean, using InstallScript CA's only where needed.

#2 gives a nice framework for people who want a fancier, more extensible UI. It also supports Setup Types alot easier then #1

#3 is particularly useful for situations that MSI doesn't support well. Two examples would be multipleinstance installation and another would be you don't want resilency. ( In certain server based situations the overhead of scanning keyfiles can have a negative effect on application performance )

Personally I doubt `InstallScript` ( in either context ) is going away anytime soon.

Thursday, July 20, 2006

Short Comings of LaunchConditions

Aaron Stebner posted a blog where he mentions a problem involving the fact that LaunchConditions doesn't support ordering of conditions. I've experienced this in the past myself and here are a few suggestions in the WindowsInstaller team happens to be reading.

In the past I've created installs that had the following additional requirements:

1) Display more then 1 condition at a time
2) Control the ordering of the conditions
3) Have the dialog be more `MSI` like ( ie not MessageBox )
4) Differentiate between Warnings and Errors

So I created a custom MSI table which is similar to the LaunchConditions table except that it has an Order column and a Required column. Then I wrote a CustomAction that processed the data and created an custom error property and a custom warning property. Finally I created a dialog that displayed the properties and either had a Exit button or a Next button depending on which property had data. I packaged this all into a merge module and reuse it with my various projects.

A future version of WindowsInstaller could easily implement this pattern by extending the schema of the LaunchConditions table and LaunchCondition standard action. A new dialog could be defined just like they did with the reboot mananger. The standard action could revert to the old behavior if the table doesn't have the new columns.

Then I could get back to authoring data relationships insted of writing custom actions.

Wednesday, July 19, 2006

MSI vs .NET

Now that I've had a few months to get comfortable with .Net, I realize just how uncomfortable MSI is with .Net. I really wish I could sit down for lunch with some people inside the Microsoft firewall and find out just what the scoop is between the two programs. WindowsInstaller is all about eliminating script and implementing data relationships to be processed by standard actions authored by people at Microsoft who are to be trusted to know what they are doing. .Net seems to be about rolling your own everything via the Installer class.

Take an assembly that contains a C# Service class derived from System.ServiceProcess.ServiceBase. In InstallShield you simply make the assembly a keyfile of a component, set the .Net properties to scan and author the appropriate ServiceControl and ServiceInstall tables. No plumbing, It Just Works!

Take that same assembly and double click on it and you will get an error message telling you that it must first be installed [using installutil.exe]. Find any website that teaches how to create a C# service and you'll read how to use a ServiceInstaller class to add the service.

The same conflict can be found over and over almost any system installation and configuration topic you can think of.

And of course just TRY telling .Net developers that there is a better way to do it. You'll quickly find out how much respect they have for the guy that does installations. After all, Setup is just XCOPY, right?? :-)

Saturday, June 24, 2006

InstallScript CA Performance Issue

InstallShield's InstallScript CA refactoring has led to one tradeoff: There seems to be about a 2 second transaction cost for invoking a CA on a typical machine.

With the old ( and very unreliable ) model, the InstallScript engine was initialized at the beginning of the installation and maintained for the live of the installation. With the new ( and much more reliable ) model each invocation of an InstallScript Custom Actions results in the initialization of the InstallScript engine, execution of the custom action and cleanup of the engine.

So let's talk about ways to mitigate this:

Use WindowsInstaller Properly

Now let's be brutally honest about custom actions. I believe that a setup developer should strive to have as few custom actions as possible. The built in patterns of WindowsInstaller should be leveraged as much as possible.

Combine Related Custom Actions

Think of ways of creating combining multiple custom actions into a single custom action. If you are calling more then one custom action in a row in the a given sequence, create a new InstallScript function that acts as a driver to the other InstallScript functions. The custom actions that are being grouped together don't have to have the same conditions. You can use MsiGetProperty and if/else/case constructs within the driver function to conditionally execute functions. If you have more custom actions elsewhere in the sequence, ask yourself if they could be rearranged for greater effect. Each combined CA will save you about 2 seconds.

User Experience

Let's say you implement AppSearch but then you have to use a InstallScript Custom Action to perform some business logic to complete the search pattern. There is a 2 second cost there, but the user is unlikely to notice because he's look at a splash dialog telling him to please wait while setup initializes. Same thing applies to deferred Custom Actions since the user is watching the InstallationProgress dialog and the various status messages and progress bar updates occurring. Frankly they expect this step to take some time to execute.

ControlEvents on dialogs is where you can get in trouble with the user very quickly. When a user clicks the next button on a dialog they expect to be taken to the next dialog very quickly. A two second delay is borderline for even the most patient user. I've recently had a discussion with a setup developer who had several DoActions on the control which resulted in as much as a 20 second delay. Consolidating those custom action calls as described would reduce this by 90% but it would still be 2 seconds.

Refactor to C++
While I really believe that InstallScript is a robust domain specific language, there may be scenarios ( like the above ControlEvent scenario ) where performance really is critical and in that case you will have to write a C++ Type 1 custom action.