From MSI to WiX, Part 23 - DLL Custom Actions - Logging and setting properties

Let's start with setting property value using MSI API MsiSetProperty.  This function takes three parameters:

  1. An installation handle, originally passed to custom action's function by Windows Installer.
  2. Name of the property to set or remove.
  3. New value for the property or NULL (or empty string) to remove property.

To get the installation handle we could cache it in some global variable, but WiX provides caching already in the form of WcaInitialize (to cache handle) and WcaGetInstallHandle (to get cached value) functions.

Here is how typical code to set property looks like:

LPWSTR szName = L"PROPNAME";

LPWSTR szValue = L"VALUE";

hr = HRESULT_FROM_WIN32(::MsiSetProperty(WcaGetInstallHandle(), szName, szValue));

ExitOnFailure(hr, "Failed to call PROPNAME");

Same code, but written using WiX API will look like this:

LPWSTR szName = L"PROPNAME";

LPWSTR szValue = L"VALUE";

hr = WcaSetProperty(szName, szValue);

ExitOnFailure(hr, "Failed to call PROPNAME");

Little bit less code to write, but WiX API also provides additional function WcaSetIntProperty, which takes second parameter as integer, so you don't have to do conversion of integer to string yourself.  This function we used in our sample to set the value of HWDOCKINFO property:

hr = WcaSetIntProperty(L"HWDOCKINFO", hwProfInfo.dwDockInfo);

ExitOnFailure(hr, "Failed to set HWDOCKINFO property value");

 

    Logging

To log informative message to the installation log file we need to call MsiProcessMessage function from Windows Installer API with second parameter set to INSTALLMESSAGE_INFO.  First parameter for this function is usual installation handle, which we already discussed previously.  Third parameter - is a handle to record, containing message text.  Let's see an example:

PMSIHANDLE hRecord = ::MsiCreateRecord(1);

if(NULL != hRecord)

{

er = ::MsiRecordSetString(hRecord, 0, TEXT("GetHardwareProfile completed successfully"));

if(ERROR_SUCCESS == er)

{

er = ::MsiProcessMessage(WcaGetInstallHandle(), INSTALLMESSAGE_INFO, hRecord);

}

}

The same can be done with just one line of code if we will be using WiX API:

WcaLog(LOGMSG_STANDARD, "GetHardwareProfile completed successfully");

WcaLog even supports formatting message string with parameters:

WcaLog(LOGMSG_STANDARD, "%s completed successfully", "GetHardwareProfile");

You can find more information on WcaLog in here.

WcaLog puts a limit on total length of resulting (after formatting is done) message string.  This limit is, as of now, 2048 characters.

There is one more specialized function - WcaLogError.  Instead of LOGLEVEL, it takes HRESULT as a first parameter.  It formats the error message just like WcaLog, but it writes into log file the following message:

Error 0x<HRESULT>: <MESSAGE>

In the next post we will continue discussion of available MSI and WiX API functions.