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

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

本文关键字:MSI 属性 UILevel 获取 操作 C++ 自定义 可视化      更新时间:2023-10-16

我正在尝试从C 自定义操作中获取'Uilevel'MSI属性有很多运气。我正在调用的函数通过我在DLL中导出的函数传递(可能是"延期"或"首先"操作)。我看到的是MsiGetPropertyW总是返回ERROR_MORE_DATAtrueLength字段始终为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'', 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上的Visual Studio/Visual C 2010,Wix 3.5.2519。

感谢您提供的任何帮助!

使此更简单的另一种方法是使用MSIEVALUATECONTICE函数。

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 中检查一下。请注意,方括号之间的属性名称的字符很重要。