我有一个自定义操作项目,该项目包含我公司创建的安装程序使用的各种CA,其中一些用于通过Microsoft.Web.Administration API操作IIs7。
我添加了一个名为 SetApplicationAutoStart 的新自定义操作,该类包含与 II 相关的 CA。此自定义操作用于设置 autoStart 属性,该属性强制 II 预加载和启动 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: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 都能正常工作,包括新的 CA。
同样的事情也发生在我身上。"加莱茨"已经指向正确的方向,让我走上正轨(没有代表赞成,对不起)。
简短版本:
MakeSfxCA生成不遵循PE/COFF规范的本机dll,导致观察到的行为。
长版本:
- 构造一个CA,例如"HavocAction",具有三个导出的入口点(即标有"CustomAction"属性),名为"HavocEntryPointa","HavocEntryPointB","HavocZappEntryPoint"(注意确切的拼写)。这些方法可能只返回"ActionResult.Success"。
- 想出简单的设置,a)只调用"HavocEntryPointa",b)只调用"HavocEntryPointB"
- ==> 安装程序"a)"将起作用,安装程序"b)"将失败
- 取消注释"HavocZappEntryPoint"上的"CustomAction"属性,行为被反转,即
- ==> 安装程序"a)"将失败,安装程序"b)"将起作用
进一步分析
当您转储包装的 CA.dll 文件时
垃圾箱/出口浩劫行动.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的评论
Kjartan 首先使用了 "SetApplicationAutoStart" 和 "SetAppPoolLoadUserProfileTrue".dll由于顺序错误它们没有正确导出到 CA;大写字母"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,没有任何问题迹象。更糟糕的是,在我的情况下,这是一个应该在卸载时运行 Result="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, EntryPointn"));
return 1;
}
LPCTSTR dllName = argv[1];
LPCTSTR entryPoint = argv[2];
HMODULE hLib = LoadLibrary(dllName);
if (hLib == NULL)
{
_tprintf(_T("Error loading %sn"), dllName);
return 1;
}
CustomActionProc procAddress =
(CustomActionProc) GetProcAddress(hLib, CStringA(entryPoint));
if (procAddress == NULL)
{
_tprintf(_T("Error locating entrypoint %sn"), 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再次开始正常工作