LoadLibraryExA 函数 (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 仍可由其他进程打开。

此值可与 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 中 C:\Dir1\Lib1.dll, loading Lib1.dll with this value causes the system to search for 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
如果使用此值,则使用 AddDllDirectory 添加的目录或 SetDllDirectory 函数将搜索 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(thread)。 如果在 DLL 中使用此语法,则无法在 Windows Vista 之前的 Windows 版本中使用 LoadLibraryEx 显式加载 DLL。 如果 DLL 将显式加载,则必须使用线程本地存储函数,而不是 _declspec(thread)。 有关示例,请参阅 使用动态链接库中的线程本地存储

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

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

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

使用 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 函数建立的进程特定的搜索路径。 有关目录的列表及其搜索顺序,请参阅 Dynamic-Link 库搜索顺序

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

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

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

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

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

应用程序可以使用 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。

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

有关 DLL 安全问题的一般讨论,请参阅 Dynamic-Link 库安全性

例子

下面的代码示例演示如何调用 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 [仅限桌面应用]
目标平台 窗户
标头 libloaderapi.h (包括 Windows.h)
Kernel32.lib
DLL Kernel32.dll

另请参阅

DllMain

Dynamic-Link 库函数

Dynamic-Link 库搜索顺序

Dynamic-Link 库安全

FindResource

FreeLibrary

GetProcAddress

GetSystemDirectory

GetWindowsDirectory

LoadLibrary

LoadResource

OpenFile

Run-Time 动态链接

SearchPath

SetDllDirectory

SetErrorMode