我试图从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。
感谢您提供的任何帮助!
答案 0 :(得分:1)
另一种简化方法是使用MsiEvaluateCondition function。
BOOL bUI = MsiEvaluateCondition(L"UILevel<3");
在C#中使用Microsoft.Deployment.WindowsIntaller(DTF)它是:
var uiLevel = session["UILevel"];
在C ++中有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;
}
答案 1 :(得分:1)
感谢@DanielGehriger,我们发现问题不在于代码,而在于自定义操作的调度问题。运行UILevel
自定义操作时,deferred
MSI属性只是不可用(我发现代码对于为firstsequence
安排的自定义操作正常工作)。我通过使用WiX明确地将其传递给自定义操作数据来解决此限制:
<CustomAction Id="CustomAction.SetProperty" Property="CustomActionCall"
Value="UILEVEL=[UILevel];" />
然后使用WcaIsPropertySet
和WcaGetProperty
在C ++中检查这一点。请注意,方括号之间的属性名称的字符大小写在这里。