22.2.4 动态链接库函数
Win32中提供了有关动态链接库的函数。下面做个简要介绍。DisableThread LibraryCalls()函数关闭hLibModule句柄指定的动态链接库的dll_thread_attach和dll_thread_detach的通知消息。可以减少一些应用程序的工作代码区的大小。函数原型为:
- BOOL DisableThreadLibraryCalls(
- HMODULE hLibModule); // hLibModule参数指定了要关闭消息的模块
如果hLibModule指定的DLL有活动的静态线程局部存储区或者hLibModule是一个无效的模块句柄,则函数会失败。要获取具体的错误原因,可以通过调用GetLastError()函数获得。
DllMain是库定义函数名称的占位符,是DLL可选的入口方法。早期的SDK使用DllEntryPoint作为入口函数名。当构建DLL时,必须指定使用的实际名称。当进程和线程初始化或终止时,或调用LoadLibrary()和FreeLibrary()函数时,系统会调用此函数。函数原型是:
- BOOL WINAPI DllMain(
- HINSTANCE hinstDLL, // DLL模块的句柄
- DWORD fdwReason, // 调用函数的来源
- LPVOID lpvReserved // 预留
- );
其中,fdwReason参数指定DLL入口函数被调用的来源,取值如表22-1所示。
表22-1 入口函数来源
当系统使用dll_process_attach值调用DllMain()函数时,如果成功返回true,否则返回false。当进程使用LoadLibrary()函数调用DllMain()函数时,如果返回值为false,则LoadLibrary()函数返回NULL。当在进程初始化时调用DllMain()函数时,如果返回值为false,则进程会报告错误并终止进程。要获取更多的错误信息,可以使用GetLastError()函数获取。
FreeLibrary()函数减少装载的DLL模块的引用数目。当引用数目达到0时,模块将从调用进程的地址空间中卸载,并且句柄不再有效。
- BOOL FreeLibrary( HMODULE hLibModule) // 装载的库模块的句柄
每个进程为每个装载的库模块维护一个引用数目。每调用一次LoadLibrary()函数,引用数目增加一,每调用一次FreeLibrary()函数引用数目减一。因为装载时动态链接有一个引用数目,DLL模块在进程初始化装载。如果调用LoadLibrary()函数装载相同模块,则数目增加。
在卸载库模块以前,如果有入口函数,系统使用dll_process_detach值调用DLL的DllMain()函数使得DLL从进程中分离。这样使得DLL可以有机会清除当前进程分配的资源。在入口函数返回后,库模块从当前进程的地址空间中移除。
从DllMain()函数中调用FreeLibrary是不安全的。调用FreeLibrary()函数不会影响其他使用相同库模块的进程。FreeLibraryAndExitThread()函数会减少装载的DLL的引用数目一次,然后调用ExitThread()函数终止调用线程。此函数没有返回值。此函数给使用动态链接库创建和执行的线程一个安全的卸载DLL并终止它们的时机。函数原型为:
- VOID FreeLibraryAndExitThread(
- HMODULE hLibModule, // 要减少引用次数的动态链接库
- DWORD dwExitCode); // 线程退出代码
GetModuleFileName()函数返回执行文件包含的指定的模块的完整路径和文件名。函数原型为:
- DWORD GetModuleFileName(
- HMODULE hModule, // 要获取文件名的模块句柄
- LPTSTR lpFilename, // 接收模块路径的缓冲区的指针
- DWORD nSize ); // 缓冲区的大小
如果模块装载到两个进程中,在一个进程中的模块名称可能会与在另一个进程中的模块名称不同。如果文件已经映射到调用进程的地址空间中,则GetModuleHandle()函数返回指定模块的模块句柄。函数原型为:
- HMODULE GetModuleHandle( LPCTSTR lpModuleName) // 要获
取句柄的模块的名称地址
如果函数成功,则返回值为指定模块的句柄。如果函数失败,返回值为NULL。要获取更多的错误信息,可以调用GetLastError()函数获取。
GetProcAddress()函数返回导出的DLL函数的地址。函数原型为:
- FARPROC GetProcAddress( HMODULE hModule,
// DLL模块的句柄 - LPCSTR lpProcName); // 函数名
LoadLibrary()函数映射指定的可执行模块到调用进程的地址空间中。其函数原型为:
- HINSTANCE LoadLibrary( LPCTSTR lpLibFileName);
// 可执行模块的文件名的地址
如果函数成功,则返回模块的句柄。如果函数失败,则返回值为NULL。要获取更多的错误信息,可以通过GetLastError()函数获取。