简体   繁体   中英

How to Obtain the MSI 'UILevel' Property From a C++ Custom Action

I am trying to get at the 'UILevel' MSI property from within a C++ custom action in order to determine whether or not the user is running in 'no UI mode', but am not having much luck. The function I am calling is passed the MSIHANDLE from a function which I export in my DLL (which may be either a 'deferred' or 'firstsequence' action). What I'm seeing is that MsiGetPropertyW is always returning ERROR_MORE_DATA and the trueLength field is always 0. Here is my code:

bool runningInNoUIMode(MSIHANDLE hInstall)
{
    unsigned long nBufLen = 64UL;
    WCHAR *wszValue = new WCHAR[nBufLen];

    DWORD trueLength = 0UL;
    UINT result = ::MsiGetPropertyW(hInstall, L"UILevel", L"", &trueLength); // Get the size of the property value first to see if there is enough storage allocated.
    if (ERROR_MORE_DATA == result || nBufLen <= trueLength)
    {
        if (NULL != wszValue)
        {
            delete [] wszValue;
        }

        // Allocate more memory for the property adding one for the null terminator.
        nBufLen = trueLength + 1;
        wszValue = new WCHAR[nBufLen];
    }

    if (NULL == wszValue)
    {
        WcaLog(LOGMSG_STANDARD, "Unable to determine the user interface level the MSI is being run with because we were unable to allocate storage for accessing the 'UILevel' property.");
        return false;
    }

    memset(wszValue, L'\0', nBufLen * sizeof(WCHAR));
    result = ::MsiGetPropertyW(hInstall, L"UILevel", wszValue, &trueLength);
    if (ERROR_SUCCESS != result)
    {
        WcaLog(LOGMSG_STANDARD, "Unable to determine the user interface level the MSI is being run with, error code = '%lu'.", result);
        delete [] wszValue;
        return false;
    }

    if (0 == wcscmp(L"2", wszValue)) // INSTALLUILEVEL_NONE == 2
    {
        delete [] wszValue;
        return true;
    }

    delete [] wszValue;
    return false;
}

I believe I can work around this for now by passing the 'UILevel' property through WiX and checking for it that way in the C++, but I am curious what the problem here is as well.

I'm using Visual Studio/Visual C++ 2010 on Windows 7 with WiX 3.5.2519.

Thanks for any assistance you can provide!

Another way of making this simpler is to use the MsiEvaluateCondition function .

BOOL bUI = MsiEvaluateCondition(L"UILevel<3");

in C# using Microsoft.Deployment.WindowsIntaller (DTF) it's:

var uiLevel = session["UILevel"];

In C++ there's a sample at MsiGetProperty function :

UINT __stdcall MyCustomAction(MSIHANDLE hInstall)
{
    TCHAR* szValueBuf = NULL;
    DWORD cchValueBuf = 0;
    UINT uiStat =  MsiGetProperty(hInstall, TEXT("MyProperty"), TEXT(""), &cchValueBuf);
    //cchValueBuf now contains the size of the property's string, without null termination
    if (ERROR_MORE_DATA == uiStat)
    {
        ++cchValueBuf; // add 1 for null termination
        szValueBuf = new TCHAR[cchValueBuf];
        if (szValueBuf)
        {
            uiStat = MsiGetProperty(hInstall, TEXT("MyProperty"), szValueBuf, &cchValueBuf);
        }
    }
    if (ERROR_SUCCESS != uiStat)
    {
        if (szValueBuf != NULL) 
           delete[] szValueBuf;
        return ERROR_INSTALL_FAILURE;
    }

    // custom action uses MyProperty
    // ...

    delete[] szValueBuf;

    return ERROR_SUCCESS;
}

Thanks to @DanielGehriger, we figured out that the problem isn't with the code, but with the scheduling for the custom action. The UILevel MSI property is simply not available when running a deferred custom action (I found that the code worked correctly for a custom action scheduled for firstsequence ). I have worked around this limitation by explicitly passing it on custom action data using WiX:

<CustomAction Id="CustomAction.SetProperty" Property="CustomActionCall"
  Value="UILEVEL=[UILevel];" />

and then checking for this in the C++ with WcaIsPropertySet and WcaGetProperty . Note that the character case of the property name between square brackets matters here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM