Wednesday, February 13, 2008

Automated Install Testing

Audience: Install Developers, Quality Assurance, Beginner to Advanced, Windows Installer (MSI)

I think everyone will agree, once your installation package is built it is a good idea to test it.

Testing installs of any size can be turn out to be tedious and time consuming. There can be many reasons for this, to list a few;
  • The install responds differently on various operating systems (like Vista and XP)
  • The install needs to support administrative images
  • The application supports run from source installations
  • There are different code paths taken depending on what is already installed on the system
  • The installer upgrades one or several previous versions
  • ... The list can go on and on depending on your specific requirements ...

One way is black box testing. Typically this involves nothing more than making a grid of the various scenarios, run them and see what happens. The more requirements the installation must fulfill, the larger the grid will be. This works however, it can be difficult catch every defect and if you are performing each install manually it can eat up a lot of time, which isn’t very cost effective. Most companies leave this strictly up to their quality assurance team, which in turn eats into application testing time.

If you want to save some money, impress your boss and QA team, think about white box testing. The nice thing about white box testing, is scripts can be written that fit into nightly build process which can help uncover known issues. You don’t really have to do anything more than look at some log files and fix the issues... besides write the tests.

If done properly you can uncover defects without even running the installation. These defects can then be fixed before the install even makes it to the QA team, in turn they spend more time testing the application, instead of the install. It’s win, win in my book.

The next few articles will share some handy scripts that I have found useful.

MSI Validation

Thursday, February 7, 2008

Windows Installer Dll - Part 3

Audience: Install Developers, Beginner, Windows Installer (MSI) Knowledge

This is the final part of a three part series that demonstrates how to use C++ in a Windows Installer Custom Action.

Once your custom action is ready to go, it is usually a good idea to debug it. The two best methods I’ve seen are:
  1. Stepping thought the code
  2. Writing to the log file

1. Step through the code

Visual Studio makes it easy, there is only a few steps to the process.

A) - Add a message box to the debug build of your DLL

Nothing new here...

UINT __stdcall MyFunction(MSIHANDLE hMsi)
{
#if _DEBUG
     AfxMessageBox(_T("MyFunction() -> Debug"));
#endif

     int x = 0;

     //complete custom tasks ...

     return ERROR_SUCCESS;
}

B) - Build your debug DLL and insert it into your .msi file

Use a program like orca to insert your debug DLL into the MSI file’s appropriate Binary table record.


Orca is a utility that will allow you to modify MSI packages. It comes with Microsoft’s Windows Installer SDK. If you have the SDK installed, Orac’s install can be found in the SDK’s bin folder. (usually – C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin)

C) - Run the install and attach to process

When the install executes your custom action, the debug message box pops up. With the project open in Visual Studio, use the Debug Menu and select Attach to Process. Find the process who’s title matches the message box’s title, and Attach to it.

Debug->Attach to Process

D) - Set a breakpoint, dismiss the message box

Set a breakpoint in your code just after the message box. Once the message box is dismissed VS will break into the debugger. From here you will have full access to the usual debug windows, and tools.

 

2 - Writing to the log file

MsiProcessMessage() can be used to write data to the log file. It is always a good idea to write important information about your action to the log file. If the install fails, you only need to collect the log file to tell what is going on. The following code writes data to the log file.

UINT __stdcall MyFunction(MSIHANDLE hMsi)
{
#if _DEBUG
     AfxMessageBox(_T("MyFunction() -> Debug"));
#endif

     WriteToLog(hMsi, L"MyFunction - doing something...");

     return ERROR_SUCCESS;
}

void WriteToLog(MSIHANDLE hMsi, LPCTSTR szMsg)
{
     PMSIHANDLE hRec = MsiCreateRecord(1);
     MsiRecordSetString(hRec, 1, szMsg);
     MsiProcessMessage(hMSI, INSTALLMESSAGE_INFO, hRec);
}

 

There it is... This concludes the series on how to use C++ in a Windows Installer custom action. Of course, the code here hasn’t really done anything. The intent is to demonstrate how to hook up a DLL. Most, if not all, the samples given at this blog will be in C++ so this seemed like a logical place to start.

 

Monday, February 4, 2008

Windows Installer Dll - Part 2

Audience: Install Developers, Beginner, Windows Installer (MSI) Knowledge

This is Part 2 of a three part series that demonstrates how to use C++ in a Windows Installer Custom Action.

Once your function is written and the DLL is created, you need to call it through a custom action. There are 2 ways to call a Windows Installer DLL.
  1. Custom Action Type 1 (store the DLL in the MSI file’s Binary table)
  2. Custom Action Type 17 (install the DLL with the product)

Hooking up the DLL in your setup project is easy. No matter what install authoring software you are using (InstallShield, Vise, Wise, Advanced Installer) – there will be some sort of wizard that guides you through the process.

I don’t think there is any value in me putting up screen shots, or demonstrating how these wizards work. Instead, lets look at some tips that will help you produce easy to maintain and 'readable' setup projects.


1 - Use Comments

This one gets missed a lot. Especially, when there is only one install developer that works on the project.

Some authoring software (InstallShield) has a comment field for the custom actions. I have found it is nice to see the comment used to tell why the custom action is needed. The function definition in you DLL’s source code should also have a quick description that describes the purpose of the function. Nothing to fancy, just enough that people can tell what’s going on.

// Example:
// checks to see if [INSTALLDIR] is too long
UINT __stdcall CA_EvaluateInstallPath(MSIHANDLE hMsi)
{
     /* ... code does something ... */

     return ERROR_SUCCESS;
}



2 - Use a Naming Convention for your Custom Actions

A) Use appropriate names for your custom actions and functions. -- You and other developers may need to maintain the code at a later date, your names should typically reflect something about what the custom action is responsible for.

Matching your Action name (custom action name) with the Target (exported function in the DLL) can be a big help if there are many functions in the same DLL.

B) Explicitly name important the Binary table entries. -- Most install authoring software will just pick a name like ‘NewBinary0' – if you take the time to rename it to something that reflects the actual source then your project will be easier to maintain thought it’s life cycle. There is no need to rename them all, just the ones that you many want to keep track off. The point here is it is better to see something like My.dll in the binary table, instead of NewBinary88.




3 - Custom Action Type 1 is easier than Custom Action Type 17

If you can get away with it, always choose Type 1 (DLL stored in the binary table) over, Type 17. It is just easier. You can use Type 1, and call the custom action anytime during the setup.

However, Type 17 can only be executed after InstallFiles and you need to use a condition on your action so that it will only run if the component has been installed.


4 - Any Action that Modifies the System Needs to be Deferred in System Context

If your action needs to modify the system, then it should be executed in the system context. This will ensure that the action will have the required permissions on the computer.

Secondly, if your action modifies the system, consider writing a rollback action as well. If the install fails after the system modification has been preformed, then the change should be undone when the install rolls back.



That’s it. The above tips will help ensure your setup project readable, easy to maintain and hopefully prevent a bug or two.

Next will move on to some debugging techniques for C++ custom actions.