folibis
folibis

Reputation: 12874

Load external dll in Qt in Windows

Assume, I have a folder with my program and also another folder with external library.

bin
    myprog.exe
etc
    lib.dll
    sublib.dll

In my case I want to load the lib.dll from my main program myprog.exe. The problem is that lib.dll linked with sublib.dll.

So I try to do that in this way:

QCoreApplication a(argc, argv);
QLibrary lib;
QString path = "C:/etc/lib.dll";
a.addLibraryPath(path);

if(QLibrary::isLibrary(path)) {
    lib.setFileName(path);
    lib.load();
    if(lib.isLoaded())
        qDebug() << "Ok\n";
    else
        qDebug() << "Error " << lib.errorString() << "\n";
} else
    qDebug() << "Not a library\n";
return a.exec(); 

After running the app I get the error:

cannot load library lib.dll the specified module could not be found

If I put both lib.dll and sublib.dll inside bin directory it works without error. But that is not I want to do.

I've tried

a.addLibraryPath("C:/etc");

but that doesn't work. As I understand QCoreApplication::addLibraryPath() sets path for Qt program, not as system wide setting. So, in this case, lib.dll still can't find sublib.dll although it locates in same directory.

So my question - how can I load external shared library inside Qt program in case that this library has its own dependencies?

Upvotes: 1

Views: 8461

Answers (2)

Nothing prevents you from explicitly preloading the libraries that lib.dll depends on. Once pre-loaded, they're ready for use by any library that you'll subsequently open. After all, you know where they are so it's a simple matter to iterate them and attempt to load them. Due to possible dependencies between these libraries, you have to keep loading them until there's no more progress:

   QString path;
   QSet<QString> libraries;
   QDirIterator it{path, {"*.dll"}};
   while (it.hasNext())
     libraries << it.next();
   bool progress = true;
   while (progress) {
     progress = false;
     for (auto i = libraries.begin(); i != libraries.end();) {
       QLibrary lib{*i};
       if (lib.load()) {
         progress = true;
         i = libraries.erase(i);
       } else
         ++i;
      }
   }

It's either that or to use a PE library of your choice to build the dependency tree yourself and only open the necessary libraries, in dependency order.

Side note: you don't own C:\Windows and you should never write anything there (nor in any subfolder) in any sort of a modern installer.

Upvotes: 2

Alexander V
Alexander V

Reputation: 8718

That is Windows issue. The DLL will be looked at the current process directory and then in the system PATH. The code that is contained in some C:\etc\lib.dll is behaving in its own process and unless very specific logic implemented will behave according to the system rule.

Please refer to MSDN article Dynamic-Link Library Search Order for details. If the source code for that lib.dll is available, it makes sense to examine LoadLibrary call. If there is no specific path provided then:

The first directory searched is the directory containing the image file used to create the calling process (for more information, see the CreateProcess function). Doing this allows private dynamic-link library (DLL) files associated with a process to be found without adding the process's installed directory to the PATH environment variable. If a relative path is specified, the entire relative path is appended to every token in the DLL search path list. To load a module from a relative path without searching any other path, use GetFullPathName to get a nonrelative path and call LoadLibrary with the nonrelative path. For more information on the DLL search order, see Dynamic-Link Library Search Order.

Upvotes: 3

Related Questions