在发布模式下延迟加载dll

时间:2019-01-21 09:51:50

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

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

在这种情况下,我有3个dll。

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

到目前为止,我已经可以使用 LoadLibrary GetProcAddress 在运行时加载libeng.dll。 但是,除了调用MatLab引擎的C代码之外,其他两个DLL都较难一些,该代码通常还被编译为mex文件(MatLab可执行文件),以允许用户从MatLab对其进行调用。当作为mex文件编译时,mex编译器会动态链接libmx.dll和libmex.dll。这意味着使用 LoadLibrary GetProcAddress 不适用于这些DLL。

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

我尝试使用 delayLoad ,如果我在“调试”模式下进行编译,则此方法有效,但是在“发布”模式下进行编译时,则会出现此生成错误。

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 

2 个答案:

答案 0 :(得分: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文件中。 运行MEX文件时,库必须存在于计算机中

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

  

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

因此,(对我而言)很明显,任何想使用该文件的人都应该安装 MCR

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

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

从未使用过 MEX 文件,也没有完整的问题说明,但是当没有 MATLAB .dll < / em>的礼物对我来说似乎不是一个好的设计(这意味着它还包含其他内容-我认为应单独放置)。唯一有意义的情况是 MEX 文件将是 .exe (不知道这是可能的还是愚蠢的事情),并且一些--help等效项(在没有 .dll 的环境中运行会很好(但不是强制性))。
但是也可以使用其他方式(例如类似文件的 README )来解决

3。最终的问题

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

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

我只能得出结论,对于发布,“ C:\ Program Files(x86)\ MATLAB \ R2012a \ bin \ win32 \ libmx。 dll < / em>“ 错误地馈送到了链接器(而不是相应的 .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 的依赖项)< / p>

  • 我能够在 Debug Release 中测试延迟分层DLLs 功能(不传递参数时) ,则程序运行时未将 MEX .dll s添加到%PATH%)。
    的确是在运行时出现了访问冲突,但这是一个完全不同的问题
  • 不用说将任何 .dll 添加到“ 链接器->输入->其他依赖项”中,触发了完全相同的错误

最后,我要提到 MCR R2012a (以及其后发布的其他一些产品)是使用 VStudio 9.0 (2008 ),并使用 VStudio 10.0(2010)构建程序,将会同时加载 CRT Lib ,并且在某些情况下可能会触发一些错误(尤其是因为 VStudio 9.0 作为程序集附带)。
这适用于 libmx.dll libmex.dll ,但不适用于 libeng.dll

答案 1 :(得分:0)

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

要将dll文件添加到Visual Studio,您可以按照以下Linking dll in Visual Studio

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