Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delay loading dll in release mode

In a C project i'm building in Visual Studio (C++ 2010 Express), I use the MatLab engine to allow for a user to provide a custom function to use within the project. The problem is that this code also needs to be able to run on computers without MatLab installed on it, meaning that the required DLL's will not be available on the computer in that case. Of course this should only work when the user does not try to access the piece of code which calls the matlab engine (I have provided a flag for this).

I have 3 dll's that are needed for this scenario.

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

So far i have been able to load the libeng.dll at run-time using LoadLibrary and GetProcAddress. The other two DLL's are a bit harder though, apart from the C-code calling the MatLab engine, the code is also often compiled as a mex-file (MatLab executable), to allow users to call it from MatLab. When compiling as a mex-file, both libmx.dll and libmex.dll are dynamically linked by the mex compiler. This means that using LoadLibrary and GetProcAddress don't work for these DLL's.

Right now I just add the libmx and libmex LIB's to the linker properties in visual studio and this works fine, but will not be possible for someone who doesn't have MatLab installed.

I have tried using delayLoad and this works if I compile in Debug mode, but gives this build error when I compile in release mode.

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

Is there a way to just completely skip looking for / Loading these DLL's if the part of the code that uses them is not accessed?

This is the command line for the linker:

/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 
like image 760
Alexander Vandenberghe Avatar asked Jan 21 '19 09:01

Alexander Vandenberghe


People also ask

How to delay load DLL?

An application can delay load a DLL using the /DELAYLOAD (Delay load import) linker option with a helper function. (A default helper function implementation is provided by Microsoft.) The helper function loads the DLL on demand at runtime by calling LoadLibrary and GetProcAddress for you.

What is delay load?

The /DELAYLOAD option causes the DLL that's specified by dllname to be loaded only on the first call by the program to a function in that DLL. For more information, see Linker Support for Delay-Loaded DLLs. You can use this option as many times as necessary to specify as many DLLs as you choose. You must use Delayimp.


1 Answers

The more I think about this, the more it looks like a [Wikipedia]: XY problem.

1. The X (running the MEX file on a machine with no MATLAB libraries)

According to [MathWorks]: Run MEX File You Receive from Someone Else (emphases are mine):

On Windows® platforms, install the C++ compiler run-time libraries used to create the MEX file.

...

A MEX file is a dynamically linked subroutine that the MATLAB interpreter loads and executes when you call the function. Dynamic linking means that when you call the function, the program looks for dependent libraries. MEX files use MATLAB run-time libraries and language-specific libraries. A MEX file might also use specialized run-time libraries. The code for these libraries is not included in the MEX file; the libraries must be present on your computer when you run the MEX file.

[MathWorks]: MATLAB Runtime contains links for downloading many versions (yours - according to your paths - would be [MathWorks]: MCR Runtime - MCR_R2012a_win32_installer.exe), which are free (I installed 3 of those versions to test this scenario), and also states:

Run compiled MATLAB applications or components without installing MATLAB

So, it's pretty clear (to me) that whoever would like to use that file, should install the MCR.

2. The Y (using Delay Loaded DLLs)

VStudio supports this feature ([MS.Docs]: Linker Support for Delay-Loaded DLLs) for quite some time.

Never worked with MEX files, nor do I have the full problem specs, but allowing one such file to run when there are no MATLAB .dlls present, doesn't look like good design to me (meaning that it also contains other stuff - which on my opinion should be placed separately). The only scenario that makes sense is that the MEX file would be an .exe (don't know whether this is possible or it's just a dumb thing) and it would have some --help equivalent (which would be nice (but not mandatory) to run on environments without the .dll's).
But that too could be solved using other ways (e.g. a README like file)

3. The end problem

Considering that there were / are multiple (logical) errors in the question:

  • The .dlls passed to the linker
  • The .lib files located in the bin dir
  • The latest path (extern/lib/win64/microsoft) contains 64 bit .libs, while the linker is set for 32 bit output
  • [MS.Docs]: Linker Tools Error LNK1107 which is pretty clear (as the error message in the question)

I can only conclude that for Release, "C:\Program Files (x86)\MATLAB\R2012a\bin\win32\libmx.dll" was incorrectly fed to the linker (instead of the corresponding .lib).

I played a little bit with 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;
}

Notes:

  • I used fprintf because in mex.h there is a line:

    #define printf mexPrintf
    
  • Didn't know what function to use from libmx.dll, to force it being added directly (not just a dependency for libmex.dll)

  • I was able to test the Delay Laded DLLs feature in Debug and Release (when passing no arg, the program ran without adding the MEX .dlls to %PATH%).
    It's true that at runtime I got Access Violation, but that's a totally different issue
  • Needless to say that adding any of the .dlls to "Linker -> Input -> Additional Dependencies", triggered the exact same error

At the end, I would like to mention that MCR R2012a (and some others that were released after it), are built with VStudio 9.0 (2008), and building your program with VStudio 10.0 (2010), will yield having both CRT Libs in loaded your process, and in some cases that might trigger some errors (especially since VStudio 9.0's comes as an assembly).
This applies to libmx.dll and libmex.dll, but not libeng.dll.

like image 144
CristiFati Avatar answered Sep 30 '22 19:09

CristiFati