1. DllMain是DLL的入口点函数,不是输出函数。入口点函数是可选的,某些纯资源DLL就不需要入口点函数。入口点函数名称也不一定是DllMain,只不过默认是DllMain,可以通过编译选项来指定名称。对于每个进程,首次加载一个动态库(不管它之前是否被其他进程加载过)都回调用到DLLMain一次并传递参数DLL_PROCESS_ATTACH. 并且已经加载并且没有释放的动态库在线程中又重新加载时就不会调用DLLMain,只是简单的增加一下引用计数.
当一个动态库被加载时也就是调用LoadLibrary()函数调用时系统根据目录优先顺序找到该动态库,将其映射到进程地址空间.然后系统使用LoadLibrary或LoadLibraryEx的线程中用DLL_PROCESS_ATTACH标志来调用DLLMain()函数,DLLMain()函数处理完通知以后LoadLibrary()函数也返回.进程可以继续执行.
2. AFX_MANAGE_STATE(AfxGetStaticModuleState())宏只是MFC制作的DLL才会有,它的实质是在导出函数被调用的开始就保存旧的当前模块句柄,把当前DLL的模块句柄设置成当前模块句柄,在函数退出时再恢复保存的模块句柄。切换模块句柄的作用主要是方便访问模块中的资源。DllMain中无需做模块句柄切换,唯一要做的事情就是保存DLL自身的模块句柄(参数传递进来的)。
3. vc向导生成的DLL已经帮你预备好了DllMain,你可以修改它,也可以直接使用。
4. DllMain会在多处被调用。
a)初次装载DLL时,无论隐式加载还是LoadLibrary显式加载时都会自动调用DllMain,第二个参数是DLL_PROCESS_ATTACH
b)进程加载DLL后,每次创建一个线程,都会再调用DllMain一次,第二个参数是DLL_THREAD_ATTACH
c)进程加载DLL后,每次结束一个线程,都会再调用DllMain一次,第二个参数是DLL_THREAD_DETACH
d)进程卸载DLL时,无论隐式卸载还是FreeLibrary显式卸载时都会自动调用DllMain,第二个参数是DLL_PROCESS_DETACH
e)假如进程用LOAD_LIBRARY_AS_DATAFILE标志调用LoadLibraryEx来加载DLL,则永远不会调用DllMain
f)DLLMain函数不仅在将DLL链接加载到进程时被调用,在DLL模块与进程分离时(以及其它时候)也被调用
5. 静态变量或者全局变量的构造函数是在DllMain之前被调用的。
6. 应用程序导入函数与DLL文件中的导出函数进行链接有两种方式:隐式链接和显式链接。所谓的隐式链接是指在应用程序中不需指明DLL文件的实际存储路径,程序员不需关心DLL文件的实际装载。而显式链接与此相反。
采用隐式链接方式,程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件。该文件包含了每一个DLL导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。当程序员通过静态链接方式编译生成应用程序时,应用程序中的调用函数与LIB文件中导出符号相匹配,这些符号或标识号进入到生成的EXE文件中。LIB文件中也包含了对应的DLL文件名(但不是完全的路径名),链接程序将其存储在EXE文件内部。当应用程序运行过程中需要加载DLL文件时,Windows根据这些信息发现并加载DLL,然后通过符号名或标识号实现对 DLL函数的动态链接。
显式链接方式对于集成化的开发语言(例如VB)比较适合。有了显式链接,程序员就不必再使用导入文件,而是直接调用Win32的LoadLibary函数,并指定DLL的路径作为参数。LoadLibary返回HINSTANCE参数,应用程序在调用GetProcAddress函数时使用这一参数。GetProcAddress函数将符号名或标识号转换为DLL内部的地址。
7. DLL文件中包含一个导出函数表。这些导出函数由它们的符号名和称为标识号的整数与外界联系起来。函数表中还包含了DLL中函数的地址。当应用程序加载DLL模块时时,它并不知道调用函数的实际地址,但它知道函数的符号名和标识号。动态链接过程在加载的DLL模块时动态建立一个函数调用与函数地址的对应表。如果重新编译和重建DLL文件,并不需要修改应用程序,除非你改变了导出函数的符号名和参数序列。
8. 在DLL代码中,必须像下面这样明确声明导出函数: __declspec(dllexport)intMyFunction(intn);在应用程序方面,要求像下面这样明确声明相应的输入函数: __declspec(dllimport)intMyFuncition(intn);
9. 当一个进程把DLL映射到它的地址空间时系统在该进程的地址空间你重新创建全局和静态变量的事例,不会与其它进程共享全局变量(16位版本以外).