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 ]