向项目添加新的自定义操作可防止运行现有的自定义操作

时间:2012-08-15 17:59:08

标签: wix custom-action wix3.6

我有一个自定义操作项目,其中包含我公司创建的安装程序使用的各种CA,其中一些用于通过Microsoft.Web.Administration API操作IIs7。

我添加了一个名为SetApplicationAutoStart的新自定义操作,该类包含与II相关的CA.此自定义操作用于设置autoStart属性,该属性强制IIs预加载和启动WCF服务,以便初始响应时间更短。

添加此操作后,名为SetAppPoolLoadUserProfileTrue的现有CA停止工作。此CA强制将站点上的设置设置为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中为此操作从PE中提取dotnet PE的问题。二进制文件中的所有其他CA都正常工作,包括新的。

3 个答案:

答案 0 :(得分:2)

我经历了完全您描述的相同症状。 WiX工具集似乎存在问题。我的WiX tolset版本是3.8,我也有一个自定义操作,它不能运行,并且更改其名称解决了问题。 SFX编译器只是编译损坏的DLL而没有任何问题的迹象。更糟糕的是,在我的情况下,这是一个应该在卸载时运行的函数,结果="忽略",所以我甚至不能立即指出存在问题在我运行实际的安装程序之后。

我尝试了解该名称究竟是什么问题,并没有找到任何令人满意的解释。在源代码中,违规函数的位置似乎无关紧要,它是按字母顺序排列的(例如:函数在字母顺序之前和之后成功)。将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);
            }
        }
    }

希望这有助于我的情况。这是一个非常令人沮丧的一天,试图解决这个问题。

答案 1 :(得分:2)

同样的事发生在我身上。 "加莱"已经指向正确的方向,让我走上正轨(没有代表upvote,对不起)。

简短版本:

MakeSfxCA生成的本机dll不遵循导致观察到的行为的PE / COFF规范。

长版:

  1. 构建一个CA,例如" HavocAction",有三个导出的入口点(即标有" CustomAction"属性),命名为" HavocEntryPointa"," HavocEntryPointB",&# 34; HavocZappEntryPoint" (记住确切的拼写)。方法可能只返回" ActionResult.Success"。
  2. 提出简单的设置,a)只调用" HavocEntryPointa",b)调用" HavocEntryPointB"
  3. ==>设置" a)"将工作,设置" b)"将失败
  4. 取消注释" CustomAction"属性" HavocZappEntryPoint"并且行为被颠倒了,即
  5. ==>设置" a)"将失败,设置" b)"会工作
  6. 进一步分析

    使用

    转储包装的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",cf。Exported DLL functions not ordered lexically?)。这些条目应该被排序(通过ASCII),以便在从dll加载方法时进行二进制搜索(条目" HavocEntryPointa"和" HavocEntryPointB"互换)。

    我有根据的猜测是,当从dll加载代码时,二进制搜索失败,导致错误。由于二进制搜索的性质,删除" HavocZappEntryPoint"反转效果。

    关于OP的备注

    Kjartan首先使用" SetApplicationAutoStart"和#34; SetAppPoolLoadUserProfileTrue"由于订购错误而未正确导出到CA.dll;大写字母" P"来自小写字母" l"但这是由MakeSfxCA互换的。他的后者选择" ConfigureApplicationAutoStart"和#34; SetAppPoolLoadUserProfileTrue"订购符合PE / COFF规范。

    PS:现在是http://wixtoolset.org/issues/4502

    <强>更新

    PPS:从WiX 3.9 RC3版本开始,包含此问题的错误修复程序;一切都按预期工作。

答案 2 :(得分:1)

这实际上很奇怪但是经过很长一段时间搜索答案并尝试了很多不同的东西后,我尝试将新CA的名称从SetApplicationAutoStart更改为ConfigureApplicationAutoStart,这导致SetAppPoolLoadUserProfileTrue再次开始正常工作