【问题标题】:Delay loading dll in release mode在发布模式下延迟加载dll
【发布时间】:2019-06-14 16:27:59
【问题描述】:

在我在 Visual Studio (C++ 2010 Express) 中构建的 C 项目中,我使用 MatLab 引擎允许用户提供自定义函数以在项目中使用。问题是该代码还需要能够在没有安装 MatLab 的计算机上运行,​​这意味着在这种情况下,所需的 DLL 在计算机上将不可用。当然,这仅在用户不尝试访问调用 matlab 引擎的代码时才有效(我为此提供了一个标志)。

这个场景需要 3 个 dll。

  • libmx.dll
  • libmex.dll
  • libeng.dll

到目前为止,我已经能够使用 LoadLibraryGetProcAddress 在运行时加载 libeng.dll。 其他两个 DLL 有点难,除了调用 MatLab 引擎的 C 代码外,代码也经常编译为 mex 文件(MatLab 可执行文件),以允许用户从 MatLab 调用它。当编译为 mex 文件时,libmx.dll 和 libmex.dll 都由 mex 编译器动态链接。这意味着使用 LoadLibraryGetProcAddress 不适用于这些 DLL。

现在我只是将 libmx 和 libmex LIB 添加到 Visual Studio 中的链接器属性中,这工作正常,但对于没有安装 MatLab 的人来说是不可能的。

我尝试过使用 delayLoad,如果我在 Debug 模式下编译,这可以工作,但是当我在 release 模式下编译时会出现此构建错误。

1>C:\Program Files (x86)\MATLAB\R2012a\bin\win32\libmx.dll : fatal error LNK1107: invalid or corrupt file: cannot read at 0x2B8

如果使用它们的代码部分未被访问,是否有办法完全跳过查找/加载这些 DLL?

这是链接器的命令行:

/OUT:"C:\Users\A.Vandenber\documents\visual studio 2010\Projects\Flash\Release\Flash.exe" /NOLOGO "C:\Program Files (x86)\MATLAB\R2012a\bin\win32\libmx.lib" "C:\Program Files (x86)\MATLAB\R2012a\bin\win32\libmex.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DELAYLOAD:"libmex.dll" /DELAYLOAD:"libmx.dll" /MANIFEST /ManifestFile:"Release\Flash.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\Users\A.Vandenber\documents\visual studio 2010\Projects\Flash\Release\Flash.pdb" /OPT:REF /OPT:ICF /PGD:"C:\Users\A.Vandenber\documents\visual studio 2010\Projects\Flash\Release\Flash.pgd" /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE 

【问题讨论】:

  • 您为链接器设置了哪些选项?请注意,您不会将 .dlls 添加到链接器属性,而是将它们对应的 .libs.
  • 是的,我的错。我确实将 .libs 而不是 .dlls 广告到 properties->linker->input -> additional dependencies 然后是 .dllsproperties->linker->input->Delay Loaded DLL's
  • Release 配置中,您没有忘记在 .dll 之一前面指定 /DELAYLOAD年代?或者你没有尝试为 x64 构建?将链接器命令粘贴到问题中。
  • 我添加了链接器命令。它是 32 位的。我在使用 Visual C++ express 2010 让它在 x64 上工作时遇到了一些麻烦,显然这是一个常见问题
  • 您重建解决方案了吗?导致错误在当前上下文中没有意义。或者,重建并发布完整的错误。您是否也在使用一些自定义构建步骤?

标签: c visual-studio matlab dll matlab-engine


【解决方案1】:

首先,将您的代码移动到包含access privileges 而不是read-only 的目录。也可以在这里查看这个答案:Delay load DLL

要将dll 文件添加到Visual Studio,您可以关注Linking dll in Visual Studio

另一个建议是将dll 放在c:\windows\system32 中。当程序运行时,它会在c:\windows\system32 目录中搜索这个文件。在此之前,它将搜索运行程序的目录。 Visual Studio 从他们的项目目录运行程序(如果提到的 .dll 文件没有放在windows\system32 目录中,则应将其放在该目录中)。同样,如果程序的可执行文件是从其目录中手动运行的,则所说的.dll文件应该在same folder where the program's executable文件所在的位置。您需要管理员权限才能执行此操作。

【讨论】:

    【解决方案2】:

    我越想这个,它就越像[Wikipedia]: XY problem

    1。 X(在没有 MATLAB 库的机器上运行 MEX 文件)

    根据[MathWorks]: Run MEX File You Receive from Someone Else重点是我的):

    在 Windows® 平台上,安装用于创建 MEX 文件的 C++ 编译器运行时库

    ...

    MEX 文件是一个动态链接子例程,当您调用该函数时,MATLAB 解释器会加载并执行该子例程。动态链接意味着当你调用函数时,程序会寻找依赖库。 MEX 文件使用 MATLAB 运行时库和特定于语言的库。 MEX 文件也可能使用专门的运行时库。这些库的代码不包含在 MEX 文件中; 运行 MEX 文件时,这些库必须存在于您的计算机上

    [MathWorks]: MATLAB Runtime 包含用于下载许多版本的链接(你的 - 根据你的路径 - 将是 [MathWorks]: MCR Runtime - MCR_R2012a_win32_installer.exe),它们是免费(我安装了其中的 3 个)版本来测试这种情况),并指出:

    无需安装 MATLAB 即可运行已编译的 MATLAB 应用程序或组件

    所以,很清楚(对我来说)任何想要使用该文件的人都应该安装 MCR

    2。 Y(使用延迟加载的DLL

    VStudio 支持这个功能 ([MS.Docs]: Linker Support for Delay-Loaded DLLs) 已经有一段时间了。

    从未使用过 MEX 文件,我也没有完整的问题规范,但允许一个这样的文件在没有 MATLAB .dll 的存在,对我来说看起来不是好的设计(这意味着它还包含其他东西 - 我认为应该单独放置)。唯一有意义的情况是 MEX 文件将是一个 .exe (不知道这是否可能或者这只是一个愚蠢的事情)并且它会有一些 --help 等价物(在没有 .dll 的环境中运行会很好(但不是强制)。
    但这也可以使用其他方式来解决(例如,类似 README 的文件)

    3。最终问题

    考虑到问题中有多个(逻辑)错误:

    • 传递给链接器的 .dll
    • .lib 文件位于 bin 目录
    • 最新路径 (extern/lib/win64/microsoft) 包含 64 位 .lib,而链接器设置为 32 位 输出
    • [MS.Docs]: Linker Tools Error LNK1107 这很清楚(作为问题中的错误消息)

    我只能得出结论,对于 Release,“C:\Program Files (x86)\MATLAB\R2012a\bin\win32\libmx.dll" 被错误地馈送到链接器(而不是对应的 .lib)。

    我玩了一点MEX

    code.c

    #include <stdio.h>
    #include <conio.h>
    #include <mex.h>
    
    
    int main(int argc, char **argv) {
        if (argc > 1) {
            fprintf(stdout, "Argument passed: mexEvalString() returns\n", mexEvalString("n = 1;"));
        } else {
            fprintf(stdout, "Argument NOT passed: pass...\n");
        }
        fprintf(stdout, "Press a key to exit...\n");
        _getch();
        return 0;
    }
    

    注意事项

    • 我使用 fprintf 因为在 mex.h 中有一行:

      #define printf mexPrintf
      
    • 不知道从 libmx.dll 中使用什么函数来强制直接添加它(不仅仅是 libmex.dll 的依赖项)

    • 我能够在 Debug Release 中测试 Delay Laded DLLs 功能(当不传递 arg ,程序运行时没有将 MEX .dlls 添加到 %PATH%)。
      确实,在运行时我遇到了访问冲突,但这是一个完全不同的问题
    • 不用说,将任何 .dll 添加到“链接器 -> 输入 -> 附加依赖项”,触发完全相同的错误强>

    最后,我想提一下 MCR R2012a(以及其他一些在它之后发布的),是用 VStudio 9.0 (2008 ),并使用 VStudio 10.0 (2010) 构建您的程序,将产生同时加载您的进程的 CRT Lib,并且在某些情况下可能会触发一些错误(特别是因为 VStudio 9.0 是作为 程序集 提供的)。
    这适用于 libmx.dlllibmex.dll,但不适用于 libeng.dll

    【讨论】:

    • 我同意我的问题在很多地方都被错误地表述了。我对 dll 和制作 matlab 调用 C 非常陌生,调用 Matlab 只是在以各种方式搅乱我的思想。感谢您对一个不好的问题的详尽回答。我不再有任何问题,因为将发送给用户的版本是使用 matlab 编译器为 matlab 运行时编译的,使用我们的 C 代码的 mex 文件。编译 mex 文件时,我遇到的两个库会自动包含在内。只有 matlab 引擎对他们不可用,但在运行时加载。
    • 这不是一个坏问题!无论如何,我觉得有点奇怪,没有包含 libeng.dll,而其他 2 个是,因为它们都是由 MCR 安装的。但是,嘿,我对 MATLAB 还是很陌生。
    • hmm,运行 matlab 引擎应用程序需要安装 matlab 版本,而不仅仅是 matlab 运行时 (source),因此即使包含它们,它也无法启动 matlab 引擎。
    • 感谢您的提示!现在我看到MCRlibeng.dll只有11kb,只暴露了17个函数,所以它一定是某种代理。
    猜你喜欢
    • 1970-01-01
    • 2010-11-26
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    • 2021-05-06
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多