Thursday, February 28, 2013

WIX CustomAction deferred versus immediate and the nightmare of Windows platform dotNet dependency

When it comes to using WIX everybody would agree that C# language is on the paper the easiest language to use to write a Custom Action.
When things get more complicated is that if you want to create a WIX installer for both Windows 7 and Windows8 then you need to
build each custom action to target both dotNet Framework 3.5 and dotNetFramework 4.0 unfortunately you will have to create two solution because
unlike Visual Studio C++ project the dotNet dependency applies to the entire solution and not the configuration at least this is what I noticed
on Visual Studio 2010.

You have to be very careful on when to decide that your CustomAction will be immediate and when it will be deferred.
If you use your custom action to install driver, install Windows Services, setup MYSQL ODBC connection, configure IIS or delete file from protected folder
then you need to use a deferred custom action.

While both deferred and immediate custom actions can run in the context of the user initiating the installation, only deferred custom actions can run elevated using the system context.
Deferred custom actions can only be sequenced between the InstallInitialize and InstallFinalize actions in execute sequence tables. Immediate custom actions, on the other hand, can be sequenced
anywhere within any of the sequence tables. Deferred custom actions are not executed immediately. Instead they are scheduled to run later during the execution script. The execution script isn't processed until the InstallExecute, InstallExecuteAgain, or InstallFinalize action is run.
Deferred custom actions cannot access the installation database. In fact, deferred custom actions have very limited access to the installation session because an installation script can be executed
outside of the installation session that created it. Immediate custom actions have access to the installation database and can read and set installation properties, modify feature and component
states, and add temporary columns, rows, and tables among other things.
Deferred custom actions should be used when the custom action must make a change to the system or call another system service. Additionally, only deferred custom actions can run in an elevated
context. If your custom action requires elevated privileges in order to run, your custom action needs to be marked as deferred. Custom actions marked to run in the system context
(msidbCustomActionTypeInScript + msidbCustomActionTypeNoImpersonate) will only run in the system context if the installation itself is elevated.

So let's look at how to solve the dependencencie issue first.

1 I recommend passing an argument to your WIX build script to create an MSI based on the targeted OS




2 Dot Net Dependency

Make sure you know the build in version of dotNet on your targeted OS Win7 is 3.5 with fallback to 2.0
Windows 8 is 4.0 and deprecated support for 3.5




3 CustomAction deferred




Inside your C# CustomAction you can only access property passed to you inside the Value attribute of the CustomAction

session.Message(InstallMessage.Warning,
new Record(new string[]
{
string.Format("MYVARIABLE: {0}",
session.CustomActionData["MYVARIABLE"])
}));

Direct access to the property will fail such as string UILevel = session["UILevel"];
You cannot change MSI property inside the CustomAction but you can cheat and log a dummy property if you expect to parse the installation log during a silent install
to check the response of your custom action. Rolling back custom action is not easy when you messed up with some third party application setting
so in some cases you have to return return ActionResult.Success regardless of the outcome and rely on a result code

EG

string strLog = string.Format("Property(S): ResultCode = {0}", Convert.ToString(1));
session.Log(strLog);

4 CustomAction immediate

For install custom action if your custom action rely on files deployed within your MIS to some target folder then make sure you change Before="InstallFinalize" to
After="InstallFinalize">




In this case you can access any property through the session object EG string UILevel = session["UILevel"]; and you can set a new property before exiting from your CustomAction
session["ResultCode"] = 1


Hope this article will help you solve Windows 7 and Windows 8 Installer issue

No comments: