Monday, April 28, 2008

Wix, Custom Actions and MSIGetProperty

Have you ever tried accessing a property from a deferred custom action, in Wix, and wondered why you were not able to access the property value? If yes then you are at the right place to find your answer. Wix is a language used to create custom installer packages. I will probably write about using Wix in some other post. For this post I am assuming you are aware of how to use Wix and what custom actions are.

Recently I had a requirement where I had to pass a value, set by the Wix compiler, to one of my deferred custom actions. Usually custom actions can access properties (like TARGETDIR, INSTALLDIR, OriginalDatabase, etc.) directly by using MsiGetProperty() function. But things are different when it is a deferred custom action.

Since deferred custom actions are delayed to a later stage in the installation they will be executed outside of the normal installation session (this session may no longer exist during the execution of the deferred action), neither the original session handle nor any property data set during installation sequence will be available to the deferred custom action. The very limited amount of information the custom action can obtain consists of three properties CustomActionData, ProductCode and UserSID

The only way to pass the data to the deferred custom action (not sure if you can pass more than one) is to through using CustomActionData. But CustomActionData property is only available to deferred execution custom actions; immediate ones do not have access to it.

Let us assume your custom action name is MyCustomAction. To pass data to this custom action we need to declare another custom action which will set a property named “MyCustomAction” to the value you want to pass to the custom action.

CAUTION: The name of the property has to be same as the name of the deferred custom action.

Now schedule the above custom action just before our deferred custom action.

Now passed value can easily be accessed using the following code in the custom action

Syntax of MsiGetProperty:

UINT MsiGetProperty(

__in MSIHANDLE hInstall, // msi handle

__in LPCTSTR szName, //A null-terminated string that specifies the name of the property

__out LPTSTR szValueBuf, //Pointer to the buffer that receives the null terminated string containing the value of the property

__inout DWORD* pchValueBuf //Pointer to the variable that specifies the size

);

Code:

TCHAR* buffer = NULL;

DWORD bufferLen = 0;

//to get the size of the property

UINT uiStat = MsiGetProperty(msiHandle, L"CustomActionData", TEXT(""), &bufferLen);

if (ERROR_MORE_DATA == uiStat)

{

++ bufferLen;

buffer = new TCHAR[bufferLen];

if(NULL != buffer)

{

uiStat = MsiGetProperty(msiHandle, L"CustomActionData", buffer, &bufferLen);

}

}

//the value of the property is stored in buffer

//don’t forget to release the buffer after use

Adios..

Bondbhai