Delay loading dll in release mode
Asked Answered
G

2

6

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 
Gatefold answered 21/1, 2019 at 9:51 Comment(18)
What options did you set to the linker? Note that you don't add the .dlls to the linker properties, but their corresponding .libs.Herc
Yes, my bad. I did ad the .libs and not the .dlls to the properties->linker->input -> additional dependencies and then the .dlls to the properties->linker->input->Delay Loaded DLL'sGatefold
In the Release config didn't you forget to specify /DELAYLOAD in front of one of the .dlls? Or didn't you try to build for x64? Paste the linker command in the question.Herc
I added the linker command. It is 32 bit. I had some trouble getting it to work for x64 with Visual C++ express 2010 and apparently that is a common issueGatefold
Did you rebuild your solution? Cause the error makes no sense in the current context. Or, rebuild and post the full error. Are you using some custom build steps as well?Herc
I'm glad you agree that it doesn't make sense :) But yes i rebuilt. There are some warnings (nothing interesting) and one error message, which is the one in my answer. No custom build steps.. I should add, it works if i add the directory where the libs are located to my PATH environment variable, but the goal is to be able to compile it without the lib files.Gatefold
I get why you want to be able to use your project without Matlab, but why do you need to be able to compile without those lib files?Equiprobable
oh wait, so I guess if you compile with the lib files and add the dll's to DelayLoad, you can run it without them? That actually would make so much sense.Gatefold
From the documentation : "Using the MATLAB engine requires an installed version of MATLAB; you cannot run the MATLAB engine on a machine that only has the MATLAB Runtime." . You may need to use MATLAB Compiler that only requires installation of MATLAB Runtime on the destination machines.Rather
@rahnema1, the goal is to be able to run the program without MatLab, provided that the user then doesn't turn the option for using it on. The DLL for the matlab engine is loaded at runtime. so if the flag is turned off, it is never loaded.Gatefold
Which flag do you mean?Rather
@Rather a flag in the input for the code which determines whether the part with the matlab engine is entered or not. If it's turned off, the LoadLibrary and GetProcAddress to load the matlab engine DLL is not used.Gatefold
Any way to freely reproduce the environment? I (shallowly) searched for Matlab products, but couldn't find free ones.Herc
I know that Octave is a popular free alternative to Matlab but i assume that the similarities will not reach as far as the C API. However, it turned out to be a bit of a non-issue. The version that is distributed to the users will be using matlab runtime environment, the C code will be compiled as a mex file, including libmx and libmex, which means they will be able to run the code with no issues.Gatefold
Can you split the "features requiring MATLAB" into a separate DLL, which links to the MATLAB libraries normally, and then delay-load (or explicit-load with LoadLibrary() and GetProcAddress()) your feature DLL into the main program?Preservative
Is it reproducible on other computers? Or on different VStudio versions? But are you sure that those .lib files are actually lib files? Because their location seems strange (in the bin dir). What is the linker command in Debug mode?Herc
Could you post some minimal code that reproduces the problem? I have now installed version 2012b, i do have the 3 .dlls, but i don't have the corresponding .libs. nor they were in 2012a. I can see the 3 .libs in 2014a.Herc
I realize now that the location i gave earlier was wrong, they are in extern/lib/win64/microsoft. The problem is solved however, so no need to worry about it any longer. Thank you for your suggestions!Gatefold
H
2

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.

Herc answered 29/1, 2019 at 9:15 Comment(4)
I agree with my question being incorrectly formulated in quite some places. I am very new to dll's and making matlab call C, calling Matlab was just messing with my mind in all kinds of ways. Thank you for an elaborate answer to a bad question. I no longer have any problems with it, since the version that will be sent to users is compiled with matlab compiler for matlab runtime, using a mex file of our C-code. When compiling a mex file, the two libraries i had trouble with are automatically included. only the matlab engine will not be available to them, but that's loaded at runtime.Gatefold
Not a bad question at all! Anyway, I find it a bit strange that libeng.dll is not included, while the other 2 are, as all 3 of them are installed by MCR. But hey, I am just as new to MATLAB.Herc
hmm, running matlab engine applications require an installed version of matlab, not just the matlab runtime (source) so even if they are included, it will not be able to start the matlab engine anyway.Gatefold
Thanks for the tip! Now I see MCR's libeng.dll only has 11kb, and only exposes 17 functions, so it must be some kind of a proxy.Herc
L
0

First, move your code to the directory that has access privileges and not read-only. also check this answer here: Delay load DLL

To add the dll files to Visual Studio, You can follow this Linking dll in Visual Studio

Another suggestion is to put the dll in the c:\windows\system32. When a program runs, it will search for this file in the c:\windows\system32 directory. Before that, it will search the directory from which the program was run. Visual Studio runs programs from the directory of their project (where the mentioned .dll file should be put if it is not placed in the windows\system32 directory). Similarly, if the program's executable file is run manually from its directory, the said .dll file should be in the same folder where the program's executable file is located. You will need administrator privileges to do that.

Libertinage answered 28/1, 2019 at 14:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.