有没有办法预先测试Windows exe是不是因为缺少dll而无法加载?

Posted

技术标签:

【中文标题】有没有办法预先测试Windows exe是不是因为缺少dll而无法加载?【英文标题】:Is there a way to test beforehand if a windows exe will fail to load because of missing dlls?有没有办法预先测试Windows exe是否因为缺少dll而无法加载? 【发布时间】:2017-05-30 14:06:23 【问题描述】:

如果您尝试在没有任何更新的情况下在 Windows 8.1 上安装 vs2015 可再发行组件,它将无法安装。但它会在安装过程中深入到 guid 位于注册表中,因此如果您运行一个程序来检查注册表中是否存在可再发行组件,您将通过该检查。

如果您随后尝试运行一个使用 vs2015 编译的程序,该程序需要一些无法安装的 dll,您将收到一个弹出窗口,上面写着“程序无法启动,因为...”您知道这个练习。

我正在开发一个存在此问题的安装程序(使用 NSIS),并且我正在尝试找到一种方法来在运行 .exe 并获取弹出窗口之前检测 dll 丢失问题。是否有任何我可以运行的命令行工具或我可以调用的任何 NSIS 函数可以在问题发生之前提示我解决这个问题?

甚至是检查 vs2015 可再发行组件是否正确安装的方法? (不必检查可再发行文件中的每个文件是否存在,因为我不知道它们都是什么。)

寻找解决整体问题的任何想法,不一定要专门通过这一检查。我预计可再发行组件可能会以各种方式安装失败。

【问题讨论】:

“如果您运行一个程序来检查注册表中是否存在可再发行组件” - 您将不得不与该程序的作者交谈,并请要求他们修复错误的实现。注册表不是公共编程接口。 使用RegMon for Windows 或Process Monitor 来嗅探注册表访问并找出在消息之前访问了哪个键。然后从您的安装程序中检查它,如有必要,将其删除,然后预安装可再发行组件。我不喜欢使用基于 DLL 的运行时 - 可以选择将(静态链接)嵌入到您的 EXE 中,并且不需要这样的 redist。 @IInspectable 我想他想知道是否安装了 VS2015 可再发行组件。 @MichaelWalz:正确,注册表不是查找该信息的地方。 MsiGetProductInfo 和朋友是要走的路。 ***.com/a/34209692/12386 对我来说似乎很受欢迎...... 【参考方案1】:

我相信 VS2015 是在没有 WinSxS 的情况下在 System32 中安装 .DLL 的版本之一,因此您可能只需检查 vcruntime140.dll 和 msvcp140.dll 是否在 $SysDir 中。

如果您担心它可能是部分安装,您可以查看是否可以加载它(假设您的安装程序与您正在安装的东西的位数相匹配):

!include LogicLib.nsh
System::Call 'KERNEL32::LoadLibrary(t "$SysDir\msvcr100.dll")p.r0'
$If $0 P<> 0
    DetailPrint "I was able to load the MSVC 2010 run-time DLL"
$Else
    DetailPrint "Ooops"
$EndIf

这可能被认为是一个小技巧,但它可能足以满足您的需求。 Dependency Walker 会告诉你要查找哪些 DLL。

如果您愿意,也可以通过 NSIS 致电 MsiGetProductInfo

!define MSVC2005_X86REDIST_PRODUCTCODE A49F249F-0C91-497F-86DF-B2585E8E76B7
!define MSVC2008_X86REDIST_PRODUCTCODE FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4
!define MSVC2010_X86REDIST_PRODUCTCODE 196BB40D-1578-3D01-B289-BEFC77A11A1E
!define MSVC2010SP1_X86REDIST_PRODUCTCODE F0C3E5D1-1ADE-321E-8167-68EF0DE699A5
!define MSVC2010_AMD64REDIST_PRODUCTCODE DA5E371C-6333-3D8A-93A4-6FD5B20BCC6E
!define MSVC2010SP1_AMD64REDIST_PRODUCTCODE 1D8E6291-B0D5-35EC-8441-6616F567A0F7

!define MSVCREDIST_PRODUCTCODE $MSVC2010_X86REDIST_PRODUCTCODE ; I don't have VS2015 redist installed on this machine so I could not test it.
!include LogicLib.nsh
System::Call 'MSI::MsiGetProductInfo(t "$MSVCREDIST_PRODUCTCODE", t "ProductName", t"?"r1, *i$NSIS_MAX_STRLEN)i.r0'
$If $0 == 0
    DetailPrint "ProductName: $1"
    System::Call 'MSI::MsiGetProductInfo(t "$MSVCREDIST_PRODUCTCODE", t "AssignmentType", t"?"r1, *i$NSIS_MAX_STRLEN)i.r0'
    DetailPrint "AssignmentType: $1"
    System::Call 'MSI::MsiGetProductInfo(t "$MSVCREDIST_PRODUCTCODE", t "PackageCode", t"?"r1, *i$NSIS_MAX_STRLEN)i.r0'
    DetailPrint "PackageCode: $1"
    System::Call 'MSI::MsiGetProductInfo(t "$MSVCREDIST_PRODUCTCODE", t "VersionString", t"?"r1, *i$NSIS_MAX_STRLEN)i.r0'
    DetailPrint "VersionString: $1"
$Else
    DetailPrint "Not registered with Windows Installer"
$EndIf

This blog post 表示 Visual Studio 2005 使用 MsiQueryProductState,如果您不需要更多详细信息,这可能是一个不错的简单替代方案:

!define INSTALLSTATE_DEFAULT 5
System::Call 'MSI::MsiQueryProductState(t "$MSVCREDIST_PRODUCTCODE")i.r0'
$If $INSTALLSTATE_DEFAULT = $0
    DetailPrint "Installed"
$Else
    DetailPrint "Not installed"
$EndIf

【讨论】:

Dependency Walker 多年未更新,并产生不可靠的信息。它对转发器 DLL 一无所知,例如,引入这些转发器 DLL 是为了将 API 表面分离到 API 集中。 @IInspectable 转发器 DLL 是什么意思?它支持经典的“DLL.FuncName”转发器。它不理解 API 集,但那些是未记录的 AFAIK(WRT 其内部格式以及它们的使用方式)。 api-ms-win-*.dll 模块是 API 集转发器。有关更多详细信息,请参阅Introducing the Universal CRT。 @Anders 不需要在!define MSVC2005_X86REDIST_PRODUCTCODE A49F249F-0C91-497F-86DF-B2585E8E76B7 中引用A49F249F-0C91-497F-86DF-B2585E8E76B7 吗? @OlowookereEmmanuel 不,如果它需要引号,我显然会引用它。只有空格和引号需要引号...

以上是关于有没有办法预先测试Windows exe是不是因为缺少dll而无法加载?的主要内容,如果未能解决你的问题,请参考以下文章

利用monkey测试android,入门级用户可能遇见的错误及解决办法

有没有办法查看刚刚关闭的 Windows 命令提示符?

修改打开的文件 c++

win7 exe 已停止工作 windows可以联机检查

windows用户隐藏

werfault.exe出现的原因与解决办法以及werfault.exe 该内存不能为written如何解决?