LoadLibrary():如何处理无效的DLL?

时间:2014-12-23 12:32:44

标签: c++ winapi dll

我的应用程序严重依赖插件。

在启动时,它会扫描目录中的DLL并逐个加载它们,寻找实现某个导出函数的目录。但是 - 如果有人要将不同类型的文件重命名为* .dll并将其放在目录中,则该文件也将由LoadLibrary()加载。 LoadLibrary()不喜欢这样,并产生错误[对话框]。

有没有办法可以简单地忽略无效/不兼容的.dll文件(在通话之前检测它们或让LoadLibrary()返回NULL而不是投掷适合的文件)?

3 个答案:

答案 0 :(得分:2)

您需要为流程设置错误模式。在启动时一劳永逸地做到这一点:

UINT oldMode = SetErrorMode(0);
SetErrorMode(oldMode | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);

在您设置了过程错误模式后,当LoadLibrary失败时,不会显示任何对话框,LoadLibrary将返回NULL

documentation说:

  

最佳做法是所有应用程序在启动时使用参数SEM_FAILCRITICALERRORS调用流程范围的SetErrorMode函数。这是为了防止错误模式对话框挂起应用程序。

我还建议添加SEM_NOOPENFILEERRORBOX,原因我认为应该是显而易见的。

答案 1 :(得分:1)

http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx

  

说明

     

要在DLL加载期间启用或禁用加载程序显示的错误消息,请使用SetErrorMode函数。

完成后不要忘记恢复错误模式。

如果你想自己这样做,你可以用原始方式解析PE头来识别坏DLL文件的明显情况,但是如果没有完整的PE加载器,确实无法确定DLL是否有效和可加载这需要大量的工作,并已内置到操作系统中。

答案 2 :(得分:1)

在djgandy和Remy Lebeau的评论中反馈后更新了答案。现在一个完整的 功能,在入口处更好地保留错误模式:

// This function will load the DLL named by pszPath if it is a valid library.
// If the function succeeds, it will return a valid HMODULE for the DLL.  This
// handle should be passed to FreeLibrary when it is no longer needed.
// If the function fails, it will return NULL and no annoying dialog boxes will 
// be displayed.  It is therefore up to the caller to notify the user about what 
// happened or take any other appropriate action.  The reason for failure can
// be obtained from GetLastError().  Common problems:
//   ERROR_BAD_EXE_FORMAT        - Bad DLL (tested function with text file)
//   ERROR_MOD_NOT_FOUND         - Missing DLL (tested with file that did not exist)
// 
// Module-loading functions can return several other errors, look at winerror.h
// list starting at ERROR_INVALID_MODULETYPE
//
// Obviously, since it's just a wrapper around LoadLibrary this function is not
// safe to call from DllMain.
//
// NB: GetErrorMode() is only available on Vista / Server 2003 or later.
HMODULE LoadLibraryIfValid(LPCTSTR pszPath)
{
  HMODULE hModule = NULL;

    UINT prevErrorMode = GetErrorMode();
    SetErrorMode(prevErrorMode | SEM_FAILCRITICALERRORS);
    hModule = LoadLibrary(pszPath);
    SetErrorMode(prevErrorMode);

  return hModule;
}

如果定位到Windows 7 / Server 2008 R2或更高版本,则为Get / SetThreadErrorMode() 功能可用,但可能不值得,甚至是一个很好的选择 (在下面的评论中讨论)

如果有人关心把时间花在它上面(我确定不要),那就是 对于kernel32和,可以使用GetModuleHandle轻松编写此函数 GetProcAddress与早期版本的Windows兼容 为支持它的平台提供全局/每线程错误模式选项 (真的没有意义,因为它只会在一次通话期间发生变化)。

这是我生命中最大的评论与代码比率。