载入时动态链接
系统启动一个使用载入时动态链接的程序时,使用连接程序放置的到文件的信息来定位进程所需要的DLL的名称。然后系统将在以下位置顺序搜寻DLL:
应用程序载入目录 当前目录 系统目录。通过GetSystemDirectory 函数可以得到。 16位系统目录。没有函数可以获取该目录,但它是被搜索的。 Windows Me/98/95: 目录不存在
Windows目录。通过GetWindowsDirectory 即可得到。 PATH环境变量中所列目录。 Windows Server 2003, Windows XP SP1: HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode 默认值为1 (当前目录在系统及Windows目录后进行搜索)。
Windows XP: 如果HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode 为1,当前目录在系统及Windows目录后搜索,但在PATH环境变量所列的目录前。默认值为0(当前目录在系统及Windows目录前进行搜索)。注意载入时该值会被缓存到每线程的基础部分。
如果系统不能找到所需DLL,就会终止进程并显示一个对话框报告错误信息。否则系统把DLL映射到进程的虚地址空间并增加DLL引用计数。
接着系统调用入口点函数,函数收到一个代码指出进程正在载入该DLL。如果入口点函数没有返回TRUE,系统将终止进程并报告错误。关于入口点函数的更多信息,请参见“动态链接库入口点函数”。
最后,系统用导入DLL函数的启动地址修改函数地址表。
DLL将在初始化期间映射到进程的虚地址空间,并仅在需要时载入到物理内存中。
运行时动态链接当应用程序调用LoadLibrary 或 LoadLibraryEx 函数时,系统就会尝试按载入时动态链接搜寻次序(参见载入时动态链接)定位DLL。如果找到,系统就把DLL模块映射到进程的虚地址空间中,并增加引用计数。如果调用LoadLibrary或LoadLibraryEx 时指定的DLL其代码已经映射到调用进程的虚地址空间,函数就会仅返回DLL的句柄并增加DLL引用计数。注意:两个具有相同文件名及扩展名但不在同一目录的DLL被认为不是同一个DLL。
系统在调用LoadLibrary或LoadLibraryEx的线程上下文中调用入口点函数。如果已经有进程通过调用LoadLibrary或LoadLibraryEx函数载入了DLL,且没有调用FreeLibrary,那么入口点函数就不会再次调用。
如果系统找不到DLL,又或者入口点函数返回FALSE,LoadLibrary或LoadLibraryEx将返回NULL。如果LoadLibrary或LoadLibraryEx调用成功,将返回DLL模块的句柄。进程可以通过该句柄标识调用GetProcAddress、FreeLibrary或FreeLibraryAndExitThread函数的DLL。
GetModuleHandle返回的句柄可以被GetProcAddress、FreeLibrary或FreeLibraryAndExitThread所使用。只有当DLL通过载入时链接或前次LoadLibrary、LoadLibraryEx调用已经映射到进程的地址空间时,GetModuleHandle才会成功。GetModuleHandle 不会增加模块的引用计数。GetModuleFileName 函数通过GetModuleHandle、LoadLibrary或LoadLibraryEx返回的句柄获取所关联的模块全路径。
模块可以通过GetModuleHandle、LoadLibrary或LoadLibraryEx返回的句柄,然后调用GetProcAddress得到DLL中出口函数的地址。
如果不再需要一个DLL模块的话,进程可以调用FreeLibrary或FreeLibraryAndExitThread(来释放)。这些函数将减少模块的引用计数,并且如果引用计数为0时,将从进程的虚地址空间取消该DLL的映射。
使用运行时动态链接即使DLL不可用的话,进程也能继续运行,然后进程可以通过一个变更方法达到最终目的。例如,如果进程不能找到一个DLL,它可以尝试另外一个或者向用户提示错误。如果用户可以提供丢失的DLL的全路径,进程就可以不管是否在正常的搜索路径中而使用该路径信息。然而如果是载入时链接的话,系统就会终止。
使用运行时动态链接时,如果DLL使用DllMain函数为进程的每个线程完成初始化就会产生问题,这是因为线程在LoadLibrary或LoadLibraryEx调用前入口点函数不被调用。关于如何处理该问题的示例,可参照“动态链接库的线程局部存储”。