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

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.

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.

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?? :-)

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.

June 07, 2006

InstallScript, meet CustomActionData

I've made a small contribution to InstallSite entitled:


"Decode the CustomActionData Property in InstallScript"


Now that InstallScript CA's running in Deferred/Commit/Rollback execution don't have access to the MSI handle via IDriver we must follow the same rules that other CA's must follow. One of these rules is that we only have access to a limited number of MSI Properties.

This contribution is designed to illustrate how to use an immediate Type51 Property Custom Action to assign an array of properties to the CustomActionData property (such as /PROPA=1 /PROPB=2 /PROPC=3) and then from within InstallScript decode the value of PROPA, PROPB or PROPC.

I hope this helps people making the transition to the new InstallScript runtime environment.

April 28, 2006

InstallShield 12 Beta2

In previous postings I've rambled on about the search for the Holy Grail of Custom Actions. I do believe that I've found it. Buried in the "what's new" for IS12 (Beta) is this little blurb:

`InstallScript design enhancements`

Ok, I know, you might be saying 'Yuck, InstallScript' or 'Yuck, Script!' But give me a second here to explain. I think you'll like it enough to pass it along to other developers who have lost faith in InstallShield.

The 2 biggest problems with InstallScript have been:

1) The need to bootstrap a scripting runtime. setup.exe != pure .msi
2) The ISScript engine had so many bugs in it that it spawned a support website of its own.

I am pleased to report that both of these problems are HISTORY! InstallScript CustomActions now compile to Type 1 Custom Actions. These means the only real difference between a C++ custom action created in VS6.0 and an InstallScript Custom Action is how much time and effort to took to write it.

Imagine all of the glory of InstallScript.... a Domain Specific C-like scripting language ( I'm not sure why they call it script anymore, it doesn't really have a scripting engine! ) that gives you an integrated IDE, Compiler, Linker, Debugger, a host of functions, simplistic datatypes, and the ability to easily invoke Native Win32API, COM and Managed Code all in one package with easy access to the MSIHANDLE.

A couple versions back InstallScript added the CoCreateDotNet() function. It basically works like this: Your write a class in VB.NET/C# and declarate it with [assembly: ComVisible(true) ]. After building the assembly you simply drop this assembly in your SUPPORTDIR view ( No COM Registration Required! ) And call it from our InstallScript:

export prototype ExampleCA( HWND );

function ExampleCA( handleInstaller )
STRING supportDir;
NUMBER bufferSize;
OBJECT myClass;
begin
MsiGetProperty( handleInstaller, "CustomActionData", supportDir, bufferSize );
set myClass = CoCreateObjectDotNet( supportDir ^ "myassembly.dll", "myNameSpace.myClass" );
myClass.myMethod();
set myClass = NOTHING;

return 0;
end;

More detailed examples can be found here

How easy could that be? No ActiveScript to blow 1720 error messages at you. No C++ to write, no CLR to invoke, no configuration of the system such as COM registration or putting assemblies in the GAC needed to call your managed code.

Now that's what I call Hard Core Setup Engineering.

Congratulations InstallShield. I only hope that Setup Developers will give InstallScript a second chance.

March 08, 2006

A New Approach to Managed Custom Actions

Well I finally got around to diving into C#. Last week I spent a week with Richard Hale Shaw and 19 other coworkers going through a 5 day Visual Studio 2005 and .Net Framework 2.0 Bootcamp.

I won't rehash the usual arguments against managed custom actions. I'll assume your application already needs the .Net 2.0 Framework so that it really isn't a big deal to have to either bootstrap this and/or include in your LaunchCondition to require that it be installed.

So consider the following design pattern:

Server Side ( MSI context ):

Mixed Mode MC++ DLL that contains a standard call function and a .Net remotable object . We schedule the CA at the beginning of the InstallUISequence and InstallExecuteSequence. We will run the CA in Immediate Execution and msidbCustomActionTypeFirstSequence
and a that gets call at the beginning of the install. The SAO Singleton Remotable Object has wrapper methods for all of the MSI API functions that we want to call. When the Type 1 CA is invoked it starts up the CLR and hosts the remotable object. Next the custom action activates the object by passing the MSIHANDLE to a public property set accessor. Finally the custom action goes into a while loop checking once a second to see if a public property has been set to Exit indicating it's time to dispose and quit. Later in the install we will set the property to the exit setting.


Client Side:

The client side can be any managed code including run in any context. The managed code connects to the URI of the remotable object calling the MSI API wrapper method desired. The object is actually activated in the context of the server side which means it has access to the Installer Context.

The result is IPC using .Net Remoting and now you can write simple, powerful and robust Managed Code CA's with minimal plumbing to talk to the Installer.