Problem loading a DLL with boost DLL from a different path when it has dependencies - c++

I use boost::dll for loading libraries at runtime.
With the following code, I'm able to load a DLL even when it's in a different folder than the one with the executable:
auto creator = boost::dll::import_alias<pluginapi_create_t>(fileName, "createPlugin", boost::dll::load_mode::append_decorations);
But I've got a problem when a DLL has other dependencies. This is an example of my folder structure:
Main Folder
|
|-program.exe
|
|-pluginsfolder
|
|-plugin1.dll
|-plugin2.dll
|-dependency.dll
If I load plugin1.dll (which has no other dependencies), it works.
If I load plugin2.dll, that requires dependency.dll, it doesn't work.
I suppose I could put all the DLLs in the same folder, and everything will begin to work again. But I'd like to keep plugins in separate folders because I want other users to be able to load plugins from their respective folders.
How can I load plugins with dependencies regardless their position in the filesystem?

I've found the solution, thanks to Richard comments.
This is the command:
auto creator = boost::dll::import_alias<pluginapi_create_t>(fileName, "createPlugin", boost::dll::load_mode::append_decorations | boost::dll::load_mode::load_with_altered_search_path);
I've added the boost::dll::load_mode::load_with_altered_search_path flag when loading, while searching how to use the corresponding LOAD_WITH_ALTERED_SEARCH_PATH using by windows natively.

Related

Qt Creator: cannot open shared object file after moving library to subdir

I have a project where the library sources were set up the following way:
MyProject
|_MyProject.pro
|_MainStuff
|_MainStuff.pro
|_ManyFiles
|_Tests
|_Tests.pro
|_LotsOfTests
|_MyLibs
| FunLibs.pro
|_FunLib1.h
|_FunLib1.cpp
|_FunLib2.h
|_FunLib2.cpp
This is not ideal, because as the number of FunLibs increases, all of it would be included into a single shared object. With this setup, everything builds and runs just fine. Just to be clear: MyProject.pro is a subdirs template, the MainStuff.pro is an app template, and the FunLibs is a lib template.
The problem stats, when I rearrange the files the following way:
MyProject
|_MainStuff
|_ ManyFiles
|_Tests
|_LotsOfTests
|_MyLibs
|_MyLibs.pro
|_FunLib1
|_FunLib1.pro
|_FunLib1.h
|_FunLib1.cpp
|_FunLib2
|_FunLib2.pro
|_FunLib2.h
|_FunLib2.cpp
Here the MyLibs.pro becomes a subdir tempalte, while the FunLibx.pro files will be lib templates. All configurations have been updated accordingly and the application builds. The problem is that when I now try to launch the application, the following message pops up:
libFunLib1.so.1: cannot open shared object file: No such file or
directory
I don't really understand why doesn't it work now, when it worked with the previous directory structure. This post for example (as many others) recommends to set the LD_LIBRARY_PATH by exporting the dir, but to be honest, I didn't have to do this with the previous setup.
I also have everything set up pretty much as described in the official docs under the "Creating a shared library" part.
Does anybody have an idea what might be the problem? Is there a way to solve this by not exporting the path?
Thanks in advance.
OK, I think I found out what can fix the aforementioned problem. Qt Creator also uses LD_LIBRARY_PATH environment variable for executing compiled programs, but it is somewhat hidden. As it turns out, it is able to use separate sets of env variables for compiling and running applications, and if the env vars for running are not properly defined, the user will get the error message mentioned in the original post, even if the program compiled properly.
To make sure all lib paths are included for running as well, one needs to check out the included paths here:
Projects (mode) --> Run Settings (under Build & Run) --> Run
Environment (expand the Details) --> LD_LIBRARY_PATH (somewhere in the
list)
If that var doesn't include the proper paths, it can be edited after which it is going to get highlighted. After setting this, everything seems to work.

Loading same DLL's with same depending DLL's from different folders

I would like to load the same DLL from different subfolders to compare there results, after for example some refactoring. The DLL I would like to load have some depending DLL's which are linked to it, so they are loaded implicitly.
To make the work easier and to keep overview of the DLL's I organise them in different sub-folders within the current working dir. So I have following structure:
CurrentWorkingDirectory
-> MyApp.exe
-> DllSubDir1
---> ManuallyLoaded.dll
---> DynamiclyLinked.dll
-> DllSubDir2
---> ManuallyLoaded.dll
---> DynamiclyLinked.dll
I managed to load the two different versions of ManuallyLoaded.dll by using LoadLibraryExA and the absolute path to the different DLL's. So I can see the two loaded ManuallyLoaded.dll instances in the debugger.
However, unfortunately the DynamiclyLinked.dll is loaded only once.
To compare all aspects of the ManuallyLoaded.dll after some refactoring, I also would like to load the potentially different versions of DynamiclyLinked.dll. Is there a way to force the application to load implicitly the same DLL from different folders? Or do I need to rename the potentially different version of DynamiclyLinked.dll?
After some time spend in investigation and testing I finally found a possible solution here: https://stackoverflow.com/a/5018526/11264951
In my case it was necessary to
add the depending manifest for DynamicLinked.dll to the ManuallyLoaded.dll. For example with such a pragma. But note to do this in one of the cpp files of the ManuallyLoaded.dll. Because if you do it in one of the h file, the exe will complane about the missing manifest. I assume, during compile time, everything what in added by pragma, is added to the exe.
#pragma comment(linker, "/manifestdependency:\"acme.common'processorArchitecture='*' version='1.0.0.0' type='win32'\"")
build in the manifest in the ManuallyLoaded.dll by setting the corresponding settings in the properties.

Force Qt5 to load SSL dlls from exe dir

Update Sorry, guys, I was incorrectly determined the problem. All is working, error was in "other program logic". Please delete or close the question.
Qt5 is designed to load libeay32.dll and ssleay32.dll on program start before any instruction in main() (because it is static).
(Details: it is located in qtbase\src\network\ssl\qsslsocket_openssl_symbols.cpp:
static QPair<QSystemLibrary*, QSystemLibrary*> loadOpenSslWin32()
)
Issue:
my program starts with not its exe dir as working directory
libeay32.dll and ssleay32.dll resides in its exe dir
user cannot install OpenSSL in system dir
user cannot change PATH variable
I cannot recompile Qt, i.e. ship program with static Qt compiled with openssl-linked
Qt loads searches dlls in this order (from qtbase\src\corelib\plugin\qsystemlibrary.cpp):
Application path.
System libraries path.
Trying all paths inside the PATH environment variable.
No. 1 is Application path, but in fact it does not search there.
My program:
int main()
{
// at this point Qt5 already checked and tried to load the DLLs
// so this:
ChangeCurrentWorkingDirectoryToExeDir(); // some function to change cwd to current exe dir
// does not work :-(
// ... other program logic ..
}
How to force Qt5 to reload OpenSSL DLLs after changing working directory?
May be someone already faced this problem...
Update Sorry, guys, I was incorrectly determined the problem. All is working, error was in "other program logic". Please delete or close the question.
QSystemLibrary::load is called with onlySystemDirectory = false for SSL, so QFileInfo(qAppFileName()).path() is the first place where the DLLs are searched. Search order:
application dir
system path (e.g. C:\Windows\System32)
all paths in PATH
I don't find documentation for that, but in our software, Qt finds SSL libeay32.dll and ssleay32.dll when they are in the same directory as the application .exe, given that
the .dll files are not in PATH
the .dll files are not in the working directory
no qt.conf exists
If you have a qt.conf, the default library value might apply, which is .\lib.
Library search orders are discussed on MSDN at Dynamic-Link Library Search Order.
There's a few ways to handle loading libraries, but it sounds like most of them won't apply.
Its not clear to me why you can call ChangeCurrentWorkingDirectoryToExeDir, but you can't call SetDllDirectory. I'm probably missing something obvious.
It seems like your last option is to create an Qt.exe.local file. This is called Dynamic-Link Library Redirection, and will cause the linker to load the DLL specified in the local file.

C++ placing dll in relative path to exe

I built a small .exe application. Currently I take the compiled .exe file and all necessary .dll's and put them in one folder. So it looks like this: (working)
appfolder/
lib1.dll
lib2.dll
...
app.exe
I'd like to organize it and bring it in following form: (not working)
appfolder/
libs/
lib1.dll
lib2.dll
...
app.exe
However, I do not find a way to make this work. I'm using VS2010 where I tried to add ".\libs" to the Additional Include Directories (Project Properties > Configuration > C/C++).
I also read about LoadLibrary which seems to be not a solution to this problem...
Is that possible at all?
Maybe the SetDllDirectory function will work for you see here.
Besides this you can use LoadLibraryEx and GetProcAddress to do "lazy" loading.
Similar function also exist for Linux.

Ogre SDK exception occured

I've setup Ogre and dependencies on my PC, and downloaded some Ogre applications. When I launch my new exe file of the project I just downloaded it generates the following error:
05:37:59: Loading library C:/OgreSDK_vc9_v1-7-1/bin/debug\RenderSystem_Direct3D9_d
05:37:59: OGRE EXCEPTION(7:InternalErrorException): Could not load dynamic library C :/OgreSDK_vc9_v1-7-1/bin/debug\RenderSystem_Direct3D9_d. System Error: The specified module could not be found.
in DynLib::load at ..\..\..\..\OgreMain\src\OgreDynLib.cpp (line 91)
Any help would be appreciated.
Thanks in advance.
Upon creation of the central Ogre3D class Ogre::Root, you need to pass the name of a *.CFG file that contains all to be loaded Ogre plugins, such as the above mentioned D3D9 Render System.
That file needs to be next to your *.EXE by default and should look like this (in a minimal form where only the D3D9 Render System is loaded and the matching DLL file resides next to this CFG file):
# Defines plugins to load
# Define plugin folder
PluginFolder=.
# Define plugins
Plugin=RenderSystem_Direct3D9
For more information, have a look at this section in the Ogre3D tutorial 1
This took me a while until I figured it out. The dll (RenderSystem_Direct3D9_d) is missed because you didn't build it - it's the project with the same name (RenderSystem_Direct3D9) in the OGRE.sln
I'm using OGRE 2.1, so the dll I missing is RenderSystem_Direct3D11_d.dll instead of RenderSystem_Direct3D9_d.dll like yours, but the fix is similar, just build that dll's project, like the image below.
Anyway, as a beginner, to avoid any trouble, just hit F6 to build whole solution.