0

ユーザーが「UIモードなし」で実行されているかどうかを判断するために、C++カスタムアクション内から「UILevel」MSIプロパティを取得しようとしていますが、あまり運がありません。呼び出している関数には、DLLにエクスポートした関数からMSIHANDLEが渡されます(これは「遅延」または「最初のシーケンス」アクションのいずれかです)。私が見ているのは、それ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 ++でそのようにチェックすることでこれを回避できると思いますが、ここでの問題も知りたいです。

WiX3.5.2519を搭載したWindows7でVisualStudio/ Visual C++2010を使用しています。

あなたが提供できるどんな援助にも感謝します!

4

2 に答える 2

1

これを簡単にする別の方法は、MsiEvaluateCondition関数を使用することです。

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

Microsoft.Deployment.WindowsIntaller(DTF)を使用するC#では、次のようになります。

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;
}
于 2012-10-26T19:56:48.033 に答える
1

@DanielGehrigerのおかげで、問題はコードにあるのではなく、カスタムアクションのスケジュールにあることがわかりました。カスタムアクションを実行しているときは、UILevelMSIプロパティを使用できませんdeferred(にスケジュールされているカスタムアクションに対してコードが正しく機能することがわかりましたfirstsequence)。WiXを使用してカスタムアクションデータに明示的に渡すことで、この制限を回避しました。

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

次に、C++でとを使用してこれをチェックしWcaIsPropertySetますWcaGetProperty。ここでは、角括弧で囲まれたプロパティ名の大文字と小文字が重要であることに注意してください。

于 2012-10-26T21:53:38.833 に答える