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

October 25, 2009

InstallAware Give Away Results

I'd like to thank Sinan at InstallAware for his generous offer of a InstallAware Developer license to readers of this blog. The offer started on Tuesday and went until Friday. During that period this blog had 1379 page loads from 859 unique visitors. Sinan Karaca reports to me that they gave away 56 free licenses worth $83,944.00.

In other news, the Federal Trace Commission has adopted new guidelines that requires blogs to disclose endorsement compensation. As such I've posted an official disclosure stating the position of this blog. In summary, this blog has never and will never accept any form of compensation. We will however pass on swag opportunities to our readers when given the chance.

October 20, 2009

InstallAware Complimentary License Announcement

Update: Per Sinan, this offer has expired.

In a recent blog comment, Sinan Karaca posted:

In fact, anybody reading this blog and wanting to check out just how revolutionary InstallAware is, send sales at installaware.com an email with the subject "Painter License" and we'll send out a complimentary Developer license your way. Till this Friday only :)

Cheers,
Sinan


Well, who am I to pass up an opportunity for my readers to get a free copy of InstallAware? So if you feel like trying something new to fire off your email request.

Note: InstallAware requires a non-anonymous email address ( no gmail, yahoo, msn ) and DeploymentEngineering.com is not affialated with InstallAware and has no role or responsibility in this give away promotion.

October 19, 2009

InstallAware Uninstall Problem

I was reading a news release where InstallAware boasted:

"InstallAware setups power the installation of the Activation Assistant for Microsoft Office 2007, pre-installed by OEMs on millions of laptops around the world," says Sinan Karaca, founder of InstallAware Software Corporation.


I decided to google "Activation Assistant for Microsoft Office 2007" and the results indicate that millions of people around the world can't get this software removed from their box. Way to go Microsoft and InstallAware! I don't have access to the installer, but from the symptoms I'm reading, it sounds like somebody forgot to listen to sage advice of always including "or Installed" in their LaunchConditions.

Anyways, the install issue caught the attention of PCWorld. Here's a snippet of the write up that is really worth reading.

Activation Assistant's Dirty Little Secret
It turns out that the Activation Assistant for Office 2007 has been a serious hassle for Microsoft. According to Joe, the Activation Assistant accounts for the great majority of tech-support calls. He wasn't specific, but said that the program is basically flawed. Apparently there's a fix coming in Office 14.

In fact, the Activation Assistant is so troublesome that when I suggested that we just reinstall the dang thing, he flat-out refused. He said that would likely cause more problems--and I don't argue with escalation managers...


So maybe InstallAware should dig a little deeper when trying to reference "successful" projects.

InstallAware resorts to Sex Appeal


It's an old adage that "sex sells" in marketing. But surely there is no space less sexy then setup development tools, right?

Well, it seems InstallAware has sunken to new lows by engaging with marketing partners to spam the twittersphere using what I can only assume are astroturfing fake profiles. Their PR angle is that they a shining example of stability in light of InstallShields multiple name changes.

Hmmm. Based on the comments, emails and threads that I've been shown InstallAware could actually use a good corporate identity change right now. The level of customer disservice (including rude attacks against customers ) that I've witnessed has been horrific.

MSDN Goes Blue



Enough said?

October 08, 2009

Goodbye Acresso, We Hardly Knew Ye

I read the news today that Acresso is changing it's name to Flexera.

Huh? Why?

As if the makers of InstallShield hadn't already done enough damage to their brand, let's just go change names yet again!


BTW, Flexera is already taken by a company in the alternative energy market. Anyone want to take a guess which one of these companies actually stands a chance of being in a high growth market for the next ten years?

September 30, 2009

MSSE Validation Errors

I recently downloaded Microsoft's new Security Essentials Suite and I decided to take a look at how it's installer is constructed.

My first observation is how they once again use an external UI to get around the fact that Windows Installer does such a poor job at localization.

Then I ran MSI validation and discovered the following gem.

ICE08 ERROR Component: SetupResMui_NLNL has a duplicate GUID: {1230940F-EB02-47B7-ACFF-D0E76871D928}
ICE08 ERROR Component: MsMpResDll has a duplicate GUID: {8FEE8260-3507-417A-AF09-1C24F341FA14}
ICE08 ERROR Component: shellextDllMui_ZHCN has a duplicate GUID: {A5F76683-9CAE-4F3F-B4FD-1668EB2C3FAD}
ICE08 ERROR Component: SetupResMui_PTBR has a duplicate GUID: {D0D868D8-EC9D-423F-AF62-345A4EEFE3C3}

I'm afraid to even ask. :-)

September 29, 2009

Configuration Manager In Training



I don't talk about my family life much but today my daughter Ashley ( Age 6 in 1st grade ) wrote the cutest thing: A french toast recipe!

See, I work a lot during the week ( probably too more then I should ) and on weekends I typically do the cooking. Very often I'll make french toast since they are always asking for it. It's a real big hit.

I was sitting at work today when I received this picture and it just warmed my heart. Milk, Eggs, Sugar, Nutmeg, Cinnamon, Mix it up and grill it with love followed by happy!

Awww, too cute.

Anyways, I can tell this kid is going to love Build/CM. :-)

Finally, here's the real recipe

16 slices thin white bread slightly stale( none of that wheat stuff mommy likes )
1 cup of egg beaters
1 cup of milk
1/2 cup of sugar
1 tsp vanilla ( life is too short for artificial )
1/2 tsp cinnamon
1/4 tsp nutmeg

Stir briskly with a whisk, drip bread and cook on a griddle coated with PAM heated to 325f. Serve with "daddy eggs" ( eggs over easy @ 375f with REAL butter ) and bacon.

September 23, 2009

Favorite InstallShield Automation Interface (Feature)Bug

Does anyone actually use the InstallShield automation interface? I'm guessing not due to huge number of bugs, bad behaviors, poor documentation and missing functionality that I routinely step into every time I try.

I'm too tired to recap every bug I've ever found, so here's my new favorite.

Let's say you are calling the ISWiProject.AddFeature( string ) method and you pass it a feature that already exists. What would you expect the proper behavior to be?

a) throw an exception that tells you that you violated a primary key constraint

or

b) throw a modal dialog telling you that you violated a primary key constrant and then swallow the exception.

Argh!!!! Enough said? I guess that's why we pay tens of thousands of dollars for maintenance and then never get our bugs fixed. Just shoved along to new releases with more bugs.

September 21, 2009

Interesting Posting on Monster

I came across this post on Monster the other day:

If you are a WINDOWS INSTALLATION ENGINEER that has experience installing windows pre-Installshield (i.e. the old fashioned way!) - think API's, DLL's, and registry setting - this is a great opportunity for you!!

Our client is seeking a smart, experienced Windows Engineer with an ability to work in the dynamic environment of an emerging growth company. You will be tasked with attacking new problems and be presented daily with development challenges that will require a high degree of versatility, mental flexibility, and innovation to solve.


This would make sense if the position if for a setup tools developer rather then setup developer, but the posting seems to clearly indicate that it's the former rather then the later.

How retro? For the love of... why??

Sure, from my script days of the 90's I probably remember how to do all of this stuff but what is the value in loosing every foundation class library available? What is the value for shunning the declarative approach of Windows Installer and doing a roll your own EVERYTHING imperative approach?

I'm lost on this one.

But maybe it really is for a tools position in the open source space and that something new and different will emerge.

BTW, I'm reminded of an embarrasing moment. About 6.5 years ago I was busy doing a build when the phone rang. It was a Senior Director of Technology for Continental Airlines calling me for a phone interview. We chatted for a minute and then he asked me how to replace a locked file on Windows.

My mind drew a blank. Sure, I knew MoveFileEx and PendingFileRename operations but I just couldn't think it at that moment. So instead I gave some lame explanation of InstallShield having a setting for locked files and that it was a black box / white box kind of thing and that if it was to fail I'd spend time profiling it to identify the cause.

The moment I hung up I thought, damn it, why didn't you talk about the Win32 APIs behind the scene? Ughh!

I ended up getting the job.

A couple years later I asked him why he hired me when I couldn't answer such a simple question and he said:

"Because you actually WANTED to do installs."

I think that says enough about our space. It was true then and it's true now, IMO.


September 16, 2009

Name This Tool

I've been working on a WiX GUI editing tool lately that I'm hoping to release as open source soon. I can't go into many details at this point because many things aren't decided yet.

One thing that I need to get settled is what to name it. Here's where I'm hoping you can help. If you have a suggestion for a name, please leave a comment below.

Rules:

After a suitable list is generated, a poll will be created where my readers will rank their priority.

The final ranked list will be vetted for trademark issues and a final name will be choosen.

If you'd like the glory of claiming you named the new tool, please leave your real name when posting.

The final name selected becomes the property of DeploymentEngineering.com and who ever I may assign it to.

For a quick tease of the new tool, click the link below.

August 24, 2009

Specifying Source Files

I've been spending a lot of time lately thinking about use cases for source file location abstractions. Some tools like Visual Studio Deployment Projects provide no abstraction and other tools such as InstallShield provide abstractions (Path Variables) based on environment variables, registry values and/or command line arguments.

Then there is Wix can use different types of compiler inferences and preprocessor variables and/or extensions.

Obviously this can get very complicated so I'm curious, what is your favorite way to roll and why? What do you need and what could you live without?

July 26, 2009

Maybe I Should Roll My Own Part II

Just over a year ago I played around with .NET object serialization for a day and came up with a simple little program that could build a WiX element tree, set the attributes and write the XML out. I blogged about it here.

Since then I've taken a .NET 3.5 / WCF / WPF / LINQ class and I now realize that LINQ to XML is perfect for this task. For example, consider the simple example of a tool that can switch between designer view and xml view. It can all be done in 10 simple steps:

1) Create a couple of tab pages. Put your designers on one and a richtext box on another.
2) Use XElement.Load() to load the WiX document into an in memory object model.
3) Use XElement.ToString() and pass it off to the RichTextBox.
4) Create an event handler and wire it up to the XElement changd event so that any time something changes in the object model you can refresh the XML view.
5) Use LINQ to query the object model and feed the data into your UI components.
6) Use your UI components to manipulate the objects using LINQ.
7) Wire up the RichTextBox TextChanged event to refresh your UI if the XML changes.
8) Use XElement.Save() to save your changes.
9) Use visual studio integration to wire the tool up to Votive. The concept is to not reinvent the wheel. Just edit the WXS/WXI files out of process and let votive reload the documents after you save your changes.
10) Profit! ( Sorry, Slashdot joke )

Sure, there's a lot of work to do it all correctly but the basic pattern is actually quite simple. So here's a couple screenshots of a (mostly working) program I was able to write in one day.



July 10, 2009

Austin meets Heat


Whew it's been hot in Texas lately. AFAIK it's been 100f+ for the last several weeks with no end in sight. Accordign to weather data, the max temp for last month was 106f with an average of 99f and a min of 90f. This month we are tracking for 106f, 102f and 93f. Whew.

So what does this have to do with setup? Well, I've been playing with WiX's Heat a lot lately. I got tired of running heat from a command prompt and then repeating my same cleanup tasks over and over so I decided to automate it a little with a C# winforms application. While I was at it, I added an interesting feature that I thought was a bit gimmicky at first until I started getting feedback on how cool it was.

What did I add? Simple: a FileSystemWatcher that monitors a directory for updates and then dynamically regenerates the wix document, cleans it up and then refreshes the display to show the new WiX code. With multiple monitors you just stage the dirctory on one screen while watching the program write the code for you on the other screen.

It's really a simple concept but everyone finds it quite informative. Once you have what you want you just cut and paste it into your Votive project.

So I was going to call this new tool "Blow Torch" but when I asked a coworker who is also named Chris how he liked the name he just said that he'd call it Austin.

Austin? Hmmm.... Sure, Why not? I like the sound of it.

So the hear finally destroyed our HVAC plant at work and everyone was sent home for the weekend early. This gave me a few hours to work and now I have Austin built and packaged. For now I'm just going to tease everyone with a screenshot but hopefully in a week or so I'll pass all of quality checks and release this tool for others to play with. That process might go faster if people actually bug me for a copy. ( Hint Hint! )

BTW, in case your wondering why the screenshot has a refresh button, I'm working on making it a feature to scan automatically or manually.

July 04, 2009

WiX 3.0 Ships

Wix 3.0.5419 has been promoted to Production Stable quality on SourceForge.net and can be downloaded here.

I've been fairly critical of WiX over the years but today marks a turning point in that believe. With the release of 3.0, many features are now in place that begin to make a really strong case for seriously considering the use of WiX over legacy tools. While WiX still lacks a 1st class bootstrapper/chainer and proper IDE GUI design tools that other tools have, I believe that the core foundation of WiX is much better positioned for the future.

Hopefully we'll see WiX 3.5 ( featuring Burn )in 6-12 months to address these concerns. I also hope to see Votive explode into a fully featured visual studio add-in. Finally, I expect a market of WiX based designer tools to appear. Hopefully WiXAware 3.0 will be released ( and even more hopefully that it actually work! ) and I also anticipate InstallShield will eventually bring tools to market based on WiX. IMO it is inevitable and the InstallShield brand as a packaging tool will not survive if they do not.

So there it is: WiX 3.0 is shipped and I now see the road that I will travel towards over the coming months. With dozens of installers composed from hundreds of merge modules and tens of thousands of files, it'll take us awhile to get there from sure. But I am no convinced that the effort will be worthwhile.

June 24, 2009

DRM Activation Question

ShadowWolf recently commented:

Activation ( and reactivation ) are pretty par for the course in the business tool world from what I've seen. I don't know that anyone really "likes" it, but it definitely serves a legitimate purpose.


This comment made me wonder, is this true? I work in an environment with airgaps around our network connections for security purposes and I can't think of a single tool that we use besides InstallShield that requires activation and/or reactivation.

Sure, Windows does (once) but they also offer a volume license key that doesn't require activation. Microsoft Office works the same way. Visual Studio, TFS and so on. Even our IBM/Rational products don't give us this problem and trust me, those are some pretty darn expensive tools. The only product that we use that I can think of is Robohelp.

So I'm curious, what are some of the products my readers use that require activation?

June 18, 2009

InstallShield 2010 vs WiX 3.0

It's been no secret that I've favored InstallShield over WiX for many years. I've used InstallShield products since 1997 and I've shipped hundreds of installers using this versatile tool. InstallScript, XML Locator, Setup Prerequisites, Multiple Instance Support, COM Extraction, MySQL, Dialog/Control editors, Product/Release configurations and Component authoring wizards/views have made me a very productive and profitable person over the years.

Unfortunatly, there are also things I dislike about InstallShield. The DRM activation ( and now reactivation with IS2010 ) is horrible, difficulty in trying to get updates in an offline scenario (which we always are for security purposes), the random crashes, the horrible DTD/XML transformation, sequenced primary keys and of course, the removal of the stand alone build from Professional and totally useless collaboration tool combined with the really high price of the product.

If I'm hurting anyones feelings, I'm sorry. It's hard for me too since I've used this tool for so long and I do believe it's still a very good tool for many development shops. Just not for mine.

At my day job, I lead a team of 4 ( going on 6! ) setup developers. We collectively maintain dozens of installs that generate and consume hundreds of merge modules from a software product line. Our typical installer ships 10,000 - 15,000 files and includes countless databases, services, webservices and many chained packages of programs that we integrate with. All of this occurs on many active branches.

Unfortunatly InstallShield with it's DTD XML and incremented primary keys just doesn't work well in this environment. Merging branches back together in clearcase is a nightmare since you always end up with unresolved conflicts. Enter WiX. The XSD XML is 95% smaller then DTD XML and is way more expressive. Also thanks to deterministically unique primary keys and guids, changes done on multiple branches can actually merge back together easily.

The problem with WiX of course is the lack of gui designer abstractions and visualizations. Fortunatly I finally have a solution for that. I've recently had an internal tools developer assigned to me to come up with our own collaboration tools to sit on top of votive. Once complete we are hoping to once again try decentralized setup development. I'm not sure it'll work ( it didn't last time ) but we are going to give it a try again. The reality is our environment is growing so fast that we need to retool and try new strategies to keep up. Hiring more and more people just doesn't seem to work anymore.

May 28, 2009

Now Hiring - Austin, TX

I'm looking for an experienced InstallShield / MSI / WiX / BuildForge / TFS / C# software engineer to join my team in Southwest Austin, TX. The engineer will be part of a Build and Install team that currently consists of 8 members with 3 more on the way to meet our ever growing needs.

Please contact me at chrpai@deploymentengineering.com if you are interested.

Please note, due to customer requirements, all applicants must be a US citizen. Ability to obtain and maintain a US Security Clearance is required; an active clearance is highly desirable.

April 27, 2009

Trip Down Memory Lane


I don't talk about this much these days, but before my career in computers I was once a musician. From 1993 to 1996, I was assigned for duty with "The Commandant's Own" United States Marine Drum and Bugle Corps. It was quite an honor to have earned the privilege to tour with such an outstanding group.

Those were some really great years of my life. Thanks to Facebook, I'm able to keep in touch with my former fellow Marines and in June we'll be having a 75th anniversary reunion in Washington, DC.

So turn up your speakers and press play for a trip down memory lane.

April 17, 2009

WiX DTF Mystery Solved

Last October a (then) former ( and now current ) coworker also named Chris asked me the following in an email:

I am running into a problem with a DTF custom action. When the action tries to run I get:

"SFXCA: Failed to create new CA process via RUNDLL32."

This on is weird because I am using the exact same module in another product on the same machine and it works like a champ. Bizarre.

My initial reply was:

Are any CA's running before it?

I hadn't seen this error before and I was a little concerned because I was such a proponent of DTF and managed custom actions I was afraid that perhaps DTF had an Achilles' heel. I also knew that where my friend worked was the home of a very restrictive environment so if anyone would find a problem with DTF, it would be him!

I introduced Chris to the creator of DTF, Jason Ginchereau, and the two attempted to troubleshoot the problem with little progress. I didn't really follow up on it because at the time I was busy cranking through sprints for a new product at Multimedia Games.

Fast forward five months and I'm working with Chris again refactoring build automation, creating installation tools and writing custom actions for installs. Suddenly the ugly RUNDLL problem rears it's head again only this time it's MY problem because I'm now the install team lead and I'm always saying how good DTF is.

Rats.

So I email Jason again and log a bug (SF210297) at SourceForge to make sure it gets proper attention this time. This time Jason sees some problems on the unmanaged side of DTF. He was assuming that the current working directory of the recycled process hadn't been mucked with ( remember my comment about other CA's scheduled prior? ) when he made his call to RUNDLL32.

So to make a long story short, I just completed an effort with the build team today to update 30 some virtual machines to have WiX 3.0.5210.0. Between this bug fix and many others related to DTF, I really suggest that anyone using DTF custom actions in builds prior to 5210 upgrade ASAP and don't ship your product until you do. You might never come across this problem but I know I sleep better knowing I won't either now also.

April 15, 2009

InstallAware Email Thread ... Is this for real?

I came across a very interesting email thread that is really far out there. I almost want to believe it's a fake but having dealt with InstallAware and Michael Nesmith in the past, I can only conclude that it's legit.

You can read the exchange here at CodeProject.com.

April 01, 2009

When You Wish Upon A Star



When you wish upon a star
Makes no difference who you are
Anything your heart desires
Will come to you


Wow, have they grown fast! It seems like just yesterday that Ashley and Emma was born.

When you have a 4 year old and a 6 year old who both are princesses, there's only place you can go for vacation... it's simply time to visit the mouse.

Anyone have tips for a first-timer? We'll be going in May before Memorial day.

Wish me luck! :-)

March 27, 2009

Interesting Tweet

I just saw this tweet on Twitter:



I don't know the whole back story, and I'm sorry Jim feels that his work is going down the drain, but I only have one thing to say to this:

Hip Hip Hooray!!!!!

March 20, 2009

SQL Server 2005 SP3 Horrible Setup Experience Results in BSOD

I maintain a bootstrapper at work and recently we were asked to update SQL Server 2005 SP2 to SQL Server 2005 SP3.

Not a big deal, right?

Wrong!

When installing SQL 2005 SP3 the setup just blows chunks and reboots the computer via blue screen of death!

Worse, the machine goes into an infinite reboot because the installation is an incomplete state and everytime the SQL services try to start the machine BSODS again.

You can boot safe mode and disable the services and then reboot again. But if you attempt to uninstall SQL server you get an error message saying it can't be accomplished.

Wow, thank you Microsoft, you've outdone yourself yet again.

So in digging into this problem it seems that the SQL team is punting to the Windows team. They are saying that they manifested PE files for Vista/2008 in SP3 and that due to a bug in Windows SXS on SP2 ( hotfix available for SP2 or otherwise update to SP3 ) that there is nothing the SQL team can due to solve this.

Um, they could at least put an AppSearch/LaunchCondition into their install so that my machine doesn't turn into a burning pile of dung!

Anyways here's my official warning. Avoid SP3 like the plague and if you must go there, make sure you provide your own prereq check for SP3 or SxS hotfix level in and as always make sure you integration test your installs on the lowest platform configuration possible. I'd hate for some ISV to test on SP3, never see this problem and then ship a product that embeds SQL to a customer. I'd hate even more to have to be taking that BSOD support call.

March 09, 2009

Records Being Dropped From Merge Module Projects When Built Using the InstallShield 2009 Standalone Build

---------------------------------------------------------------
[Update/Retraction 3/16/09]
I like to think I'm a big enough man to admit when I'm wrong, so here goes...
The problem reported in this post is fixed by updating to the SP2 version of IS 2009 Standalone Build. Now in my defense, I didn't know there was an SP2 until I reported this problem because the Software Manager doesn't properly identify the update (so I thought I already had "Standalone Build" installed). Anyway, I'm going to leave the original post up (below) in case any readers have the same problem.
---------------------------------------------------------------

I thought I'd post information about another bug I found in InstallShield 2009 merge module projects that I found while comparing output from a merge module project built using the standalone builds for IS 12 and IS 2009.

Records entered into the ProgId or Registry tables in the merge module source project do not get created in the output merge module file (.msm).

Acresso support has duplicated this behavior and I am currently working with them to find a work around (my incident number is SIOA-000143195).

This can be a serious issue if you are not using [or cannot use] the "COM Extract At Build" option to populate the appropriate MSI tables with COM interfaces when the module contains COM binaries. An example of this (that I'm stuck with at the moment) is if the install contains 64-bit COM binaries but is actually built on an x86 machine. In this case, the "COM Extract At Build" option doesn't work so we use the "REG File To Merge At Build" option to add the required interfaces directly to the MSI Registry table.

I suspect (but have not confirmed) that this may also occur for any records added to the Class or TypeLib tables in a merge module source project file. There may also be others.

February 19, 2009

MSI Tip: How to Reuse a CustomAction for Deferred and Rollback

Neil Sleightholm recently asked how to tell if your in a rollback custom action using C#/DTF. The answer is simple.

Let's suppose we want to export one custom action method and make it multipurposed. In other words, if we call into while deferred execution we should do one thing but if we call into it for rollback execution we should do another.

How would we do that? The answer is in the BOOL MsiGetMode( __in MSIHANDLE hInstall, __in MSIRUNMODE iRunMode) Windows Installer function exposed by the Session.GetMode( InstallRunMode installRunMode ) DTF method.

Consider the following WiX Code:

    <Binary Id="CustomActionModeTest"
            SourceFile="PATH_TO_DLL.CA.dll "
    </Binary>
 
    <CustomAction Id="RollbackCA"
                  BinaryKey="CustomActionModeTest"
                  DllEntry="CustomAction1"
                  Execute="rollback"
                  Impersonate="yes">
    </CustomAction>
    <CustomAction Id="DeferredCA"
                  BinaryKey="CustomActionModeTest"
                  DllEntry="CustomAction1"
                  Execute="deferred"
                  Impersonate="yes">
    </CustomAction>
 
    <InstallExecuteSequence>
      <Custom Action="RollbackCA" 
              After="InstallInitialize">
      </Custom>
      <Custom Action="DeferredCA"
              After="RollbackCA">
      </Custom>
    </InstallExecuteSequence>



You'll notice we have 2 custom actions pointing to the same exported function in the binary table. Also notice that one custom action is scheduled as deferred and the other rollback. The deferred is scheduled right after the rollback. This results in Windows Installer scheduling RollbackCA after InstallInitialize and DeferredCA after RollbackCA.

Now let's look at the code inside of that Custom Action.

using System;
using System.Windows.Forms;
using Microsoft.Deployment.WindowsInstaller;
 
namespace CustomActionModeTest
{
    public class CustomActions
    {
        [CustomAction]
        public static ActionResult CustomAction1(Session session)
        {
            ActionResult result = ActionResult.Success;
 
            if (session.GetMode(InstallRunMode.Scheduled))
            {
                MessageBox.Show("I'm not in rollback, let's cause one to occur!");
                result = ActionResult.Failure;
            }
            
            if (session.GetMode(InstallRunMode.Rollback))
            {
                MessageBox.Show("We are now in a rollback." );
            }
 
            
            return result;
        }
    }
}


At runtime, RollbackCA is skipped and DeferredCA is executed. The CustomAction1 method will be executed by the DeferredCA and it will detect that it's scheduled in deferred mode and display a message saying that it's not in rollback and that it'll cause one. It does so by returning a failure to Windows Installer. Now MSI starts walking the script backwards executing any rollback CA it finds. This causes it to run RollbackCA and once again we are inside of the CustomAction1 method.

This time we will evaluate that we are in rollback, display a message stating so and quit gracefully. At this point the product is not installed.

This pattern can be extended so that CustomAction1 also handles immediate execution, implicit scheduling of the deferred custom actions and CustomActionData serialization/deserialization. But I'll leave that for another blog.

February 15, 2009

MSI Tip: Authoring an ICE using C# / DTF

I once wrote an article for InstallShield entitled "MSI Tip: Authoring a Custom ICE using InstallShield 2008". The article can be found here. [Warning: PDF]
In the article, I demonstrated how to write a unit test that could find evil script custom actions. While there is value and humor in doing so, the real point of the article was to demonstrate how InstallShield's refactored InstallScript language could be used to write ICEs.

While InstallScript is certainly an improvement over C++ in terms of cutting down on the line noise and complexity, the difference between C++/InstallScript and C# is nothing short of amazing. As such, I've created a sample project demonstrating how to author ICE's using C#/DTF and Stefan Krueger of InstallSite.org is kind enough to host it for me here.

Consider the following snippet from an MSDN sample demonstrating how to write an ICE in C++:


#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include <MsiQuery.h>
 
///////////////////////////////////////////////////////////
// ICE01 - simple ICE that does not test anything
UINT __stdcall ICE01(MSIHANDLE hInstall)
{
// setup the record to describe owner and date created
PMSIHANDLE hRecCreated = ::MsiCreateRecord(1);
::MsiRecordSetString(hRecCreated, 0, TEXT("ICE01\t3\tCreated 04/29/1998 by <insert author's name here>"));
 
// post the owner message
::MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER), hRecCreated); 
// setup the record to describe the last time the ICE was modified
::MsiRecordSetString(hRecCreated, 0, TEXT("ICE01\t3\tLast modified 05/06/1998 by <insert author's name here>"));
 
// post the last modification message
::MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER), hRecCreated);
 
// setup the record to describe what the ICE evaluates
::MsiRecordSetString(hRecCreated, 0, TEXT("ICE01\t3\tSimple ICE illustrating the ICE concept"));
 
// post the description of evaluation message
::MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER), hRecCreated);
// time value to be sent on
TCHAR szValue[200];
DWORD cchValue = sizeof(szValue)/sizeof(TCHAR);
 
// try to get the time of this call
if (MsiGetProperty(hInstall, TEXT("Time"), szValue, &cchValue) != ERROR_SUCCESS)
StringCchCopy(szValue,  sizeof("(none)")/sizeof(TCHAR)+1, TEXT("none"));// no time available
 
// setup the record to be sent as a message
PMSIHANDLE hRecTime = ::MsiCreateRecord(2);
::MsiRecordSetString(hRecTime, 0, TEXT("ICE01\t3\tCalled at [1]."));
::MsiRecordSetString(hRecTime, 1, szValue);
 
// send the time
::MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER), hRecTime);
 
return ERROR_SUCCESS; // allows other ICEs will continue
}

With DTF and a little OOP ( Object Oriented Programming ) this can be reduced to the following snippet in C# / DTF:

using DE.TestFramework;
using Microsoft.Deployment.WindowsInstaller;
 
namespace DE.Tests
{
    partial class ICE01 : TestBase
    {
        [ICETest]
        public void TestExample()
        {
            Publish( ICELevel.Information, "Created 04/29/1998 by <insert author's name here>");
            Publish( ICELevel.Information, "Last modified 05/06/1998 by <insert author's name here>");
            Publish( ICELevel.Information, "Simple ICE illustrating the ICE concept");
            Publish( ICELevel.Information, "Called at " + Session["Time"] );
        }
    }
}
 
That may not seem like a big deal but consider the flexibity a few overloads can provide:

public void Publish(ICELevel iceLevel, string Description)
public void Publish(ICELevel iceLevel, string Description, string HelpLocation )
public void Publish(ICELevel iceLevel, string Description, string HelpLocation, string Table, string Column, string PrimaryKey)
public void Publish(ICELevel iceLevel, string Description, string HelpLocation, string Table, string Column, string[] PrimaryKeys)

Of course the real power comes from DTF's awesome interop classes. Going back to example the of detecting script custom actions in InstallScript, here is what it would look like in C# / DTF:

using DE.TestFramework;
using Microsoft.Deployment.WindowsInstaller;
using System;
 
namespace DE.Tests
{
    partial class ICE_DE_10
    {
        [ICETest]
        public void TestForScriptCustomActionsAreEvil()
        {
            Publish(ICELevel.Information, "Searching for Evil Script Custom Actions...");
 
            using (View view = Session.Database.OpenView("SELECT `CustomAction`.`Action`, `CustomAction`.`Type` FROM `CustomAction`"))
            {
                view.Execute();
                foreach (var record in view)
                {
                    string customActionName = record.GetString("Action");
                    int type = record.GetInteger("Type") & 0x00000007;
                    CustomActionTypes customActionType = (CustomActionTypes)type;
 
 
                    if (customActionType.Equals(CustomActionTypes.VBScript) || customActionType.Equals(CustomActionTypes.JScript))
                    {
                        Publish(ICELevel.Error, 
                            "Found Evil " + customActionType.ToString() + " Custom Action " + customActionName,
                            "http://blogs.msdn.com/robmen/archive/2004/05/20/136530.aspx",
                            "CustomAction",
                            "Action",
                            customActionName ); 
                    }
                    else
                    {
                        Publish(ICELevel.Information, "Found Nice Custom Action: " + customActionName + " Type: " + customActionType.ToString());
                    }
                }
            }
        }
    }
}

January 22, 2009

IS 2009 Bug - Patch Optimization & Custom CAB Names Mutually Exclusive

I realize this is a very unique scenario, but I thought I would post it in case you find yourself in this scenario. The bug only applies if you use InstallShield 2009 to build a ‘Basic MSI’ installation and you use ALL of the build options specified below:
  • You specify custom CAB names (by editing the ISFeatureCabName column of the custom InstallShield Feature table).
  • You specify the “One .cab per Feature” option on the Custom Compression Settings dialog of the Release Wizard.
  • You sync file IDs with a previous build using the “Previous package” option on the Advanced Settings dialog of the Release Wizard.

If you do build under the scenario described above, then you should be aware that the options appear to be mutually exclusive and the custom CAB names you specified will NOT be generated correctly by InstallShield at build time.

Below is a description of the problem I reported to Acresso support yesterday (incident #SIOA-000140045):


I have a serious problem with the IsCmdBld.exe in InstallShield 2009 Premier that I need a fix for ASAP.

We are in the process of upgrading our build environment to use IS 2009 to build our primary application installation and are seeing different behavior during the build between the IsSABld.exe we used with previous versions of IS (both IS 12 Premier and IS 2008 Premier) and the behavior seen using IsCmdBld.exe in IS 2009 Premier.

Our primary application installation is a very complex and large MSI installation. Since we must control the names of the CAB files we generate at build time, we use the InstallShield Direct Editor to modify the Feature table in the InstallShield source project and specify a different CAB name for each defined feature (using the ISFeatureCabName field). Using the Release Wizard, we also set the Release Configuration to 'Custom' and select the "One .cab per Feature" option ("Custom Compression Settings" dialog of the Release Wizard). In addition, we specify the fully qualified path and name of a previous MSI package build (by setting the "Previous package" option on the "Advanced Settings" dialog of the Release Wizard. The only other configuration information that may be relevant to this issue is the fact that we have multiple merge modules in the project and each defined feature has one or more merge modules associated with it (no merge module is associated with more than one feature).

When we build the installation (with NO CHANGES other than upgrading the project to IS 2009 schema format) using the IsCmdBld.exe command line utility from IS 2009 the CAB files are not generated correctly. In other words, the files associated with feature A are not being placed into the CAB file specified in the ISFeatureCabName for feature A. However, if I remove the option to point the build to a previous package and then build the project then the CAB files are generated correctly (the files associated with feature A are being correctly placed into the CAB file specified in the ISFeatureCabName for feature A.

In other words, the options to specify the CAB file name for each feature (ISFeatureCabName column of the Feature table) and the Release Wizard option for Patch optimization ("Previous package" option) ARE MUTUALLY EXCLUSIVE IN IS 2009.

I have confirmed this behavior by building under the different scenarios described below:

  • Build A: IS 12 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path specified, and IsSABld.exe used to build the project.
  • Build B: IS 12 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path NOT specified, and IsSABld.exe used to build the project.
  • Build C: IS 2008 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path specified, and IsSABld.exe used to build the project.
  • Build D: IS 2008 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path NOT specified, and IsSABld.exe used to build the project.
  • Build E: IS 2009 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path specified, and IsCmdBld.exe used to build the project.
  • Build F: IS 2009 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path NOT specified, and IsCmdBld.exe used to build the project.

In all scenarios specified above EXCEPT "Build E", the CAB files are correctly generated during the build. In other words, in each of the scenarios EXCEPT "Build E", the files associated with feature A are correctly placed into the CAB file whose name is specified in the ISFeatureCabName column of the Feature table.It is absolutely critical that this be fixed or we cannot use IS 2009 without completely redesigning our MSI installation packaging.

January 16, 2009

Please, Just One More Miracle

I know it's been awhile since I posted an update. I've been incredibly swamped by life and my new work. I sit here this morning reading about United 1549 which went down in the Hudson river. Miraculously, no one perished.

I mention this because I'm praying for one more miracle. Cheryl had her quarterly CT scan on Monday and in a couple of hours we'll visit her oncologist to see if she remains no evidence of disease.

[Update]

The CT Scan looks perfect! Thank You God!!