Не удалось получить свойство MSI в UPGRADINGPRODUCTCODE, WIX_UPGRADE_DETECTED - PullRequest
0 голосов
/ 26 декабря 2018

Я хотел пропустить некоторые из моих пользовательских действий во время обновления, uninstallDriver, чтобы добиться этого, я попытался получить свойства WIX_UPGRADE_DETECTED и UPGRADINGPRODUCTCODE, но обаиз них не установлены.

Пример кода:

UninstallDriver(MSIHANDLE hInstall)  
{
   char szBuff[1024]; DWORD dwValue = 0;

   OutputDebugStringA("UninstallDriver");
   MsiGetPropertyA(hInstall, "UPGRADINGPRODUCTCODE", szBuff, &dwValue);
   OutputDebugStringA("UPGRADINGPRODUCTCODE");OutputDebugStringA(szBuff);

   MsiGetPropertyA(hInstall, "WIX_UPGRADE_DETECTED", szBuff, &dwValue);
   OutputDebugStringA("WIX_UPGRADE_DETECTED");OutputDebugStringA(szBuff);

   result = UninstallDriver();

   return result;
}

И мой customAction -

<Custom Action='UninstallMYDriverAction'
 After='InstallInitialize'>
        REMOVE~="ALL" OR REINSTALL</Custom>

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018

Игнорируя строки отладки, легче увидеть, что обработка буфера некорректна.Я бы также предложил вывести возвращаемые значения из MsiGetPropertyA() и значение в dwValue для подтверждения, но я думаю, что вот что происходит (комментарии относятся к dwValue):

char szBuff[1024]; DWORD dwValue = 0;
MsiGetPropertyA(hInstall, "UPGRADINGPRODUCTCODE", szBuff, &dwValue); // passes 0, updated to ?x?
MsiGetPropertyA(hInstall, "WIX_UPGRADE_DETECTED", szBuff, &dwValue); // passes ?x?, updated to ?y?

При запросе UPGRADINGPRODUCTCODE свойство с заявленной длиной буфера ноль, выборка никогда не будет успешной, поскольку она всегда должна принимать по крайней мере нулевой символ.Таким образом, это вернет ERROR_MORE_DATA и установит dwValue на длину, исключающую нулевой символ (?x?).

Затем он запросит значение WIX_UPGRADE_DETECTED с заявленной длиной буфера (?x?).Если новая длина (?y?) меньше старой длины (?x?), вы получите ее содержимое в своем буфере;в противном случае он также просто запросит длину этого нового свойства.

Поскольку WIX_UPGRADE_DETECTED содержит список из одного или нескольких идентификаторов GUID, а UPGRADINGPRODUCTCODE содержит только один, и этот код никогда не увеличивает dwValue на счетдля нуля, это возможно только успешно, если последний ?y? равен 0 (пусто) и ?x? не пусто.Но обратите внимание, что этот второй вызов передал непроверенное значение в качестве длины вашего буфера, этот шаблон является переполнением буфера, ожидающим выполнения.

Так что исправьте обработку вашего буфера.Шаблон, который мне нравится использовать (ниже), похож на тот, что описывает Стейн, но избегает второго вызова, если я знаю хороший размер по умолчанию для буфера.В вашем случае это звучит так, как будто вы довольны буфером из 1024 элементов, но подумайте, нужно ли вам обрабатывать более 1024 / len (GUID) кодов обновления.

(Полагаю, вы 'все хорошо. Но, по крайней мере, продумайте это. И хотя GUID являются ASCII, поэтому содержимое не имеет значения, пожалуйста, пожалуйста, соберите UNICODE в эти дни ...)

WCHAR szBuf[1024];
DWORD cchBuf = 1024; // or _countof(szBuf);
DWORD dwErr = MsiGetPropertyW(hInstall, L"UPGRADINGPRODUCTCODE", szBuf, &cchBuf);
if (dwErr != ERROR_MORE_DATA) {
    // exercise: increment cchBuf for null, adjust buffer, call MsiGetPropertyW again
}
if (dwErr != ERROR_SUCCESS) {
    // per https://docs.microsoft.com/en-us/windows/desktop/msi/custom-action-return-values
    return ERROR_INSTALL_FAILURE;
}

// reset buffer length for next call, in case second property is longer than first
cchBuf = 1024;
dwErr = MsiGetPropertyW(hInstall, L"WIX_UPGRADE_DETECTED", szBuf, &cchBuf);
// : : :
0 голосов
/ 26 декабря 2018

Условие настраиваемого действия : Вы должны быть в состоянии выполнить это настраиваемое действие сразу, не выполняя настраиваемое действие?Условия MSI печально известны тем, что их трудно понять правильно, поскольку существует множество режимов установки, с которыми приходится иметь дело: install, repair, self-repair, modify и minor upgrade patching, uninstall, major upgrade initiated uninstalls,и т.д ... Есть еще несколько.

В вашем случае может быть достаточно добавить к существующему условию:

AND (NOT UPGRADINGPRODUCTCODE)

Это сделает условие недействительным при обнаружении обновления.

Я бы на самом деле попытался: (REMOVE~="ALL") AND (NOT UPGRADINGPRODUCTCODE) (, как видно из этого ответа ).


Главный совет : Вы можете довольно эффективно отлаживать условия MSI с помощью подхода, описанного здесь: Как выполнить условное пользовательское действие при установкеи изменять только? (см. нижний раздел).Вы используете VBScript и несколько вызовов MSI API, чтобы определить, какие условия выполняются, а затем вы можете изменить последовательность для проверки условий в разное время.Они могут измениться.

Примечание : Это просто отладчик MSI для жалости к себе, но он работает.


Свойство Размер строки : Я не эксперт по C ++, но вот из MSI SDK : Вам нужно позвонить MsiGetProperty ссначала пустую строку, а затем добавьте 1 для нулевое окончание .Как обычно высокий "шум линии" с C ++.Много сантехники и формальностей для очень небольшого эффекта - но давайте просто разберемся с этим :-):

Пример ниже C ++ от MSI SDK :

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;

}

VBScript : для целей тестирования можно легко использовать VBScript (поэтомуВы можете определить, есть ли у вас проблемы с кодированием или нет):

MsgBox Session.Property("PROPERTYNAME")

Некоторые дополнительные ссылки (только для справки и для простого поиска, не требуется)Я думаю, что для вас):

...