Прервать установку, когда пользовательское действие возвращает ошибку - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть метод, который проверяет пароль в .dll, и он должен вернуть код ошибки при ошибке.Он имеет следующий прототип:

#define DllExport __declspec( dllexport )
extern "C" DllExport UINT TestPassword(MSIHANDLE hInstall);

Я ожидаю, что когда этот метод вернет код ошибки (например, ERROR_INSTALL_USEREXIT = 1602), весь процесс установки завершится (никакие другие пользовательские действия после этого не будут выполнены),но это не так.

Кроме того, в Wix у меня есть следующий фрагмент:

 <CustomAction Id='TestPassword' BinaryKey='TestPassword' DllEntry='TestPassword' Execute='immediate'
              Return='check'/>

<Binary Id='TestPassword' SourceFile='DummyDll.dll'/>

1 Ответ

0 голосов
/ 28 февраля 2019

ОБНОВЛЕНИЕ : некоторые полезные ссылки.


Предполагаемые причины:

Здесь перечислены некоторые предложения вверху.

  • 1) Неправильная конфигурация кода настраиваемого действия C ++, часто забывая создать CA.def файл для определения экспорта DLL.Я также всегда использую __stdcall (MSI - старая девочка).
  • 2) Неправильный путь к пользовательским действиям dll вРазметка WiX (недопустимая DLL в MSI).
  • 3) Забыл включить проверку кодов ошибок в разметке WiX (* .WXS), после чего центр сертификации не завершает настройку.В вашем случае это выглядит правильно (Return='check').
  • 4) Забыл вставить пользовательское действие в последовательности установки.
  • Естьеще немного, не могу думать о них в данный момент.Можно добавить позже ... На ум приходят проблемы с битностью (x86 / 64) ...
  • Файловые и временные зависимости - это классическая причина сбоя.
    • Старайтесь статически связывать все, что можете.
    • DLL-библиотеки развертывания должны быть минимальными зависимостями наверняка, так как они должны работать в любой системе, влюбой язык, в любом состоянии, в любой версии ОС и т. д. *
    • Один из немногих случаев, когда статическое связывание действительно рекомендуется и всегда правильный выбор.

Heads-Up : избегать лицензирования при настройке?Я бы порекомендовал вам поставить проверку лицензии в вашем приложении вместо ваших настроек.Вот некоторые соображения по этому вопросу: Установщик с онлайн-регистрацией для приложения Windows ( рекомендуется прочитать ).


Технические проблемы:

FileName.def : Я не эксперт по C ++, но у вас есть файл FileName.def в вашем проекте для объявления экспортированных функций дляDll?Если нет - добавьте один (шаги / процедура ниже).Убедитесь, что он в правильном формате (добавьте через Visual Studio, я думаю, что это UTF8 без спецификации).Скомпилируйте и проверьте с помощью Dependency Walker , если все операции экспорта верны:

MSI DLL

Проверка DLL файла MSI : Вы должны проверить скомпилированный MSI, чтобы убедиться, что в нем есть правильная DLL-библиотека с правильным доступным экспортом.Следовательно,убедитесь, что DLL безопасно перешла в двоичную таблицу MSI:

  1. Откройте ваш скомпилированный MSI с Orca ( или эквивалентным ).
  2. Двоичная таблица , дважды щелкните по столбцу Данные для своей записи DLL.
  3. Выберите " Записать двоичный файл в имя файла "и сохраните на рабочем столе (или в другом месте).
  4. Используйте Зависимость Walker (зависимость.exe), чтобы убедиться, что у вас есть действительная DLL, как показанона изображении выше. Общая проблема заключается в том, что вы вообще не видите экспорта (MyImmediateCA, MyTestFail, MyTestSuccess, etc...).
  5. Проверьте файл - и версии продукта , а также в свойствах файла.

Обработка ошибок : можно настроить настраиваемое действие для подавления ошибок.Ваша разметка выглядит правильно с набором «атрибут возврата»: (Return='check').Ваш фрагмент:

<CustomAction Id='TestPassword' BinaryKey='TestPassword' 
              DllEntry='TestPassword' Execute='immediate' Return='check'/>

Секвенирование : Также убедитесь, что с секвенированием все в порядке.В целом вам нужно указать на DLL двоичной таблицы, объявить пользовательское действие, а затем также вставить его в правильную последовательность.Макет WiX разметки:

<!--<Binary Id="CustomActions" SourceFile="$(var.TestDll.TargetPath)" />-->
<Binary Id="CustomActions" SourceFile="C:\TestDll.dll" />

<CustomAction Id="MyTestFail" BinaryKey="CustomActions" DllEntry="MyTestFail"/>
<CustomAction Id="MyTestSuccess" BinaryKey="CustomActions" DllEntry="MyTestSuccess"/>

<InstallExecuteSequence>
  <Custom Action="MyTestSuccess" After="CostFinalize" />
  <Custom Action="MyTestFail" After="MyTestSuccess" />
</InstallExecuteSequence>

C ++ DLL : И собственно сама C ++ DLL (вспомните файл *.def).Фрагмент в нижнем сегменте кода из Безопасность настраиваемых действий API MSI :

Предлагаемые действия для Visual Studio 2017 :

  1. Создание нового проекта VC + DLL - Dynamic-Link Library (DLL).
  2. Дамп кода ниже в основной файл *.cpp (я избегаю dllmain.cpp).
  3. Добавьте файл * .def!
    • Right Click Source Files => Add => New Item... => Code =>Module-Definition File (.def) => Любое имя должно делать ... (разрешен только один файл def)
    • Добавить имена функций экспорта:

Макет:

LIBRARY

EXPORTS
     MyTestFail
     MyTestSuccess
     MyImmediateCA

Закройте и снова откройте файл, чтобы проверить, есть ли какие-либо ошибки формата.Выберите исправление, если появится предупреждение. UTF8 без спецификации требуется, я думаю.

#include "stdafx.h"

#include <windows.h>
#include <Msiquery.h>
#pragma comment(lib, "msi.lib")

UINT __stdcall MyTestFail(MSIHANDLE hInstall)
{
    MessageBox(NULL, L"MyTestFail", L"MyTestFail", MB_OK);    
    return ERROR_INSTALL_FAILURE;
}

UINT __stdcall MyTestSuccess(MSIHANDLE hInstall)
{
    MessageBox(NULL, L"MyTestSuccess", L"MyTestSuccess", MB_OK);    
    return ERROR_SUCCESS;
}

// I will leave in the below snippet from the MSI API - section "Custom Action Security". Above two test methods will do though... 
UINT __stdcall MyImmediateCA(MSIHANDLE hInstall)
{
    MessageBox(NULL, L"Test", L"Test", MB_OK);

    // set up information for deferred custom action called MyDeferredCA
    const TCHAR szValue[] = TEXT("data");
    UINT uiStat = ERROR_INSTALL_FAILURE;
    if (ERROR_SUCCESS == MsiSetProperty(hInstall, TEXT("MyDeferredCA"), szValue))
    {
        uiStat = MsiDoAction(hInstall, TEXT("MyDeferredCA"));

        // clear CustomActionData property
        if (ERROR_SUCCESS != MsiSetProperty(hInstall, TEXT("MyDeferredCA"), TEXT("")))
            return ERROR_INSTALL_FAILURE;
    }

    return (uiStat == ERROR_SUCCESS) ? uiStat : ERROR_INSTALL_FAILURE;
}

Минимальные зависимости : чтобы минимизировать зависимости, вы должны устранить визуальныеC / C ++ Зависимости времени выполнения и любые зависимости MFC (не используйте MFC, если вы можете помочь ему по размеру файла и соображениям производительности).Если вы используете MFC, установите для него статическое связывание - также для ATL.И, наконец, время выполнения C / C ++ см. Здесь: Удаление зависимостей MSVCR в Visual Studio 2010? (есть лучшие ссылки, но все, что я смог найти, на это у меня есть время - просто хочу получить это втам так не забыто).

Multi-threaded /MT

...