正确捕获LoadLibrary()错误

时间:2009-08-19 07:32:39

标签: c++ windows qt plugins loadlibrary

我正在开发一款可在Windows XP和Windows Vista之间的所有Windows版本上运行的C ++软件。在我的代码中,我开发了一个链接标准库(Qt library)的DLL。一旦部署了我的软件,用户在他的系统上没有完全相同的Qt构建,但配置略有不同并不罕见。可能有禁用的功能(因此它们的Qt构建不会导出相同的符号集),或者甚至可能以使库二进制文件与原始文件不兼容的方式更改库。

在某些时候,我正在通过LoadLibrary()调用加载我的DLL。这可以吸引用户系统上的任何Qt库。如果我很幸运,他们的Qt构建与我在开发DLL时使用的内容兼容,因此LoadLibrary()成功。但是,根据他们对Qt构建所做的更改,LoadLibrary()调用有时会失败并带有

  • “找不到指定的模块。”;如果他们的Qt构建包含比我的Qt构建更少的DLL,通常会发生这种情况。所以我的DLL试图加载例如QtFoo.dll但由于这个dll不是他们Qt构建的一部分,因此加载我的DLL失败。
  • “找不到指定的程序。”;如果他们更改了他们的Qt版本以便禁用某些功能,这会导致导出的符号减少。

我的问题是:我怎样才能优雅地捕捉到这些错误?对,我只是使用GetLastError(),然后打印上述两个消息之一。但是,如果我知道无法找到模块,或缺少哪个过程,那么很多会更有用。我注意到,当在资源管理器中运行一个链接缺少DLL的应用程序时,资源管理器设法产生一个很好的'由于缺少所需的库blah.dll而无法加载应用程序foo'。是否有一些API可用于获取有关LoadLibrary()调用失败原因的更多信息?

6 个答案:

答案 0 :(得分:2)

  

在某些时候,我正在加载我的DLL   一个LoadLibrary()调用。拉了进来   无论Qt库在用户身上   系统

不要这样做!你遇到的那种错误是幸运的,同样容易损坏内存和崩溃。 运送Qt应用程序的规范方式是运送DLL或静态链接。查看帮助文件中的Qt部署指南。

稍后编辑:

在阅读您的评论后,我仍然不建议您使用此方法,因为即使加载了DLL也无法确定DLL是否是二进制兼容的,这可能导致难以跟踪错误。

尽管如此,我相信您可以拦截LoadLibrary调用并查看哪些调用失败。 MS Detours库可用于此目的。另请参阅this Stackoverflow问题。

答案 1 :(得分:2)

要扩展jeffamaphone的答案,您可以在致电LoadLibrary之前尝试检索文件版本的详细信息。您可以使用以下功能执行此操作:

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;
}

然后,您可以检查主要/次要版本号码与您期望的版本号码。

答案 2 :(得分:1)

如果没有将调试器附加到您的进程,我认为您不能。通常在发生这种情况时弹出的消息由LoadLibrary在内部生成。 SetErrorMode在很多应用程序中被用来禁止这种形式的消息,我正在你的应用程序框架中的某个地方,它调用SetErrorMode来禁止操作系统消息。

我见过的唯一应用程序生成自己的关于dll加载失败的详细消息是MS DevStudio - 它作为调试器附加,因此可以访问特殊的调试事件流。

答案 3 :(得分:1)

ImageHLP.DLL中的MapAndLoad可以提供帮助。它返回一个LOADED_IMAGE结构。

答案 4 :(得分:0)

在调用LoadLibrary()之前,您是否可以更加主动和check the version所需的QT二进制文件?然后,您可以警告您的用户他们没有您的应用所需的版本,甚至可能提供指向他们的安装点的链接。

答案 5 :(得分:0)

您还可以使用清单文件对Windows进行检查。此文件包含有关已使用库版本的要求的信息。 msdn site上有更准确,更完整的信息。

查看this question about how to use LoadLibrary with a manifest file的答案。

The Qt documentation简要提到了VS2005的清单文件的用法;对于早期版本,您必须为自己创建它。