2

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

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

添加此操作后,名为 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 中提取 dotnet PE 以执行此操作的问题。二进制文件中的所有其他 CA 都可以正常工作,包括新的 CA。

4

3 回答 3

2

我遇到了和你描述的完全一样的症状。WiX 工具集似乎有问题。我的 WiX tolset 版本是 3.8,而且我还有一个自定义操作,它不会运行,并且更改它的名称解决了这个问题。SFX 编译器只是简单地编译损坏的 DLL,而没有任何问题的迹象。更糟糕的是,在我的情况下,这是一个应该在 Result="ignore" 的情况下在卸载时运行的函数,所以在我运行实际安装程序后,我什至没有任何直接的迹象表明存在问题。

我尝试尝试了解名称的确切问题,但没有找到任何令人满意的解释。有问题的函数在源代码中的哪个位置似乎并不重要,它按字母顺序是什么(例如:函数成功,它按字母顺序在它之前和之后)。将 DLL 加载到depends.exe 表明存在导出,但尝试运行dll32 却找不到该导出。更改其名称可以解决问题。此外,有时您可以添加另一个功能,失败的功能会成功,但您刚刚添加的功能会失败。

以下是我为解决此问题所做的工作:我编写了一个 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);
            }
        }
    }

希望这对我的情况有所帮助。试图确定这一点是非常令人沮丧的一天。

于 2014-08-04T15:00:48.467 回答
2

同样的事情发生在我身上。“galets”已经指向正确的方向,让我走上正轨(没有代表支持,抱歉)。

简洁版本:

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

长版:

  1. 构造一个CA,例如“HavocAction”,具有三个导出的入口点(即用“CustomAction”属性标记),命名为“HavocEntryPointa”、“HavocEntryPointB”、“HavocZappEntryPoint”(注意准确的拼写)。这些方法可能只返回“ActionResult.Success”。
  2. 提出简单的设置,a) 仅调用“HavocEntryPointa”,b) 仅调用“HavocEntryPointB”
  3. ==> 设置“a)”将起作用,设置“b)”将失败
  4. 取消注释“HavocZappEntryPoint”上的“CustomAction”属性,行为被反转,即
  5. ==> 设置“a)”将失败,设置“b)”将起作用

进一步的分析

当您转储包装的 CA.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 函数?)。当从 dll 加载方法时(条目“HavocEntryPointa”和“HavocEntryPointB”互换),条目应该被排序(按 ASCII)以便进行二进制搜索。

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

关于OP的备注

Kjartan首先使用了“SetApplicationAutoStart”和“SetAppPoolLoadUserProfileTrue”,由于排序错误,没有正确导出到CA.dll;大写字母“P”出现在小写字母“l”之前,但这已被 MakeSfxCA 互换。他的后一个选择“ConfigureApplicationAutoStart”和“SetAppPoolLoadUserProfileTrue”是按照 PE / COFF 规范排序的。

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

更新

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

于 2014-08-14T03:23:39.357 回答
1

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

于 2012-08-15T18:01:12.900 回答