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


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

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

После добавления это действие существующей сертификации, который называется 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:WindowsInstallerMSIBD82.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:WindowsInstallerMSIBD82.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:WindowsInstallerMSIBD82.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:WindowsInstallerMSIBD82.tmp 
Action ended 15:20:25: InstallFinalize. Return value 3.

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

3 2

3 ответа:

То же самое случилось и со мной. "Галец" уже указывал в нужном направлении, настраивая меня на нужный лад (нет репа на апвоте, извините).

Краткая версия:

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

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

  1. создайте CA, например "HavocAction", имеющий три экспортированные точки входа (т. е. помеченные атрибутом "CustomAction"), названные "HavocEntryPointa", "HavocEntryPointB", " HavocZappEntryPoint" (обратите внимание на точное написание). Методы могут просто возвращать " ActionResult.Успех".
  2. придумайте простые настройки, а) вызывая только "HavocEntryPointa", б) вызывая только "HavocEntryPointB"
  3. ==> Setup "a)" будет работать, Setup "b)" потерпит неудачу
  4. раскомментируйте атрибут CustomAction на "HavocZappEntryPoint", и поведение будет инвертировано, т. е.
  5. ==> Setup "a)" не сработает, Setup "b)" сработает

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

Когда вы сбрасываете завернутый ОКОЛОdll-файл с

Мусорный Контейнер / Экспорт 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" инвертирует эффект.

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

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

PS: Это http://wixtoolset.org/issues/4502 теперь.

Обновить

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

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

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

Вот что я сделал, чтобы исправить эту проблему: я написал программу на C++, которая загружает скомпилированное пользовательское действие и проверяет экспорт. Затем я написал модульный тест, который проверил все экспортные операции в пользовательском действии. Очевидно, что это не исправит проблему, но, по крайней мере, у вас будет сбой модульного теста и вы будете знать, что ваш установщик сломанный. Вот код 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);
            }
        }
    }
Надеюсь, это поможет кому-то в моей ситуации. Это был очень неприятный день, когда я пытался разобраться с этим.

Это на самом деле довольно странно, но после долгого поиска ответов и попыток много разных вещей я попытался изменить имя нового CA с SetApplicationAutoStart на ConfigureApplicationAutoStart, и это привело к SetAppPoolLoadUserProfileTrue, чтобы начать работать правильно снова