LoadLibraryExA function (libloaderapi.h)

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

语法

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

参数

[in] lpLibFileName

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

该模块可以是 (.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 仍可由其他进程打开。

此值可与 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 模块,而无需调用 DLL 的 DllMain 函数。
  • 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: LOAD_LIBRARY_SEARCH_标志在安装了 KB2533623 的系统上可用。 若要确定标志是否可用,请使用 GetProcAddress 获取 AddDllDirectoryRemoveDllDirectorySetDefaultDllDirectories 函数的地址。 如果 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 函数检索 DLL 的路径,以便进行后续 LoadLibraryEx 调用。 SearchPath 函数使用的搜索顺序与 LoadLibraryEx 不同,并且它不使用安全进程搜索模式,除非使用 BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE 调用 SetSearchPathMode 显式启用。 因此, SearchPath 可能首先搜索用户当前工作目录以查找指定的 DLL。 如果攻击者已将 DLL 的恶意版本复制到当前工作目录中, SearchPath 检索到的路径将指向恶意 DLL, 然后 LoadLibraryEx 将加载该 DLL。

不要基于搜索 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