《Windows核心编程》读书心得——DLL(6)

DLL中的内存空间DLL中的函数创建的任何对象,都为调用线程或调用进程所拥有,DLL绝不会拥有任何对象。(例如,DLL中的一个函数调用了VirtuallAlloc(),系统会从调用进程的地址空间中预订地址空间区域)。

导出:编译器看到_declspec(dllexport)修饰符修饰的变量,会在生成的.obj文件中嵌入一些额外信息。当连接器链接dll所有.obj文件时,会解析这些信息。链接器还会在生成的DLL文件中嵌入一个导出段,其中列出了导出的变量、函数和类的符号名。同时,链接器还会保存相对虚拟地址(RVA),表示每个符号可以在DLL模块中的何处找到。

导入:链接器在导入符号时,会在生成的可执行模块中嵌入一个导入段,其中列出了模块所需的DLL模块,以及它从每个DLL模块中引用的符号。

加载DLL时的路径搜索顺序:

(1)包含可执行文件的目录;

(2)Windows系统目录;

(3)16位系统目录,即Windows目录的System子目录;

(4)Windows目录;

(5)进程当前目录;

(6)PATH环境变量中所列出的目录。

DLL载入的方式:

(1)隐式载入:在应用程序的源代码中引用DLL所包含的符号,在程序运行的时候隐式载入(并链接)所需的DLL;

(2)显式载入:程序运行时显式载入DLL并显式地与想要输出的符号进行链接。

LoadLibrary():显式载入DLL; FreeLibrary():显式卸载DLL。系统对DLL有一个计数,当调用LoadLibrary()时,计数加1;调用FreeLibrary()时,计数减1。

DLL的入口点函数DlllMain():

(1)系统第一次将DLL映射到进程地址空间时,调用DllMain()函数,并为fdwReason参数传入DLL_PROCESS_ATTACH;

(2)系统将DLL从进程地址空间中撤销映射时,调用DllMain()函数,并为fdwReason参数传入DLL_PROCESS_DETACH;(DLL可能阻碍进程终止,因为当DllMain函数收到DLL_PROCESS_DETACH时,可能进入无限循环,只有当每一DLL收到该通知后,操作系统才真正终止进程)

(3)DLL_THREAD_ATTACH、DLL_THREAD_DETACH:类似于以上,在线程创建和退出时收到。

转发器:转发器是DLL输出段中的一个条目,用来将一个函数调用转发到另一个DLL的另一个函数。

可以在自己的DLL中使用函数转发器,例如:#pragma comment(linker, "/export:SomFunc=DllWork.SomeOtherFunc")。 // 转发给DllWork.dll中的SomeOtherFunc函数来执行。

注意事项:

(1)在编写C和C++代码时,为了避免C++编译器对函数和变量进行改名,必须加上extern " C"

(2)为保证Microsoft工具包开发的DLL能够与其他编译器厂商的工具包链接,需要告诉Microsoft编译器不要对导出函数名进行改编,常用的方法是:为工程创建一个.def文件,并在.def文件中包含EXPORTS段

EXPORTS

          MyFunc

这样,链接器会使用.def文件定义的名称;

(3)DLL中申请的内存最好在DLL中释放;

(4)尽量保证调用LoadLibrary()和FreeLibrary()的是同一个线程;




至此,《Windows核心编程》最核心、最常用的知识点都已经讲完了,终于可以歇一口气了,呵呵!


你可能感兴趣的:(编程,windows,Microsoft,读书,dll,编译器)