繁体   English   中英

如何从C ++自定义操作获取MSI'UILevel'属性

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

我试图从C ++自定义操作中获取'UILevel'MSI属性,以确定用户是否以'无UI模式'运行,但运气不佳。 我调用的函数是从我在我的DLL中导出的函数传递的MSIHANDLE(可以是'deferred'或'firstsequence'动作)。 我看到的是MsiGetPropertyW总是返回ERROR_MORE_DATA ,而且trueLength字段始终为0.这是我的代码:

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;
}

我相信我现在可以通过WiX传递'UILevel'属性并在C ++中检查它来解决这个问题,但我很好奇这里的问题是什么。

我在Windows 7上使用带有WiX 3.5.2519的Visual Studio / Visual C ++ 2010。

感谢您提供的任何帮助!

使这更简单的另一种方法是使用MsiEvaluateCondition函数

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

在C#中使用Microsoft.Deployment.WindowsIntaller(DTF)它是:

var uiLevel = session["UILevel"];

在C ++中, MsiGetProperty函数有一个示例:

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;
}

感谢@DanielGehriger,我们发现问题不在于代码,而在于自定义操作的调度问题。 运行deferred自定义操作时, UILevel MSI属性根本不可用 (我发现代码对于为firstsequence安排的自定义操作正常工作)。 我通过使用WiX明确地将其传递给自定义操作数据来解决此限制:

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

然后使用WcaIsPropertySetWcaGetProperty在C ++中检查这WcaGetProperty 请注意,方括号之间的属性名称的字符大小写在这里。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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