Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching LoadLibrary() errors gracefully

I'm working on a piece of C++ software which runs on all Windows versions between Windows XP and Windows Vista. In my code, I developed a DLL which links against a standard library (the Qt library). Once my software is deployed, it's not unusual that the user doesn't have the exact same Qt build on his system but a slightly different configuration. There might be features disabled (so their Qt build doesn't export the same set of symbols) or the library might even be changed in ways which make the library binary incompatible to the original.

At some point, I'm loading my DLL via a LoadLibrary() call. This pulls in whatever Qt library is on the user's system. If I'm lucky, their Qt build is compatible with what I used while developing my DLLs, so LoadLibrary() succeeds. However, depending on the changes they did to their Qt build, the LoadLibrary() call sometimes fails with

  • "The specified Module could not be found."; this usually happens if their Qt build consists of less DLLs than my Qt build. So my DLL attempts to load e.g. QtFoo.dll but since this dll is not part of their Qt build, loading my DLL fails.
  • "The specified Procedure could not be found."; this usually happens if they changes their Qt build so that certain features are disabled, which results in less exported symbols.

My question is: how can I catch these errors gracefully? Right I'm simply using GetLastError() and then print either of the above two messages. However, it would be much more useful if I knew which module could not be found, or which procedure is missing. I noticed that when running an application in the explorer which links against a missing DLL, explorer manages to yield a nice 'The application foo could not be loaded since the required library blah.dll is missing'. Is there maybe some API available to get more information about why a LoadLibrary() call failed exactly?

like image 754
Frerich Raabe Avatar asked Aug 19 '09 07:08

Frerich Raabe


2 Answers

At some point, I'm loading my DLL via a LoadLibrary() call. This pulls in whatever Qt library is on the user's system.

Don't do this! The kind of errors you have are the lucky kind, just as easily it could corrupt memory and crash. The canonical way of shipping a Qt application is either shipping the DLLs or linking statically. Check out the Qt deployment guide in the help files.

Later edit:

After reading your comments, I still do not recommend that you use this approach, since you can't be sure that the DLLs are binary compatible even if they load, which could lead to hard to track errors.

Nevertheless, I believe that you could intercept the LoadLibrary calls and see which ones fail. The MS Detours library can be used for this. Also see this Stackoverflow question.

like image 79
rpg Avatar answered Sep 23 '22 09:09

rpg


To expand jeffamaphone's answer, you can try retrieving the file version details before calling LoadLibrary. You can do this using the following function:

BOOL GetFileDetails(LPCTSTR lpszPath, LPDWORD lpMajorVersion, 
                    LPDWORD lpMinorVersion)
{
    DWORD dwVersionHandle;

    DWORD dwVersionSize = GetFileVersionInfoSize((LPTSTR)lpszPath,
                                                 &dwVersionHandle);
    if (dwVersionSize == 0)
        return FALSE;

    LPBYTE lpVersion = new BYTE[dwVersionSize];

    if (!GetFileVersionInfo((LPTSTR)lpszPath, dwVersionHandle, 
                            dwVersionSize, lpVersion))
    {
        delete [] lpVersion;
        return FALSE;
    }

    VS_FIXEDFILEINFO *pVersionInfo = NULL;
    UINT nLength;

    if (!VerQueryValue(lpVersion, _T("\\"), (LPVOID *)&pVersionInfo, &nLength))
    {
        delete [] lpVersion;
        return FALSE;
    }

    *lpMajorVersion = pVersionInfo->dwFileVersionMS;
    *lpMinorVersion = pVersionInfo->dwFileVersionLS;

    return TRUE;
}

You can then check the major/minor version numbers against ones you're expecting.

like image 35
Alan Avatar answered Sep 23 '22 09:09

Alan