c++ - 有没有办法提前测试Windows exe是否会因为缺少dll而无法加载?

标签 c++ windows winapi nsis redistributable

如果您尝试在没有任何更新的情况下在 Windows 8.1 上安装 vs2015 可再发行组件,它将安装失败。但它会在安装过程中进行足够多的操作,GUID 位于注册表中,因此,如果您运行一个程序来检查注册表中是否存在可再发行组件,您将通过该检查。

如果您随后尝试运行一个用 vs2015 编译的程序,该程序需要一些无法安装的 dll,您将看到一个弹出窗口,显示“程序无法启动,因为...”您知道该怎么做。

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

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

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

最佳答案

我相信 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}

关于c++ - 有没有办法提前测试Windows exe是否会因为缺少dll而无法加载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44264521/

相关文章:

python:使用windows api使用ttf字体呈现文本

c++ - 初始化 D3D9 导致第 3 方库停止工作

c++ - 如何在构造期间从派生类实例初始化抽象基类数据成员

.net - C++/CLI 中的垃圾收集

php - 安装 composer (windows) 时缺少许多 DLL

c++ - 在客户端矩形中隐藏光标但不在标题栏上

c++ - Go:使用 C++ 库:包含 <string> 的错误

c++ - 从 C++ 远程访问 Hypertable

c# - 如何以编程方式更改屏幕保护程序?

c++ - 如何检索 Win32 Windows Mobile 平台的进程 ID?