Monthly Archives: April 2007

Austin Code Camp 2007

It’s hard to believe but Code Camp 2007 is just around the corner. If you live in the Austin area I hope you’ll be attending. Drop me an email and we can do drinks and talk setup afterwords. It will be Cinco de Mayo afer all.

Personally I plan on attending following these seminars:

Effective Database Change Management
Fundamentals of modern programming
Good Test, Better Code – From Unit Testing to Behavior-Driven Design
How To Work As a Team

Life After Windows Installer: Install.NET?

I’ve recently been very upset with the attitude from Redmond ( Ala we will write the patterns thank you very much…. custom actions are evil and we aren’t going to help you roll your own patterns despite the fact that we are sitting around doing nothing to standardize these patterns for you. I’m sorry, but there are crucial stories missing from Windows Installer and I don’t see them doing anything about it to update the technology.

No NGEN pattern
Broken GAC MSIL patterns ( commit race problems with trying to start services or invoke webservices with GAC dependencies )
No native XML patterns
No IIS patterns
No managed framework classes
No P/Invoke wrappers
COM interfaces that don’t properly generate primary interop assemblies
No native support for managed code custom actions
No support for invoking webservices
No database support
Poor INI AppSearch support
Lack of Account Management capabilities
Very poor ACL support ( LockPermissions is broken )
No driver installation support
Very little native support for package serialization stories
Aging UI story
Very little support in GPO for setup.exe driven installs ( becoming more and more important as installs have to serialize prerequistes, have external UI handlers and generally perform .NET configuration actions outside of MSI because Windows Installer just can’t hack it.)

The list goes on and on…..

Now I generally like MSI, after all I do use it every day. However, C++/data driven abstraction is how we were designing systems 10+ years ago… The world has moved on to better designs. MSI does many things right, but there are also many things that it doesn’t even try to do. Worse, they seem to think the solution is to tell us not to try to do it also.

Although I’ve been using Windows Installer for years, I’m starting to wonder what’s next and how long I’ll be using this aging SDK.

MSVCR71.DLL TIDBIT

Recently I was involved in a .NET 1.1 to .NET 2.0 migration. This migration was needed for us to switch over to TFS. Things went pretty smoothly but I’ve noticed an issue appear twice that I thought I’d share.

Some of our thirdparty assemblies ( which we don’t have source to and can’t recompile ) were written in VS2003 have have dependencies on MSVCR71.DLL. When you migrate over to .NET 2.0 your application will break.

The reason is the .NET 1.1 Framework ships MSVCR71.DLL in the [WindowsFolder]Microsoft.NETFrameworkv1.1.4322 folder and .NET 2.0 does not. After doing a lot of searching, it almost seems like a mistake that the .NET 1.1 framework ever shipped this file in the first place.

The problem comes when you’ve not identified this dependency and you switch over to .NET 2.0. Now that this file is not available at runtime you’ll have a crash. A quick profiling with Filemon reveals the problem right away. At this point you add msvcr71.dll prereq package and/or private assembly to your install and your back in business.

No Managed Code Custom Actions For You!

Rob Mensching just posted a blog giving insite into why the Windows Instalelr team doesn’t support managed code custom actions. It’s a really good read to get a view of their inside thinking, but I have to admit I completly disagree with them. Microsoft ( or Macrovision for that matter ) doesn’t write my pay checks but I’m still going to give some free advice here….

Regarding the strategic direction, I completely agree with that built-in Windows Installer stories should be updated to eliminate the need for custom actions.

Unfortunately I’ve lost confidence that the Windows Installer team will get this job done. The last generally available release of MSI isn’t available down-level and only adds stories related to Vista UAC/RM functionality. Cool stuff, but not the additional standard action patterns that many people have been begging for over the last several years. The release before that seemed to focus mainly on patching. Even if the Windows Installer team was to pull a rabbit out of the hat and support these stories, I doubt they would port it down-level to a 3.x branch.

Please, tell me I’m wrong with that assessment. Please tell me that Bill G is going to throw so money at that team and we are going to get the framework improvements we have all been begging for.

Until that day comes, Custom Actions aren’t only tactical; they are strategic because there is no other viable solution. You raise some interesting points about AppDomains and the CLR and yet I’ve seen InstallShield address these issues with their CoCreateObjectDotNet() pattern. I’ve also done some work on my own with .NET 2.0 IPC remoting and I’ve found it to be a very reliable way of hosting custom actions out of process and yet still giving them the ability to communicate with MSI.

For the rest of Microsoft, managed code is clearly marketed as the future of software development. Windows Installer should adopt this strategic initiative and simply overcome the technical hurdles. This way we can have really good custom action patterns to play with until the day comes that MSI natively supports the patterns that we are writing custom actions for. Then we can gladly dump our CA’s and refactor using the built-in standard actions.

Googling for Windows Installer: New Twist

A thread over on InstallShield Community recently revealed that InstallShield 12 recently started setting the SummaryInformation stream Last Modified property to “DavidHacker”. DavidH then explained that a file used by InstallShield to perform the build was last modified by him and that this behavior would be addressed in a future release. Ok, that’s funny and somewhat embarrassing. I was going to post this blog just to give David a gentle poke but then something else became quite a bit more interesting.

It all started in fun when I decided to Google for “davidhacker msi” and I got 137 hits that were basically all MSI downloads. But then I made a wrong turn at Albuquerque turn when I started wondering just how many MSIs I could find. A quick examination of a blank MSI database created in ORCA made me try this search:

“S u m m a r y I n f o r m a t i o n” Installation Database root entry Install MSI { }

Wow, 48,500 hits!

Then it got interesting. I decided to add filter the query with additional words like:

InstallShield – 10,100 hits
Candle/Light – 12,200 hits
WISE – 71 hits
InstallAware – 1 hit

Now I have to realize that I was quite a bit surprised that WiX had more hits then InstallShield until I took into consideration that large corporate applications are likely to have the budget to use installshield and small projects are not likely to have the funding and will turn to open source/low cost solutions. At the same time, these large company apps are not nearly as likely as the small company apps to be available for download on the web. But come WISE only had 71 hits?? And of course our friends at InstallAware…. well ’nuff said.

Then I realized that I had a very powerful tool in my hands. I could download thousands of MSIs to use for data mining in determining industry trends. The first trend I decided to look at was the `Dialogs are optional in WiX trend`. I wondered if perhaps I was too hard on WiX the other day. To decide I downloaded the first 10 hits that Google returned:

images.windowsmarketplace.com/img/EDT/tools/UpgradeOptionsTool.msi
gmamaladze.googlepages.com/OutlookTasks.msi
www.eep.ac.uk/content/EEPSearchDeskBar.msi
software.jessies.org/downloads/windows/scm.msi
software.jessies.org/downloads/windows/terminator.msi
desktop.google.de/url?q=http%3A%2Fplugins%2Fgooglevideo.msi
desktop.google.fr/url?q=http%3A%2Fplugins%2Fhoroscope.msi
www.whitworth.org/downloads/SQLQueryGrid_1_000/SqlQueryGrid_1_000.msi
pluginplace.googlepages.com/gdSkype.msi
blogs.msdn.com/heaths/attachment/1472048.ashx

Of note the package sizes were:
MIN: 48KB
MAX: 2431KB
MEDIAN: 130KB
AVERAGE: 602KB

Of the 10 packages, not one single package ( not even the one that happened to be from Heaths MSDN blog ) had a dialog table. 100% of the packages lacked a UI experience for the user.

Now I didn’t make this up. You can use my search query, do your own 10 downloads and look at the MSIs in ORCA. But I do have a good explanation for why this is happening.

This page is the number one Google hit for the term `WiX sample`. On that page is a simple definition of the wix product, package, media, directory, component, and file elements followed by a call to candle and msiexec.

So thousands of developers who don’t know basic setup best practices who think setup is `simple` and setup is `xcopy` are basically told that they are correct.

Another interesting pattern I see is when I do stumble across an MSI created by WiX that has dialogs, it is quite obvious that the dialogs were STOLEN from an InstallShield project as you’ll see ControlConditions that use variables like _IsSetupTypeMin. I’ve seen this mentioned in WiX mailing lists but I never realized just the extent that people were doing this.

InstallShield 12 SP2 Released

It appears that Macrovision released IS12 SP2 for English and Japanese customers today. It should be noted ( as mentioned in the IS KB Article ) that a couple of the fixes resolve issues that were introduced in IS12 SP1. Personally I had not noticed these bugs since I’m in a 100% .NET environment these days ( Yippie, No COM ) and we don’t do database changes in our installers.

A list of resolved issues can be found here. There is also a link to where to download on that page.

Are Dialogs Optional Now??

I’ve recently been picking up various utilities to integrate with Team Foundation Server when I downloaded TfsDeployerSetup.msi.

I dropped the package in my COTS_ARCHIVE area and went to my integration machine to install the package. After executing the double click pattern the MSI initialization dialog appeared and then it exited. The product was installed. Oh my, good thing this is my test machine and it’s a simple package!

Now unfortunatly this is not the first time I’ve seen setup developers create a UI-less installer. In fact, I’ve seen it so many times that I didn’t really need to examine the MSI to know what toolset it was written in. Sure enough, there it was:

Windows Installer XML v3.0.1821.0 (candle/light)

Now I know WiX is all about not letting setup developers author `Bad` MSI’s and I suppose if you only go by one persons definition of bad, they have succeeded. I’m going to go old school for a moment… before Windows Installer there was Bullet Proof Installs. One of the patterns that I’ve ALWAYS believed in was the User Interview and Confirmation pattern ( aka the Next, Next, Install, Finished pattern).

Every, I repeat EVERY stand alone installer should have a UI Sequence that greets the user, gets all needed information, checks for failure conditions and prompts the user one final point of no return before making any changes to the machine.

But it seems that because WiX is too primitive of a toolset to possibly assist the developer in authoring a decent UI experience then UI must simply not be important these days. The result is many converted WiX developers seem to think it’s enough to throw together a few xml elements and build it. After all…. Setup is easy, right?

Now I’m sure TFSDeployer will probably be a really cool tool, but if your going to treat setup like a UI-less Xcopy, I’m not sure why you’d even bother with WiX/MSI. I personally don’t think a properly behaving install just automatically installs it self without any confirmation simply by clicking the msi.

TFS Build automation with VS2005 and InstallShield

I’ve just written a 3 part blog series dedicated to Visual Studio Team Foundation Server. This series outlines an incremental build story using TFS and InstallShield that makes MSI Minor Upgrades possible.

Ever since I decided to relaunch Hard Core Setup Engineering as DeploymentEngineering.com I’ve been meaning to post some blogs on the build automation side of the house. Build Automation is important because without some important patterns working upstream of the installer, MSI will never have a chance to do all of it’s costing magic that it was designed to do.

TFS Build Automation Part 1 – Introduction

TFS Build Automation Part 2 – Incremental Builds

TFS Build Automation Part 3 – InstallShield Build

TFS Build Automation Part 3 – InstallShield Build

Remember that TeamBuildTypes are VS2005 Solution centric. Fortunatly InstallShield comes with VS2005 and MSBuild integration right out of the box. When you add an InstallShield ( .ISM ) project to a VS2005 solution it automatically wires up a .ISPROJ file and some source control binding files.

The purpose of the .ISPROJ file is to teach the solution how to process the project using MSBuild. Using stanard VS2005 patterns such as Configuration Manager, TeamBuild simply builds the project completly unaware of the fact that it’s using InstallShield to build one of the projects inside the solution.

In our previous article I mentioned the `LATEST` pattern. Since the binaries needed to be consumed into the Windows Installer database are in a seperate solution, we need to bring them into scope. We do that using MSBuild ItemCollections and CopyTasks like this:

&ltItemGroup>
&ltMySourceFiles Include=”$(LATEST)***.*” />
&lt/ItemGroup>

&ltTarget Name=”CopyFiles”>
&ltCopy SourceFiles=”@(MySourceFiles)” DestinationFiles=”@(MySourceFiles->’$(SolutionRoot)ProgramFilesFolderMyCompanyNameMyProductName\%(RecursiveDir)%(Filename)%(Extension)’)”/>
&lt/Target>

So now the WorkspaceMappings.xml brings the InstallShield files into scope and this CopyFiles tasks gets us our binaries from the previous build output. The result is ( assuming proper Windows Installer design of the InstallShield Wizard ) is 100% ready to perform a minor upgrade of just those component keyfiles that were rebuilt and branded with a newer version number.

Obviously I’ve not provided an entire sample solution showing all of the integration points. Hopefully I’ve not overlooked any so feel free to leave a comment if your getting stuck wiring up your new TFS based incremental, versioned build automation.

TFS Build Automation Part 2 – Incremental Builds

Once you have your VS2005 solutions building, it’s time to learn how to do an incremental build. Modify your TFSBuild.proj and insert these properties into your PropertyGroup:

&ltforceget>false&lt/forceget>
&ltskipinitializeworkspace>true&lt/skipinitializeworkspace>
&ltskipclean>true&lt/skipclean>

This tells TFS to not reset your build directory and to only rebuild projects that need to be rebuilt. Personally incremental builds `scare` me, but Neil Enns ( MSFT program manager for Visual Studio ) personally assures me

“Incremental builds using MSBuild are 100% reliable for managed projects.”

There is always the possibility that an incremental build would success when a full build would fail ( perhaps a deprecated component that doesn’t go missing until you initialize the workspace ) so we will perform a redundant full build as a sanity check but discard the bits for deployment.

Now that we have incremental builds working, it sure would be nice to properly version them so Windows Installer costing patterns will work effeciently. Here is where Neil Enns comes to the rescue again. Neil wrote the AssemblyInfoTask community task. This task does a bunch of things, but one of the things it does well is to update the AssemblyInfo.cs files of only the projects that are out of date, or reference an out of date project. This means that during an incremental build, only the projects that get compiled will get versioned. Now isn’t that exactly the sort of pattern that MSI costing needs?

To take advantage of this, we download the task and install it. Then we have to add a few lines to each of the projects in our solution to `subscribe` them to the pattern.

&ltImport Project=”$(MSBuildExtensionsPath)MicrosoftAssemblyInfoTaskMicrosoft.VersionNumber.Targets” Condition=”‘$(BuildLabBuild)’==’true'”/>
&ltPropertyGroup>
&ltAssemblyMajorVersion>$(Major)&lt/AssemblyMajorVersion>
&ltAssemblyMinorVersion>$(Minor)&lt/AssemblyMinorVersion>
&ltAssemblyBuildNumber>$(Build)&lt/AssemblyBuildNumber>
&ltAssemblyRevision>$(Revision)&lt/AssemblyRevision>
&ltAssemblyBuildNumberType>NoIncrement&lt/AssemblyBuildNumberType>
&ltAssemblyBuildNumberFormat>DirectSet&lt/AssemblyBuildNumberFormat>
&ltAssemblyRevisionType>NoIncrement&lt/AssemblyRevisionType>
&ltAssemblyRevisionFormat>DirectSet&lt/AssemblyRevisionFormat>
&ltAssemblyFileMajorVersion>$(Major)&lt/AssemblyFileMajorVersion>
&ltAssemblyFileMinorVersion>$(Minor)&lt/AssemblyFileMinorVersion>
&ltAssemblyFileBuildNumber>$(Build)&lt/AssemblyFileBuildNumber>
&ltAssemblyFileRevision>$(Revision)&lt/AssemblyFileRevision>
&ltAssemblyFileBuildNumberType>NoIncrement&lt/AssemblyFileBuildNumberType>
&ltAssemblyFileBuildNumberFormat>DirectSet&lt/AssemblyFileBuildNumberFormat>
&ltAssemblyFileRevisionType>NoIncrement&lt/AssemblyFileRevisionType>
&ltAssemblyFileRevisionFormat>DirectSet&lt/AssemblyFileRevisionFormat>
&lt/PropertyGroup>

By now you’ll note that TFS `drops` the build ( stage the build to an archive location ) in a directory structure with it’s build name. I like the `latest` pattern where each build drops the bits in a folder called LATEST so that a downstream build can consume it. In our TFSBuild.proj we’ll do something like this:

&ltTarget Name=”AfterDropBuild”>
&ltCreateItem Include=”$(BinariesRoot)***.*” >
&ltOutput TaskParameter=”Include” ItemName=”AllLatestFiles”/>
&lt/CreateItem>
&ltRemoveDir Directories=”$(DropLocation)LATEST” />
&ltCopy SourceFiles=”@(AllLatestFiles)” DestinationFiles=”@(AllLatestFiles->’$(DropLocation)LATEST\%(RecursiveDir)%(Filename)%(Extension)’)”/>
&lt/Target>

Now when we drop the build we’ll see the binaries get copied to a build specific folder, and a latest folder. It’s time to move on to the InstallShield portion that will be in Part 3 of this article.