设为首页 加入收藏

TOP

22.2.2 DLL的导出
2013-10-07 13:10:57 来源: 作者: 【 】 浏览:60
Tags:22.2.2 DLL 导出

22.2.2  DLL的导出

DLL的导出表可以通过工具DUMPBIN使用/EXPORTS开关查看。从DLL中导出函数有两种方法:

创建模块定义文件.DEF文件(module-definition file),是包含一条或多条描述DLL不同属性的模块语句的文本文件。当构建DLL时,使用此DEF文件,可以按照函数的顺序号而不是名称从DLL中导出函数。

在函数定义中使用__declspec(dllexport)。如果不使用此关键字,则必须使用DEF文件。

如果DLL在多线程应用程序中使用时,则需要DLL仅链接支持多线程的库,以使得DLL是"线程安全"。同样,需要确保访问全局数据的同步性,有关多线程的开发在第23章会详细介绍。

导入库(.LIB)文件包含链接器需要的导出DLL函数的外部引用需要的信息,因此,系统可以在运行时定位到指定的DLL和导出的DLL函数。如调用CreateWindow()函数,用户必须在程序中链接导入库USER32.LIB,因为CreateWindow在系统DLL中,而文件USER32.DLL用于解决调用CreateWindow()的导入库。

每个DLL像应用程序一样必须有一个入口。当进程或线程装载或卸载DLL时,系统调用入口函数。如果程序像C运行库一样链接DLL到库中,则会提供一个入口函数,并允许提供一个独立的初始化函数。其中,DllMain是一个用户自定义函数的占位符。当构建DLL时,用户必须指定使用的实际名称。系统在下面4种情况下调用入口函数。

进程装载DLL时。使用装载时动态链接的进程,DLL在进程初始化时装载。对于使用运行时链接的进程,DLL在LoadLibrary()或LoadLibraryEx()函数返回时装载。

进程卸载DLL时。当进程终止或调用FreeLibrary()函数时,DLL卸载,并且引用数目变成0。如果进程是调用TerminateProcess()或TerminateThread()函数终止的,系统不会调用DLL的入口。

已经装载DLL的进程创建新线程时。用户可以使用DisableThreadLibraryCalls()函数关闭线程创建时的通知。

已经装载DLL的进程的线程正常终止时,但不是使用TerminateThread()或TerminateProcess()。但进程卸载DLL时,整个进程仅调用一次入口函数,而不是进程的每个存在的线程调用一次。用户可以使用DisableThreadLibraryCalls()函数关闭线程终止时的通知。

不管是哪种情况下调用DLL入口,同一时间只能有一个线程调用入口函数。系统在调用函数的进程或线程上下文中调用入口函数。允许DLL使用自己的入口函数在调用进程的虚拟地址控件中分配内存,或者是打开可访问进程的句柄。入口函数也可以私自为使用线程本地存储(TLS)的新线程分配内存。

DLL入口函数必须使用标准调用规范声明。在入口函数体中,用户可以处理DLL入口函数被调用情况的任何组合。一般情况下,入口函数应该只完成简单的初始化任务,如建立线程本地存储(TLS),创建同步对象和打开文件。在入口函数中不能调用LoadLibrary()函数,因为可能在DLL装载顺序中产生依赖循环,导致DLL在系统执行初始化代码前使用。同样,在入口函数中也不能调用FreeLibrary()函数,因为这可能导致DLL在系统已经执行终止代码后被使用。

调用除了TLS的Win32函数,同步和文件函数也可能导致难诊断的问题。如调用User、Shell和COM函数会导致访问违反错误,因为在这些DLL中一些函数调用LoadLibrary()函数装载其他系统组件。下面代码列出了DLL入口函数的结构。

  1. BOOL APIENTRY DllMain( HANDLE hModule, 
    DWORD ul_reason_for_call, LPVOID lpReserved )  
  2. {  
  3.     switch (ul_reason_for_call)  
  4.     {   // 根据调用DLL的来源完成相应的工作  
  5.     case DLL_PROCESS_ATTACH:  
  6.         // 对于每个新进程,初始化一次。如果DLL装载失败,返回false  
  7.     case DLL_THREAD_ATTACH:  
  8.         // 执行线程指定初始化  
  9.     case DLL_THREAD_DETACH:  
  10.         // 执行线程指定的清除工作  
  11.     case DLL_PROCESS_DETACH:  
  12.         // 执行任何需要的清除工作  
  13.         break;  
  14.     }  
  15.     return true;        // 进程装载入口函数成功完成  

当DLL入口函数在进程装载时调用,函数返回true表示成功。对于进程使用装载时链接,返回值false引起进程初始化失败和进程终止。对于进程使用运行时链接,返回值false表示LoadLibrary()或LoadLibraryEx()函数返回NULL,表示失败。其他调用入口函数的情况,返回值可以忽略。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇22.2.4 动态链接库函数 下一篇22.2.11 禁止使用Alt+F4键关闭窗..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: