Добавление нового пользовательского действия в проект предотвращает выполнение существующего пользовательского действия.

У меня есть проект Custom Action, в котором установщики, созданные моей компанией, используют различные CA, некоторые из них используются для управления IIs7 через Microsoft.Web.Administration API.

Я добавил новое пользовательское действие под названием SetApplicationAutoStart, класс, содержащий CA, связанные с II. Это настраиваемое действие используется для установки атрибута autoStart, который заставляет II предварительно загружать и запускать службы WCF, чтобы сократить начальное время отклика.

После добавления этого действия существующий CA с именем SetAppPoolLoadUserProfileTrue перестал работать. Этот ЦС устанавливает для этого параметра на сайте значение true, даже если сайт по умолчанию на компьютере был изменен таким образом, что этот параметр имеет значение false, поэтому нам действительно нужно, чтобы он работал.

Файлы журнала содержат следующие строки в случае сбоя действия.

MSI (s) (A0:18) [15:02:43:639]: Executing op: ActionStart(Name=SetAppPoolLoadUserProfileTrue,,)
Action 15:02:43: SetAppPoolLoadUserProfileTrue. 
MSI (s) (A0:18) [15:02:43:641]: Executing op: CustomActionSchedule(Action=SetAppPoolLoadUserProfileTrue,ActionType=3073,Source=BinaryData,Target=SetAppPoolLoadUserProfileTrue,CustomActionData=AppPoolName=xxxxx)
MSI (s) (A0:18) [15:02:43:670]: Creating MSIHANDLE (377) of type 790536 for thread 50712
MSI (s) (A0:C8) [15:02:43:670]: Invoking remote custom action. DLL: C:\Windows\Installer\MSIBD82.tmp, Entrypoint: SetAppPoolLoadUserProfileTrue
CustomAction SetAppPoolLoadUserProfileTrue returned actual error code 1154 (note this may not be 100% accurate if translation happened inside sandbox)
MSI (s) (A0:C8) [15:02:43:673]: Closing MSIHANDLE (377) of type 790536 for thread 50712
MSI (s) (A0:18) [15:02:43:674]: Note: 1: 1723 2: SetAppPoolLoadUserProfileTrue 3: SetAppPoolLoadUserProfileTrue 4: C:\Windows\Installer\MSIBD82.tmp 
Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor.  Action SetAppPoolLoadUserProfileTrue, entry: SetAppPoolLoadUserProfileTrue, library: C:\Windows\Installer\MSIBD82.tmp 
MSI (s) (A0:18) [15:20:25:139]: Product: xxxxxxx -- Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor.  Action SetAppPoolLoadUserProfileTrue, entry: SetAppPoolLoadUserProfileTrue, library: C:\Windows\Installer\MSIBD82.tmp 
Action ended 15:20:25: InstallFinalize. Return value 3.

Это похоже на проблему извлечения PE dotnet из PE для этого действия. Все остальные ЦС в бинарнике работают нормально, включая новый.


person Kjartan Þór Kjartansson    schedule 15.08.2012    source источник
comment
Имейте в виду, что Visual Studio не выбрала мой проект CustomActions для сборки при создании моего решения (Диспетчер конфигурации). Это может привести к неожиданной устаревшей сборке Custom Action.   -  person Adam Caviness    schedule 04.05.2016


Ответы (3)


Со мной случилось то же самое. «Галеты» уже указывали в правильном направлении, направляя меня на правильный путь (нет представителя, чтобы проголосовать, извините).

Укороченная версия:

MakeSfxCA создает собственные библиотеки DLL, не соответствующие спецификации PE/COFF, что приводит к наблюдаемому поведению.

Длинная версия:

  1. Создайте ЦС, например. «HavocAction», имеющий три экспортированные точки входа (т. е. помеченные атрибутом «CustomAction»), названные «HavocEntryPointa», «HavocEntryPointB», «HavocZappEntryPoint» (обратите внимание на точное написание). Методы могут просто возвращать «ActionResult.Success».
  2. Придумайте простые настройки: а) вызов только «HavocEntryPointa», б) вызов только «HavocEntryPointB»
  3. ==> Настройка «а)» будет работать, настройка «б)» не удастся
  4. Раскомментируйте атрибут «CustomAction» в «HavocZappEntryPoint», и поведение будет инвертировано, т.е.
  5. ==> Установка "а)" не сработает, установка "б)" сработает

Дальнейший анализ

Когда вы сбрасываете обернутый файл CA.dll с помощью

dumpbin / Экспорт HavocAction.CA.dll

вы получаете что-то вроде (отрывок)

125   7C 00003A36 
126   7D 00003A4C HavocEntryPointa
127   7E 00003A62 HavocEntryPointB
128   7F 00003A78 HavocZappEntryPoint
129   80 000042FC zzzEmbeddedUIHandler
130   81 000043B8 zzzInitializeEmbeddedUI
131   82 0000467F zzzShutdownEmbeddedUI
132   83 00003AA5 zzzzInvokeManagedCustomActionOutOfProcW

Это неправильно (ищите "pecoff_v83.docx", ср. Экспортированные функции DLL не упорядочены лексически?). Записи должны быть отсортированы (по ASCII) для выполнения бинарного поиска при загрузке методов из dll (записи "HavocEntryPointa" и "HavocEntryPointB" меняются местами).

Мое обоснованное предположение заключается в том, что при загрузке кода из dll двоичный поиск завершается сбоем, что приводит к ошибке. Из-за характера бинарного поиска удаление «HavocZappEntryPoint» инвертирует эффект.

Замечание относительно ОП

Кьяртан сначала использовал «SetApplicationAutoStart» и «SetAppPoolLoadUserProfileTrue», которые неправильно экспортировались в CA.dll из-за неправильного порядка; заглавная буква «P» стоит перед строчной «l», но MakeSfxCA заменила ее. Его последний выбор «ConfigureApplicationAutoStart» и «SetAppPoolLoadUserProfileTrue» заказан в соответствии со спецификацией PE/COFF.

PS: сейчас это http://wixtoolset.org/issues/4502.

Обновить

PPS: Начиная с выпуска WiX 3.9 RC3, исправление этой проблемы включено; все работает как положено.

person Hille    schedule 14.08.2014
comment
Изменил это на правильный ответ, так как это позволит людям создавать правильные обходные пути. - person Kjartan Þór Kjartansson; 22.08.2014
comment
Ошибка существует в Wix 3.10 на Win10 :( - person Uriel Katz; 05.08.2016

Я испытал точно тот же симптом, который вы описываете. Кажется, проблема с набором инструментов WiX. Моя версия WiX tolset — 3.8, и у меня также было пользовательское действие, которое не запускалось, и изменение его имени решило проблему. Компилятор SFX просто компилирует сломанную DLL без каких-либо признаков проблемы. Что еще хуже, так это то, что в моем случае это была функция, которая должна была запускаться при удалении с Result="ignore", поэтому у меня даже не было бы немедленных указаний на наличие проблемы после запуска фактического установщика.

Я пытался поэкспериментировать, чтобы понять, в чем именно проблема с названием, и не нашел удовлетворительного объяснения. Кажется, не имеет значения, где в исходном коде находится функция-нарушитель, какова она в алфавитном порядке (например: функции, находящиеся до и после нее в алфавитном порядке, имеют успех). Загрузка DLL в файл depend.exe показывает, что экспорт есть, но попытка запустить rundll32 не находит этот экспорт. Изменение имени решает проблему. Кроме того, иногда вы можете добавить еще одну функцию, и неудачная функция будет успешной, но вместо нее произойдет сбой той, которую вы только что добавили.

Вот что я сделал, чтобы решить эту проблему: я написал программу на C++, которая загружает скомпилированное пользовательское действие и проверяет экспорт. Затем я написал модульный тест, который проверил все экспорты в пользовательском действии. Это, очевидно, не решит проблему, но, по крайней мере, вы столкнетесь с ошибкой модульного теста и узнаете, что ваш установщик не работает. Вот код С++, если вам интересно:

typedef int(__stdcall *CustomActionProc)(HANDLE);

int _tmain(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        _tprintf(_T("Parameters: DLL, EntryPoint\n"));
        return 1;
    }

    LPCTSTR dllName = argv[1];
    LPCTSTR entryPoint = argv[2];

    HMODULE hLib = LoadLibrary(dllName);
    if (hLib == NULL)
    {
        _tprintf(_T("Error loading %s\n"), dllName);
        return 1;
    }

    CustomActionProc procAddress = 
        (CustomActionProc) GetProcAddress(hLib, CStringA(entryPoint));
    if (procAddress == NULL)
    {
        _tprintf(_T("Error locating entrypoint %s\n"), entryPoint);
        return 1;
    }

    return 0;
}

И модульный тест:

    [TestMethod]
    public void TestCustomActionCanBeInvoked()
    {
        var asm1 = typeof(MyCustomActionsClass).Assembly;
        var methods = asm1.GetTypes().SelectMany(t =>
            t.GetMethods().Where(m => m.GetCustomAttributes(false)
                    .Where(a => a.GetType().Name == "CustomActionAttribute").Any()));

        var binFolder = (new FileInfo(this.GetType().Assembly.Location)).DirectoryName;
        var customActionsSfx = Path.Combine(binFolder, "MyCustomAction.CA.dll");
        var testMsiExport = Path.Combine(binFolder, "TestMsiExport.exe");

        foreach (var m in methods)
        {
            Trace.WriteLine("Method Name: " + m.Name);

            var p = Process.Start(new ProcessStartInfo()
            {
                FileName = testMsiExport,
                Arguments = "\"" + customActionsSfx + "\" " + m.Name,
                UseShellExecute = false,
                RedirectStandardOutput = true,
            });

            p.OutputDataReceived += (s, d) => Trace.WriteLine(d.Data);
            p.BeginOutputReadLine();
            p.WaitForExit();

            if (p.ExitCode != 0)
            {
                Assert.Fail("Bad Sfx export detected! Export name: " + m.Name);
            }
        }
    }

Надеюсь, это поможет кому-то в моей ситуации. Это был очень разочаровывающий день, когда я пытался прибить это.

person galets    schedule 04.08.2014

На самом деле это довольно странно, но после долгого поиска ответов и перепробования множества разных вещей я попытался изменить имя нового ЦС с SetApplicationAutoStart на ConfigureApplicationAutoStart, и это привело к тому, что SetAppPoolLoadUserProfileTrue снова начал работать правильно.

person Kjartan Þór Kjartansson    schedule 15.08.2012
comment
Я также видел, что определенный .DLL нарушает функциональность ЦС, и простое переименование этого файла .DLL запускает его и запускает. Очень странно. - person Morten Frederiksen; 04.08.2014