Force Qt5 to load SSL dlls from exe dir - c++

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.

Related

How to resolve missing Lua DLL when using LuaBinaries and LuaBridge?

I'm trying to embed Lua into C++ (and learn Lua), starting off with Elias Daler's training wheels method here. I'm using MSVC 14.0, LuaBinaries 5.3.2 - Release 1 (specifically, lua-5.3.2_Win32_dllw4_lib.zip here), and LuaBridge 2.0.
I've added the following Additional Include Directories:
C:\lua-5.3.2_Win32_dllw4_lib\include;C:\LuaBridge
And the following Additional Dependency:
C:\lua-5.3.2_Win32_dllw4_lib\liblua53.a
And I'm using the following source (pared down as far as it can):
#include "stdafx.h"
#include <LuaBridge.h>
int main() {
luabridge::lua_State* L = luabridge::luaL_newstate();
}
That source compiles and links fine, but the application itself causes a standard missing DLL system error:
The program can't start because lua53.dll is missing from your computer. Try reinstalling the program to fix this problem.
lua53.dll is in C:\lua-5.3.2_Win32_dllw4_lib\ —what am I missing?
According to the official Microsoft documentation, Windows searches for DLLs in the following directories:
The directory where the executable module for the current process is located.
The current directory.
The Windows system directory. The GetSystemDirectory function retrieves the path of this directory.
The Windows directory. The GetWindowsDirectory function retrieves the path of this directory.
The directories listed in the PATH environment variable.
So, one way to solve the problem would be to add C:\lua-5.3.2_Win32_dllw4_lib to the current user's PATH.
Compared to the other options, this has the advantages of not requiring admin privileges and not requiring lua53.dll to be in either the current directory or the same directory as your executable.

Unable to load shared library : libxerces.so

While running the application developed by other person, getting the following error
./appln: error while loading shared libraries: libxerces-c.so.28: cannot open shared object file: No such file or directory
And if I run ldd command:
# ldd appln
linux-gate.so.1 => (0x00e20000)
libdl.so.2 => /lib/libdl.so.2 (0x00a61000)
libxerces-c.so.28 => not found
I already have that libxerces-c.so.28 file in current folder. Please help me how to resolve that error
You need to put libxerces-c.so somewhere in the library path. Probably current folder is not searched for libraries. Try putting it in /usr/local/lib
Evidently "the current folder" isn't in the run time search path used by your executable. I'm assuming that you are on linux (linux-gate.so.1).
You need to ensure that "the current" directory is under the search path. You can do this at link time by using the -rpath option to the linker (-R is also accepted) or -Wl,-rpath,<dir> if you are invoking the linker through the compiler front end. This embeds a search path to be used at run time into your program.
Consider how you want the program to be installed, though. There's no point in adding a path that is specific to your development environment. You might want to consider using $ORIGIN or a $ORIGIN relative path which tells the run time linker to look for shared objects in the location containing (or relative to) the executable. You should always avoid adding . to the run time search path; your program shouldn't behave differently depending on the current directory of the process which invokes it.
As a temporary measure you can set the environment variable LD_LIBRARY_PATH to override the embedded and system search paths but it is normally a bad idea to rely on LD_LIBRARY_PATH overrides for a final installation.
By default .so files are NOT being searched in the current folder (they should be in /usr/lib, etc).
To add the current directory for .so lookup use:
LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH ./appln
When adding new "local system" libraries (e.g. in /usr/local/lib/) you better add that directory (/usr/local/lib/) once in your /etc/ld.so.conf and you should run ldconfig to update the linker cache (every time you add something inside /usr/local/lib/)
See ldconfig(8), ld.so(8), ldd(1), dlopen(3)
If you want your own libraries, set LD_LIBRARY_PATH to a directory containing them (e.g. $HOME/lib/ and to standard directories, e.g.
export LD_LIBRARY_PATH=$HOME/lib:/usr/lib:/usr/local/lib
in your ~/.bashrc (but I dislike that confusing practice, and prefer to manage my /usr/local/lib/).
You could also use some -Wl,-rpath argument but I really dislike that also.
Read also Program Library HowTo and Drepper's paper: How To Write Shared Libraries

Recursive shared library loading - Cannot open shared object file

I am compiling an application which consists of several projects, that generate dynamic libraries (Shared Libraries on LINUX). Of course that different projects are linking to the others that I've compiled. I am using CodeBlocks 10 under Ubuntu, using GCC compiler.
Due to the fact that, according to the arguments specified by the user, different libraries shall be loaded, in my main application I am loading the appropriate library, according to the decision, with the following line:
dll = dlopen("my_library.so", RTLD_LAZY);
As specified in documentation, the dlopen loads libraries automatically If the library has dependencies on other shared libraries and the process is done recursively.
The problem is that right after my dlopen, I call dlerror() in order to understand what's going on and I get the following error:
../../../../gccDebug/os.so : Cannot open shared object file: No such
file or directory.
Just looking at the error, I completly understand it, because it is looking 2 folders below more than it should. The question is why?
What I mean is: I use relative paths to explicitly load Shared Libraries on the projects. On my Main Application, the Working Directory is ../../gccDebug.
I load, using dlopen, mylibrary.so, which explicitly loads (in project Options) ../../gccDebug/gui.so. This gui.so then also explicitly loads (in project options) ../../gccDebug/so.os
What it seems to me that is happening, is that he is appending the paths making that on the 3rd "iteration" he is looking for a path which is already searching too many folders back than it should. If the first recursive loading (gui.so) works just fine, why does the 2nd recursive loading (so.os) is giving a strange path??
What is wrong with the recursive loading of the shared libraries using dlopen function?
Each path should be relative to the library doing the loading, so for ../../gccDebug/gui.so to load something in the same directory it should load ./gui.so
The extra ../.. are because you've told something in ../../gccDebug to load something in ../../gccDebug_relative to itself_ which relative to your program's working directory is../../gccDebug/../../gccDebugi.e.../../../gccDebug`
Do that a few times for different libraries and you'll get the number of unwanted .. components you're seeing.
Are you sure that gui.so actually loaded? Could it be that mylibrary.so had copied the ../../gccDebug/os.so dependency from gui.so at link-time and so at run-time was trying to load that before loading gui.so?
Have you use ldd mylibrary.so to see what it tries to find? You can also use readelf -d mylibrary.so to see the contents of the dynamic section of the library.

C++ move dll files from root to sub folder

I'm making a program in visual c++. The program relies on some dll files, which I don't want to place in system32. Now the dll files is in the same folder as my .exe, but i would like to move them to a sub folder. The problem is, if I move the files, my application fails to start and comes with this error message:
MyProgram.exe - Unable to Locate Component
This application has failed to start because myDll.dll was not found. Re-installing the application may fix the problem.
I have had the same problem before, where if found a solution, which included adding something to the registry, but i forgot how it worked, and now I can't find the guide again.
Can someone please help me?
There is more than one way to solve this problem. As other mentioned you can modify search path for your application in registry. Sometimes, you don't have rights to write to the registry, or you cannot do it for other reasons, then you can set dll path explicitly, the WinAPI function for that is SetDllDirectory, see MSDN.
Sounds like you're after the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths key. See here for complete information. In short, a string called Path points to a DLL search path. For example if your application was called "MyApp" a .reg file like this would do the trick:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppPaths\MyApp.exe]
#="C:\\Program Files\\MyCompany\\MyApp\\MyApp.exe"
"Path"="C:\\Program Files\\MyCompany\\MyApp\\DLLs"
I believe this is the article you are looking for:
http://www.codeguru.com/Cpp/W-P/dll/article.php/c99
Each application can now store it own path the registry under the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
The use the application path, set a key for your application, using ONE.EXE from the example above:
HKEY_LOCAL_MACHINE...\CurrentVersion\App Paths\ONE.exe
Set the (Default) value to the full path of your executable, for example:
C:\Program Files\ONE\ONE.exe
Add a sub-key named Path

DLL file loaded twice with DLL redirection through manifest

I'm including python.h in my Visual C++ DLL file project which causes an implicit linking with python25.dll. However, I want to load a specific python25.dll (several can be present on the computer), so I created a very simple manifest file named test.manifest:
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<file name="python25.dll" />
</assembly>
And I'm merging it with the automatically embedded manifest file generated by Visual Studio thanks to:
Configuration Properties -> Manifest Tool -> Input and Output -> Additional Manifest Files
-->$(ProjectDir)\src\test.manifest
python25.dll is now loaded twice: the one requested by the manifest, and the one that Windows should find through its search order.
Screendump of Process Explorer http://dl.dropbox.com/u/3545118/python25_dll.png
Why is that happening and how can I just load the DLL file pointed by the manifest?
After exhaustive battle with WinSxS and DLL redirection, here's my advice for you:
Some background
Various things can cause a DLL file to be loaded under Windows:
Explicit linking (LoadLibrary) -- the loader uses the current activation context of the running EXE file. This is intuitive.
Implicit linking ("load time linkage", the "auto" ones) -- the loader uses the default activation context of the depending DLL file. If A.exe depends on B.dll depends on C.dll (all implicit linkage), the loader will use B.dll's activation context when loading C.dll. IIRC, it means if B's DllMain loads C.dll, it can be using B.dll's activation context -- most of the time it means the system-wide default activation context. So you get your Python DLL from %SystemRoot%.
COM (CoCreateInstance) -- this is the nasty one. Extremely subtle. It turns out the loader can look up the full path of a DLL file from the registry using COM (under HKCR\CLSID). LoadLibrary will not do any searching if the user gives it a full path, so the activation context can't affect the DLL file resolution. Those can be redirected with the comClass element and friends, see [reference][msdn_assembly_ref].
Even though you have the correct manifest, sometimes someone can still change the activation context at run time using the Activation Context API. If this is the case, there is usually not much you can do about it (see the ultimate solution below); this is just here for completeness. If you want to find out who is messing with the activation context, WinDbg bp kernel32!ActivateActCtx.
Now on to finding the culprit
The easiest way to find out what causes a DLL file to load is to use Process Monitor. You can watch for "Path containing python25.dll" or "Detail containing python25.dll" (for COM lookups). Double clicking an entry will actually show you a stack trace (you need to set the symbol search paths first, and also set Microsoft's PDB server). This should be enough for most of your needs.
Sometimes the stack trace obtained from above could be spawned from a new thread. For this purpose you need WinDbg. That can be another topic, but suffice to say you can sxe ld python25 and look at what other threads are doing (!findstack MyExeModuleName or ~*k) that causes a DLL file to load.
Real world solution
Instead of fiddling with this WinSxS thing, try hooking LoadLibraryW using Mhook or EasyHook. You can just totally replace that call with your custom logic. You can finish this before lunch and find the meaning of life again.
[msdn_assembly_ref]: Assembly Manifests
I made some progress for the understanding of the issue.
First let me clarify the scenario:
I'm building a DLL file that both embeds and extends Python, using the Python C API and Boost.Python.
Thus, I'm providing a python25.dll in the same folder as my DLL file, as well as a boost_python-vc90-mt-1_39.dll.
Then I have an EXE file which is a demo to show how to link to my DLL file: this EXE file doesn't have to be in the same folder as my DLL file, as long as the DLL file can be found in the PATH (I'm assuming that the end user may or may not put it in the same folder).
Then, when running the EXE file, the current directory is not the one containing python25.dll, and that's why the search order is used and some other python25.dll can be found before mine.
Now I figured out that the manifest technique was the good approach: I managed to redirect the loading to "my" python25.dll.
The problem is that this is the Boost DLL file boost_python-vc90-mt-1_39.dll that's responsible for the "double" loading!
If I don't load this one, then python25.dll is correctly redirected. Now I somehow have to figure out how to tell the Boost DLL file not to load another python25.dll...
Dependency Walker is usually the best tool for resolving this kind of problem. I'm not too sure how well it handles manifests though...
Where in this entangled mess is the actual process executable file?
Two possibilities come to mind:
You are writing a Python extension DLL file. So the Python process is loading your DLL file, and it would already have its own python25.dll dependency.
The EXE file loading your DLL file is being built with header files and libraries provided by the DLL file project. So it is inheriting the #pragma comment(lib,"python25.lib") from your header file and as a result is loading the DLL file itself.
My problem with the second scenario is, I'd expect the EXE file, and your DLL file, to be in the same folder in the case that the EXE file is implicitly loading your DLL file. In which case the EXE file, your DLL file and the python25.dll are all already in the same folder. Why then would the system32 version ever be loaded? The search order for implicitly loaded DLL files is always in the application EXE file's folder.
So the actual interesting question implicit in your query is: How is the system32 python26.dll being loaded at all?
Recently, I hit a very similar problem:
My application embedding Python loads the python32.dll from a known location, that is a side-by-side assembly (WinSxS) with Python.manifest
Attempt to import tkinter inside the embedded Python interpreter caused second loading of the very same python32.dll, but under a different non-default address.
The initialisation function of tkinter module (specifically, _tkinter.pyd) was failing because to invalid Python interpreter thread state (_PyThreadState_Current == NULL). Obviously, Py_Initialize() was never called for the second Python interpreter loaded from the duplicate python32.dll.
Why was the python32.dll loaded twice? As I explained in my post on python-capi, this was caused by the fact the application was loading python32.dll from WinSxS, but _tkinter.pyd did not recognise the assembly, so python32.dll was loaded using the regular DLL search path.
The Python.manifest + python32.dll assembly was recognised by the DLL loading machinery as a different module (under different activation context), than the python32.dll requested by _tkinter.pyd.
Removing the reference to Python.manifest from the application embedding Python and allowing the DLL search path to look for the DLLs solved the problem.