LoadLibraryExA function (libloaderapi.h)

将指定的模块加载到调用进程的地址空间中。 指定的模块可能会导致加载其他模块。

语法

HMODULE LoadLibraryExA(
  [in] LPCSTR lpLibFileName,
       HANDLE hFile,
  [in] DWORD  dwFlags
);

参数

[in] lpLibFileName

一个字符串,指定要加载的模块的文件名。 此名称与库模块本身中存储的名称无关,如模块定义 (.def) 文件中 的 LIBRARY 关键字指定。

该模块可以是库模块, (.dll文件) 或可执行模块 (.exe文件) 。 如果指定的模块是可执行模块,则不会加载静态导入;而是加载模块,就像指定 了DONT_RESOLVE_DLL_REFERENCES 一样。 有关详细信息,请参阅 dwFlags 参数。

如果字符串指定没有路径的模块名称,并且省略文件扩展名,则函数会将默认库扩展名“.DLL”追加到模块名称。 若要防止函数将“.DLL”追加到模块名称,请在模块名称字符串中包含尾随点字符 (.) 。

如果字符串指定完全限定的路径,则函数仅搜索模块的路径。 指定路径时,请确保使用反斜杠 (\) ,而不是 (/) 正斜杠。 有关路径的详细信息,请参阅 命名文件、路径和命名空间

如果字符串指定了没有路径的模块名称,并且多个加载的模块具有相同的基本名称和扩展,则函数将返回第一次加载的模块的句柄。

如果字符串指定了没有路径的模块名称,并且尚未加载同名的模块,或者如果字符串指定具有相对路径的模块名称,则函数将搜索指定的模块。 如果加载指定的模块会导致系统加载其他关联的模块(即模块具有依赖项 () ,则函数还会搜索模块。 所搜索的目录及其搜索顺序取决于指定的路径和 dwFlags 参数。 有关详细信息,请参阅“备注”。

如果函数找不到模块或其依赖项之一,该函数将失败。

hFile

此参数留待将来使用。 它必须为 NULL

[in] dwFlags

加载模块时要执行的操作。 如果未指定任何标志,则此函数的行为与 LoadLibrary 函数的行为相同。 此参数的取值可为下列值之一:

含义
DONT_RESOLVE_DLL_REFERENCES
0x00000001
如果使用此值,并且可执行模块为 DLL,则系统不调用 DllMain 进行进程和线程初始化和终止。 此外,系统不会加载由指定模块引用的其他可执行模块。
注意 请勿使用此值;它仅用于向后兼容性。 如果计划仅访问 DLL 中的数据或资源,请使用 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVELOAD_LIBRARY_AS_IMAGE_RESOURCE 或两者。 否则,使用 LoadLibrary 函数将库加载为 DLL 或可执行模块。
 
LOAD_IGNORE_CODE_AUTHZ_LEVEL
0x00000010
如果使用此值,系统不会检查 AppLocker 规则或应用 DLL 的软件限制策略 。 此操作仅适用于要加载的 DLL,而不适用于其依赖项。 建议在安装过程中必须运行提取的 DLL 的安装程序中使用此值。

Windows Server 2008 R2 和 Windows 7: 在安装了 KB2532445 的系统上,调用方必须作为“LocalSystem”或“TrustedInstaller”运行;否则,系统将忽略此标志。 有关详细信息,请参阅帮助和支持知识库 https://support.microsoft.com/kb/2532445中的“通过在运行 Windows 7 或 Windows Server 2008 R2 的计算机上使用 Office 宏来规避 AppLocker 规则”。

Windows Server 2008、Windows Vista、Windows Server 2003 和 Windows XP: AppLocker 是在 Windows 7 和 Windows Server 2008 R2 中引入的。

LOAD_LIBRARY_AS_DATAFILE
0x00000002
如果使用此值,系统会将文件映射到调用进程的虚拟地址空间,就像它是数据文件一样。 不执行任何操作或准备执行映射的文件。 因此,不能使用此 DLL 调用 GetModuleFileNameGetModuleHandleGetProcAddress 等函数。 使用此值会导致写入只读内存以引发访问冲突。 如果要仅加载 DLL 以从中提取消息或资源,请使用此标志。

此值可用于 LOAD_LIBRARY_AS_IMAGE_RESOURCE。 有关详细信息,请参阅“备注”。

LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
0x00000040
LOAD_LIBRARY_AS_DATAFILE类似,只不过 DLL 文件是使用调用进程的独占写入访问权限打开的。 其他进程无法在使用 DLL 文件时打开 DLL 文件进行写入访问。 但是,DLL 仍可由其他进程打开。

此值可用于 LOAD_LIBRARY_AS_IMAGE_RESOURCE。 有关详细信息,请参阅“备注”。

Windows Server 2003 和 Windows XP: 在 Windows Vista 之前不支持此值。

LOAD_LIBRARY_AS_IMAGE_RESOURCE
0x00000020
如果使用此值,系统会将文件映射到进程的虚拟地址空间作为图像文件。 但是,加载程序不会加载静态导入或执行其他常规初始化步骤。 如果要仅加载 DLL 以从中提取消息或资源,请使用此标志。

除非应用程序依赖于具有图像内存中布局的文件,否则此值应与 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVELOAD_LIBRARY_AS_DATAFILE一起使用。 有关详细信息,请参见“备注”部分。

Windows Server 2003 和 Windows XP: 在 Windows Vista 之前不支持此值。

LOAD_LIBRARY_SEARCH_APPLICATION_DIR
0x00000200
如果使用此值,则会搜索应用程序的安装目录来查找 DLL 及其依赖项。 不会搜索标准搜索路径中的目录。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。

Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008: 此值要求安装 KB2533623

Windows Server 2003 和 Windows XP: 不支持此值。

LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
0x00001000
此值是 LOAD_LIBRARY_SEARCH_APPLICATION_DIRLOAD_LIBRARY_SEARCH_SYSTEM32LOAD_LIBRARY_SEARCH_USER_DIRS的组合。 不会搜索标准搜索路径中的目录。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。

此值表示应用程序在其 DLL 搜索路径中应包含的建议最大目录数。

Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008: 此值要求安装 KB2533623

Windows Server 2003 和 Windows XP: 不支持此值。

LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
0x00000100
如果使用此值,则包含 DLL 的目录会暂时添加到搜索 DLL 依赖项的目录列表的开头。 不会搜索标准搜索路径中的目录。

lpFileName 参数必须指定完全限定的路径。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。

例如,如果Lib2.dll是C:\Dir1\Lib1.dll的依赖项,则使用此值加载Lib1.dll会导致系统仅在 C:\Dir1 中搜索Lib2.dll。 若要在 C:\Dir1 中搜索Lib2.dll以及 DLL 搜索路径中的所有目录,请结合使用此值与 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS

Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008: 此值要求安装 KB2533623

Windows Server 2003 和 Windows XP: 不支持此值。

LOAD_LIBRARY_SEARCH_SYSTEM32
0x00000800
如果使用此值,则会搜索 %windows%\system32 来查找 DLL 及其依赖项。 不会搜索标准搜索路径中的目录。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。

Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008: 此值要求安装 KB2533623

Windows Server 2003 和 Windows XP: 不支持此值。

LOAD_LIBRARY_SEARCH_USER_DIRS
0x00000400
如果使用此值,则使用 AddDllDirectorySetDllDirectory 函数添加的目录将搜索 DLL 及其依赖项。 如果添加了多个目录,则未指定搜索目录的顺序。 不会搜索标准搜索路径中的目录。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。

Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008: 此值要求安装 KB2533623

Windows Server 2003 和 Windows XP: 不支持此值。

LOAD_WITH_ALTERED_SEARCH_PATH
0x00000008
如果使用此值, lpFileName 指定绝对路径,则系统会使用“备注”部分中讨论的备用文件搜索策略来查找指定模块导致加载的关联可执行模块。 如果使用此值, lpFileName 指定相对路径,则行为未定义。

如果未使用此值,或者 lpFileName 未指定路径,则系统会使用“备注”部分中讨论的标准搜索策略来查找指定模块导致加载的关联可执行模块。

此值不能与任何 LOAD_LIBRARY_SEARCH 标志组合在一起。

LOAD_LIBRARY_REQUIRE_SIGNED_TARGET
0x00000080
指定必须在加载时检查二进制映像的数字签名。

此值需要Windows 8.1、Windows 10或更高版本。

LOAD_LIBRARY_SAFE_CURRENT_DIRS
0x00002000
如果使用此值,则仅当 DLL 位于安全加载列表中的目录下时,才允许从当前目录加载 DLL 执行。

返回值

如果函数成功,则返回值是已加载模块的句柄。

如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。

注解

LoadLibraryEx 函数与 LoadLibrary 函数非常相似。 区别包括 LoadLibraryEx 提供的一组可选行为:

  • LoadLibraryEx 可以在不调用 DLL 的 DllMain 函数的情况下加载 DLL 模块。
  • LoadLibraryEx 可以采用针对永远不会执行模块的情况进行优化的方式加载模块,就像是数据文件一样加载模块。
  • LoadLibraryEx 可以使用两种搜索策略之一来查找模块及其关联的模块,也可以搜索特定于进程的目录集。
通过设置 dwFlags 参数来选择这些可选行为;如果 dwFlags 为零, 则 LoadLibraryEx 的行为与 LoadLibrary 相同。

调用进程可以使用 LoadLibraryEx 返回的句柄来标识 对 GetProcAddressFindResourceLoadResource 函数的调用中的模块。

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

DllMain 调用 LoadLibraryEx 是不安全的。 有关详细信息,请参阅 DllMain 中的“备注”部分。

Visual C++: Visual C++ 编译器支持用于声明线程本地变量的语法: _declspec (线程) 。 如果在 DLL 中使用此语法,则无法在 Windows Vista 之前的 Windows 版本中使用 LoadLibraryEx 显式加载 DLL。 如果 DLL 将显式加载,则必须使用线程本地存储函数,而不是 _declspec (线程) 。 有关示例,请参阅 在动态链接库中使用线程本地存储

将 DLL 作为数据文件或图像资源加载

LOAD_LIBRARY_AS_DATAFILELOAD_LIBRARY_AS_DATAFILE_EXCLUSIVELOAD_LIBRARY_AS_IMAGE_RESOURCE值会影响每个进程引用计数和指定模块的加载。 如果为 dwFlags 参数指定了其中任何值,则加载程序将检查该模块是否已由进程作为可执行 DLL 加载。 如果是这样,则表示模块已映射到调用进程的虚拟地址空间。 在这种情况下, LoadLibraryEx 返回 DLL 的句柄,并递增 DLL 引用计数。 如果 DLL 模块尚未作为 DLL 加载,系统会将模块映射为数据或图像文件,而不是作为可执行 DLL。 在这种情况下, LoadLibraryEx 返回已加载的数据或图像文件的句柄,但不递增模块的引用计数,并且不会使模块对 CreateToolhelp32SnapshotEnumProcessModules 等函数可见。

如果为具有 LOAD_LIBRARY_AS_DATAFILELOAD_LIBRARY_AS_DATAFILE_EXCLUSIVELOAD_LIBRARY_AS_IMAGE_RESOURCE 的同一文件调用了两次 LoadLibraryEx,则会为该文件创建两个单独的映射。

使用 LOAD_LIBRARY_AS_IMAGE_RESOURCE 值时,使用可移植可执行文件 (PE) 节对齐扩展将模块作为映像加载。 (RVA) 相对虚拟地址不必映射到磁盘地址,因此可以从模块更快地检索资源。 指定 LOAD_LIBRARY_AS_IMAGE_RESOURCE 可防止加载模块时修改其他进程。

除非应用程序依赖于特定的图像映射特征, 否则LOAD_LIBRARY_AS_IMAGE_RESOURCE 值应与 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVELOAD_LIBRARY_AS_DATAFILE一起使用。 这样,加载程序就可以选择是将模块加载为图像资源还是数据文件,选择允许系统更有效地共享页面的选项。 FindResource 等资源函数可以使用任一映射。

若要确定模块的加载方式,请使用以下宏之一测试 LoadLibraryEx 返回的句柄。

#define LDR_IS_DATAFILE(handle)      (((ULONG_PTR)(handle)) &  (ULONG_PTR)1)
#define LDR_IS_IMAGEMAPPING(handle)  (((ULONG_PTR)(handle)) & (ULONG_PTR)2)
#define LDR_IS_RESOURCE(handle)      (LDR_IS_IMAGEMAPPING(handle) || LDR_IS_DATAFILE(handle))

下表描述了这些宏。

描述
LDR_IS_DATAFILE (句柄) 如果此宏返回 TRUE,则模块作为数据文件加载 (LOAD_LIBRARY_AS_DATAFILELOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
LDR_IS_IMAGEMAPPING (句柄) 如果此宏返回 TRUE,则模块作为图像文件加载 (LOAD_LIBRARY_AS_IMAGE_RESOURCE) 。
LDR_IS_RESOURCE (句柄) 如果此宏返回 TRUE,则模块作为数据文件或图像文件加载。
 

使用 FreeLibrary 函数释放加载的模块,无论是否加载模块导致其引用计数递增。 如果模块作为数据或图像文件加载,则会销毁映射,但引用计数不会递减。 否则,DLL 引用计数会递减。 因此,使用 LoadLibraryEx 返回的任何句柄调用 FreeLibrary 是安全的。

搜索 DLL 和依赖项

搜索路径是搜索 DLL 的目录集。 LoadLibraryEx 函数可以使用标准搜索路径或更改的搜索路径搜索 DLL,也可以使用使用 SetDefaultDllDirectoriesAddDllDirectory 函数建立的进程特定的搜索路径。 有关目录的列表及其搜索顺序,请参阅 动态链接库搜索顺序

LoadLibraryEx 函数在以下情况下使用标准搜索路径:

  • 文件名未指定路径,并且基文件名与加载的模块的基本文件名不匹配,并且未使用 任何LOAD_LIBRARY_SEARCH 标志。
  • 指定了路径,但未使用 LOAD_WITH_ALTERED_SEARCH_PATH
  • 应用程序未使用 SetDefaultDllDirectories 为进程指定默认 DLL 搜索路径。

如果 lpFileName 指定相对路径,则整个相对路径将追加到 DLL 搜索路径中的每个令牌。 若要从相对路径加载模块而不搜索任何其他路径,请使用 GetFullPathName 获取非关系路径,并使用非关系路径调用 LoadLibraryEx 。 如果模块作为数据文件加载,并且相对路径以“.”或“..”开头,则相对路径被视为绝对路径。

如果 lpFileName 指定绝对路径, dwFlags 设置为 LOAD_WITH_ALTERED_SEARCH_PATH则 LoadLibraryEx 使用更改的搜索路径。 设置 LOAD_WITH_ALTERED_SEARCH_PATH 标志时,行为未定义, lpFileName 指定相对路径。

SetDllDirectory 函数可用于修改搜索路径。 此解决方案优于使用 SetCurrentDirectory 或硬编码 DLL 的完整路径。 但是,请注意,使用 SetDllDirectory 可有效禁用安全 DLL 搜索模式,而指定的目录位于搜索路径中,并且不是线程安全的。 如果可能,最好使用 AddDllDirectory 修改默认进程搜索路径。 有关详细信息,请参阅动态链接库搜索顺序

应用程序可以使用 LOAD_LIBRARY_SEARCH_* 标志指定要搜索单个 LoadLibraryEx 调用的目录。 如果指定了多个 LOAD_LIBRARY_SEARCH 标志,则按以下顺序搜索目录:

  • 包含 DLL (的目录LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) 。 此目录仅搜索要加载的 DLL 的依赖项。
  • 应用程序目录 (LOAD_LIBRARY_SEARCH_APPLICATION_DIR) 。
  • 使用 AddDllDirectory 函数显式添加到应用程序搜索路径的路径 (LOAD_LIBRARY_SEARCH_USER_DIRS ) SetDllDirectory 函数。 如果添加了多个路径,则未指定搜索路径的顺序。
  • System32 目录 (LOAD_LIBRARY_SEARCH_SYSTEM32) 。

Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008: 已安装 KB2533623 的系统上提供了LOAD_LIBRARY_SEARCH_标志。 若要确定标志是否可用,请使用 GetProcAddress 获取 AddDllDirectory、RemoveDllDirectorySetDefaultDllDirectories 函数的地址。 如果 GetProcAddress 成功, LOAD_LIBRARY_SEARCH_ 标志可与 LoadLibraryEx 一起使用。

如果应用程序已使用 SetDefaultDllDirectories 函数为进程建立 DLL 搜索路径,并且未使用 任何 LOAD_LIBRARY_SEARCH_* 标志, LoadLibraryEx 函数将使用进程 DLL 搜索路径而不是标准搜索路径。

如果指定了路径,并且存在与应用程序关联的重定向文件, LoadLibraryEx 函数将在应用程序目录中搜索模块。 如果模块存在于应用程序目录中, LoadLibraryEx 将忽略路径规范,并从应用程序目录中加载模块。 如果应用程序目录中不存在该模块,函数将从指定的目录中加载该模块。 有关详细信息,请参阅 动态链接库重定向

如果使用不带路径规范的程序集的名称调用 LoadLibraryEx ,并且程序集在系统兼容的清单中列出,则调用会自动重定向到并排程序集。

安全备注

LOAD_LIBRARY_AS_DATAFILE 不会阻止其他进程在加载模块时修改模块。 由于这会使应用程序更安全,因此在将模块加载为数据文件时,应使用 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 而不是 LOAD_LIBRARY_AS_DATAFILE ,除非专门需要使用 LOAD_LIBRARY_AS_DATAFILE。 指定 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 可防止加载模块时修改模块。 不要在同一个调用中指定 LOAD_LIBRARY_AS_DATAFILELOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE

请勿使用 SearchPath 函数为后续 LoadLibraryEx 调用检索 DLL 的路径。 SearchPath 函数使用与 LoadLibraryEx 不同的搜索顺序,并且它不使用安全进程搜索模式,除非使用 BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE 调用 SetSearchPathMode 显式启用此模式。 因此, SearchPath 可能首先搜索用户的当前工作目录以获取指定的 DLL。 如果攻击者已将 DLL 的恶意版本复制到当前工作目录中, 则 SearchPath 检索的路径将指向恶意 DLL,然后 加载 LoadLibraryEx

不要根据搜索 DLL 的 LoadLibraryEx 调用对操作系统版本做出假设。 如果应用程序在 DLL 合法不存在的环境中运行,但 DLL 的恶意版本位于搜索路径中,可能会加载 DLL 的恶意版本。 请改用“ 获取系统版本”中所述的建议技术。

有关 DLL 安全问题的一般讨论,请参阅 动态链接库安全性

示例

下面的代码示例演示了对 LoadLibraryExA 的调用。

//Load the FMAPI DLL
hLib = ::LoadLibraryEx(L"fmapi.dll", NULL, NULL);
if ( !hLib )
{
      wprintf(L"Could not load fmapi.dll, Error #%d.\n", GetLastError());
      return;
}

有关其他示例,请参阅 查找错误代码号的文本

注意

libloaderapi.h 标头将 LoadLibraryEx 定义为别名,该别名根据 UNICODE 预处理器常量的定义自动选择此函数的 ANSI 或 Unicode 版本。 将非中性编码别名与非非编码的代码混合使用可能会导致编译或运行时错误不匹配。 有关详细信息,请参阅 函数原型的约定

要求

   
最低受支持的客户端 Windows XP [仅限桌面应用]
最低受支持的服务器 Windows Server 2003 [仅限桌面应用]
目标平台 Windows
标头 libloaderapi.h (包括 Windows.h)
Library Kernel32.lib
DLL Kernel32.dll

另请参阅

DllMain

动态链接库函数

动态链接库搜索顺序

动态链接库安全性

FindResource

FreeLibrary

GetProcAddress

GetSystemDirectory

GetWindowsDirectory

LoadLibrary

LoadResource

OpenFile

运行时动态链接

SearchPath

SetDllDirectory

SetErrorMode