【发布时间】:2019-12-11 14:43:34
【问题描述】:
当您尝试在 Windows 上运行程序时,加载程序找不到所有必需的 DLL,默认行为是弹出一个描述问题的对话框,包括程序名称和(其中一个)丢失的 DLL 的名称。然后该过程挂起,直到有人单击“确定”,然后退出并显示错误代码。以下是此对话框的示例:
现在假设您正在编写一些可能由于这个原因而失败的自动化过程,例如安装后运行 CI 测试,其中部分目的是确保安装程序安装所有 DLL。您不希望您的构建工作人员等待某人单击一个对话框,该对话框显示在计算机物理上没有的监视器上,因为它位于某处的服务器机架中。您希望立即停止测试周期并将详细信息写入日志。
您的构建驱动程序可以通过调用SetErrorMode 为自己及其所有子进程(假设没有人使用CREATE_DEFAULT_ERROR_MODE)禁用此对话框:
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
hProc = CreateProcess(...);
但是,这只解决了一半的问题。有问题的进程将以0xC0000135 (STATUS_DLL_NOT_FOUND) 的退出状态终止,但在我能找到的任何地方都没有报告问题可执行文件的名称和丢失的 DLL 的名称。
所以这是实际的问题:如何从构建驱动程序中运行的代码中获取问题可执行文件的名称和丢失的 DLL 的名称,以便我可以将它们写入我的 CI 构建日志?任何事情都会发生,除了问题可执行文件本身的代码和它的 DLL 不能被修改(因为这应该是一个通用的解决方案)并且强烈推荐不需要提升权限的方法。
(这是Suppress "The program can't start because X.dll is missing" error popup 的后续问题。多年来我一直隐约想写它。)
【问题讨论】:
-
简短回答 - 你不能。调用 CreateProcess 的进程根本无法获得该信息。除非它像 SysInternals ProcessMonitor 那样监视文件系统,以查看加载每个文件的每次尝试,然后可以看到诸如“未找到”之类的错误。
-
@RemyLebeau 你确定没有办法让
LoadLibrary实现,例如,获取它应该放入对话框的信息,而是将其写入标准错误句柄或系统日志或类似的东西?而且也没有办法拦截对话框使用,我不知道,可访问性 API 可能,刮掉它的内容然后关闭它? -
LoadLibrary()不是一个因素。错误对话框来自 OS Loader 本身,同时将 EXE 加载到内存并解析其 DLL 依赖项,然后生成的进程开始运行。如果你想拦截对话框,你可以在调用CreateProcess()之前尝试通过SetWindowsHookEx()安装一个全局钩子,但是你自己负责抓取对话框的内容,然后将其关闭。没有 API 可以直接向您提供您寻求的信息。你将不得不寻找它。 -
您需要启用show loader snaps GFlags 选项,并在调试器下运行您的进程。我确信至少有一个调试器可以让您将其控制台输出转储到文件中。万一我错了,你必须自己实现。
标签: winapi