Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

Qt-interest Archive, October 2007
QLibrary on Windows


Message 1 in thread

I'm trying to port a section of our code from Linux to Windows.  This uses 
QLibrary from Qt 3.  Everything works well in Linux but fails on Windows and 
I'm looking for some pointers to figure out what's going wrong.

The library in question is libpq.dll.  That's the postgres library.  Yes, I 
know that Qt3 includes support for PostGreSQL but we don't want to use that.

So, I do the following:

if (!QFile::exists(libname)) {
  // Display an error message
  return;
}

QLibrary* library = new QLibrary(libname);
if (!library->load()) {
    // Display an error
}

Now, I've tried loading the library with the full filename and path.  That 
passes the QFile::exists check but then the library fails to load.  I've 
tried commenting out the ::exists check and trying with "pq" and "libpq" as 
the library instead of the full filename and path.  That also fails.

I tried doing:
regsvr32 libpq.dll
but this fails.  That seems to be expected, however.


What am I doing wrong?  I'm really not sure where to even start debugging 
here.  Remember, this code works in Linux.

--
 [ signature omitted ] 

Message 2 in thread

Chris Thompson wrote:
> I'm trying to port a section of our code from Linux to Windows.  This uses 
> QLibrary from Qt 3.  Everything works well in Linux but fails on Windows and 
> I'm looking for some pointers to figure out what's going wrong.
> 
> The library in question is libpq.dll.  That's the postgres library.  Yes, I 
> know that Qt3 includes support for PostGreSQL but we don't want to use that.
> 
> So, I do the following:
> 
> if (!QFile::exists(libname)) {
>   // Display an error message
>   return;
> }
> 
> QLibrary* library = new QLibrary(libname);
> if (!library->load()) {
>     // Display an error
> }
> 
> Now, I've tried loading the library with the full filename and path.  That 
> passes the QFile::exists check but then the library fails to load.  I've 
> tried commenting out the ::exists check and trying with "pq" and "libpq" as 
> the library instead of the full filename and path.  That also fails.

I took a look at the Qt source code and QLibrary::load basically just 
does a LoadLibrary API call.  Now I started out with a suspicion that 
the whole problem here was that while Windows was finding the libpq.dll 
just fine, it in turn depends on other libraries and it wasn't finding 
them.  I found in the API docs that using SetErrorMode(0) can make 
Windows give a better error message so I wrote a test program that does 
SetErrorMode(0) and then tries to load the library and I get an error 
dialog popup saying that the comerr32.dll can't be found.  This is in 
the PostgreSQL bin directory where the libpq.dll is but I guess its not 
searching there.

So I looked up how LoadLibrary searches for libraries.  It turns out it 
does the following:

1. It looks in the directory where the application was loaded

2. It looks in the directory specified by SetDllDirectory

3. It looks in System32

4. It looks in System

5. It looks in the Windows directory

6. It looks in any directory included in the PATH

The SetDllDirectory looked helpful so I tried to use that and found I 
couldn't.  Found out its a recent addition and only there after XP SP-1 
has been installed and it doesn't seem to be there in the windows.h on 
my system.  I wrote some code to get a handle to this from kernel32.dll 
though and this got things working.

So it looks like the options for loading the libpq.dll from the 
directory C:\Program Files\PostgreSQL\8.2\bin are:

1. Copy the dll's out of there and in to the application directory

2. Add this directory to the PATH

3. If you can SetDllDirectory, use it to add this directory to the dll 
search path

Really I would have thought that PostgreSQL should have installed their 
dll files to the System32 or System directory and then all this would go 
away.

I've attached a test program that shows that its all working.  Comment 
out the setDllDirectory call to see the dialog that SetErrorMode shows.

--
 [ signature omitted ] 
#include <qapplication.h>
#include <qlibrary.h>
#include <windows.h>

typedef void (CALLBACK* LPFNSETDLLDIRECTORY)(LPCTSTR);

void
setDllDirectory(const char* path)
{
  static LPFNSETDLLDIRECTORY MySetDllDirectory = NULL;

  HMODULE hmod = GetModuleHandleA("kernel32.dll");

  if (hmod != NULL) {
    MySetDllDirectory = (LPFNSETDLLDIRECTORY) GetProcAddress(hmod,
						"SetDllDirectoryA");
    if (!MySetDllDirectory)
      printf("SetDllDirectory not supported\n");
  } else
    printf("Error getting kernel32.dll module handle\n");

  if (MySetDllDirectory) {
    MySetDllDirectory((LPCTSTR)path);
  }
}

int
main(int argc, char* argv[])
{
  QApplication app(argc, argv);

  SetErrorMode(0);

  setDllDirectory("C:\\Program Files\\PostgreSQL\\8.2\\bin");

  QLibrary library("libpq.dll");
  if (!library.load())
    qFatal("Loading failed: %d", GetLastError());

  void* PQstatus = library.resolve("PQstatus");
  qDebug("PQStatus = %p", PQstatus);

  return 0;
}

Message 3 in thread

Brad Pepers schrieb:
> > ...
> 1. Copy the dll's out of there and in to the application directory
> 
> 2. Add this directory to the PATH
> 
> 3. If you can SetDllDirectory, use it to add this directory to the dll 
> search path
> 
> Really I would have thought that PostgreSQL should have installed their 
> dll files to the System32 or System directory and then all this would go 
> away.

If you really intend to ship your application to a customer then you 
should never rely on the existence of certain 3rd party DLLs (and not 
even for the C++ runtime DLLs, for that matter, see other thread 
"Problems with Win Vista" ;) )

So chances that a user has C:\Program Files\PostgreSQL\8.2\bin installed 
on her machine are rather slim.

As a side-note: just remember that you should never hardcode the path 
"Program Files" in your application, e.g. when calling the 
SetDllDirectory() function. On my system for example it would be called 
"Programme" - see again other thread "Problems with Win Vista")

A good thing (at least on Windows) is hence to ship *all* required DLLs 
with your application: C++ runtime (or have vcredist_x86.exe run by the 
installer), Qt, Qt plugins, 3rd party DLLs, your DLLs, ...

By the way you can also setup a registry entry for your application and 
modify its PATH as soon as it is executed, see my soon-to-follow post 
about "Build framework" if you are interested. Then you can have a setup 
like this:

   [AppDir]
   + TheApplication.exe
   + lib // subdirectory containing all required libs
     + - Qt libs
     + - PostgreSQL libs

Off course calling SetDllDirectory() (I did not know this one, thanks ;) 
on "lib" would also be a (probably more elegant) solution. But setting a 
registry key works also on Windows 2000 (and probably since Windows 95 
or even earlier).

Have a look at:

   HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths

It seems to be a common thing to use it, also for recent applications.


Off course when you are dealing with an "in-house tool" where you have 
control over the target platforms and can have your users install the 
PostgreSQL package, then you don't need to worry about shipping the 
PostgreSQL libraries...


Cheers, Oliver

--
 [ signature omitted ]