Run-Time动态链接
当应用程序调用 LoadLibrary 或LoadLibraryEx 函数时,系统会尝试找到 DLL (以获取详细信息,请参阅 动态链接库搜索顺序) 。 如果搜索成功,系统将 DLL 模块映射到进程的虚拟地址空间,并递增引用计数。 如果对 LoadLibrary 或 LoadLibraryEx 的调用指定了一个 DLL,其代码已映射到调用进程的虚拟地址空间,则函数只需返回 DLL 的句柄并递增 DLL 引用计数。 请注意,两个 DLL 具有相同的基本文件名和扩展名,但位于不同的目录中,不被视为同一 DLL。
系统在调用 LoadLibrary 或 LoadLibraryEx 的线程上下文中调用入口点函数。 如果进程已通过对 LoadLibrary 或 LoadLibraryEx 的调用(没有对 FreeLibrary 函数的相应调用)加载 DLL,则不会调用入口点函数。
如果系统找不到 DLL,或者入口点函数返回 FALSE, 则 LoadLibrary 或 LoadLibraryEx 返回 NULL。 如果 LoadLibrary 或 LoadLibraryEx 成功,它将返回 DLL 模块的句柄。 此过程可以使用此句柄在对 GetProcAddress、FreeLibrary 或 FreeLibraryAndExitThread 函数的调用中标识 DLL。
GetModuleHandle 函数返回 GetProcAddress、FreeLibrary 或 FreeLibraryAndExitThread 中使用的句柄。 仅当 DLL 模块已通过加载时链接或之前调用 LoadLibrary 或LoadLibraryEx 映射到进程的地址空间时,GetModuleHandle 函数才成功。 与 LoadLibrary 或 LoadLibraryEx 不同, GetModuleHandle 不会递增模块引用计数。 GetModuleFileName 函数检索与 GetModuleHandle、LoadLibrary 或 LoadLibraryEx 返回的句柄关联的模块的完整路径。
此过程可以使用 GetProcAddress 通过 LoadLibrary 或 LoadLibraryEx、GetModuleHandle 返回的 DLL 模块句柄获取 DLL 中导出函数的地址。
不再需要 DLL 模块时,该过程可以调用 FreeLibrary 或 FreeLibraryAndExitThread。 如果引用计数为零,这些函数会减少模块引用计数,并从进程的虚拟地址空间取消映射 DLL 代码。
运行时动态链接使进程能够继续运行,即使 DLL 不可用也是如此。 然后,该过程可以使用备用方法来实现其目标。 例如,如果某个进程找不到一个 DLL,则可以尝试使用另一个 DLL,也可以通知用户出现错误。 如果用户可以提供缺失 DLL 的完整路径,则进程可以使用此信息加载 DLL,即使它不在普通搜索路径中也是如此。 这种情况与加载时链接形成鲜明对比,如果系统找不到 DLL,则系统只会终止进程。
如果 DLL 使用 DllMain 函数对进程的每个线程执行初始化,则运行时动态链接可能会导致问题,因为调用 LoadLibrary 或 LoadLibraryEx 之前存在的线程不会调用入口点。 有关如何处理此问题的示例,请参阅 Dynamic-Link 库中的“使用线程本地存储”。
相关主题