《Windows Via C/C++》读书笔记之dll入口函数

《Windows Via C/C++》读书笔记之dll入口函数

一、DllMain()的一些知识与注意事项

*** DllMain()是大小写敏感的。  

*** DllMain()里面不要处理太复杂的操作,且由于加载顺序不定,只有调用Kernel32的某些函数是安全的。

参考文档:http://msdn.microsoft.com/en-us/windows/hardware/gg487379.aspx
The following tasks are safe to perform within DllMain:
• Initialize static data structures and members at compile time.
• Create and initialize synchronization objects.
• Allocate memory and initialize dynamic data structures (avoiding the functions listed above.)
• Set up thread local storage (TLS).
• Open, read from, and write to files.
• Call functions in Kernel32.dll (except the functions that are listed above).
• Set global pointers to NULL, putting off the initialization of dynamic members. In Microsoft Windows Vista™, you can use the one-time initialization functions to ensure that a block of code is executed only once in a multithreaded environment.

 

*** DLL_PROCESS_ATTACH: 进程第一次加载时通知

DLL_PROCESS_ATTACH仅在dll第一次被加载时通知。

隐式链接中,系统将exe和其所需的dll加载进地址空间后,创建主线程(Primary Thread),由主线程调用各个dll的DllMain(),然后调用exe的main()。

动态加载时,由调用LoadLibrary()的线程执行DllMain()。

 

*** DLL_THREAD_ATTACH: 新线程创建时通知

DLL_THREAD_ATTACH的几点注意事项:

1、进程中有新线程创建时,所有已经加载的DLL可以处理DLL_THREAD_ATTACH通知,这些处理代码由新线程执行,处理完毕后,新线程才能继续执行代码

2、当新的dll被加载时,系统不会让进程中已有的线程去通知DLL_THREAD_ATTACH

3、主线程不通知DLL_THREAD_ATTCH,主线程通知的是DLL_PROCESS_ATTACH 

 

*** DLL_THREAD_DETACH: 线程消亡时通知

DLL_THREAD_DETACH的注意事项:

1、ExitThread()的线程调用已加载dll的DLL_THREAD_DETACH的处理,该通知处理完毕后,线程才能退出

2、该通知不一定和DLL_THREAD_ATTACH配对,有可能是和DLL_PROCESS_ATTACH

 

 *** DLL_PROCESS_DETACH: 进程卸载dll时通知 

DLL_PROCESS_DETACH的几点注意事项:

1、如果DLL_PROCESS_ATTACH的处理返回FALSE,则不会调用DllMain(),传递DLL_PROCESS_DETACH

2、调用ExitProcess()的线程负责调用DLL_PROCESS_DETACH

3、对于显示链接的dll,调用FreeLibrary()的线程负责调用DLL_PROCESS_DETACH

4、DLL所在进程被TerminateProcess()后,不会收到DLL_PROCESS_DETACH通知。可能会导致数据丢失

注意:DLL_PROCESS_DETACH处理完成后,dll才会被卸载,进程才能正常退出。所以如果存在死循环,则进程不会被正常退出。 

 

二、DllMain()的执行对于系统来说是个同步操作

*** 进程对于DllMain会做同步操作,需要注意避免死锁

MSDN有草稿文档说,LoadLibrary会获取LoadLock,如果在DllMain()里面调用了其他DLL或者Kernel.dll的LoadLibrary等函数,会构成死锁或者崩溃。因为其他dll不一定已初始化过

 *** DisableThreadLibraryCalls()

《Windows Via C/C++》作者在Chapter20中Serialized Calls to DllMain小节,曾尝试调用DisableThreadLibraryCalls()来预期达到解除死锁的目的。代码片段如下: 

case DLL_PROCESS_ATTACH:
// The DLL is being mapped into the process' address space.
// Prevent the system from calling DllMain
// when threads are created or destroyed.
DisableThreadLibraryCalls(hInstDll);

// Create a thread to do some stuff.
hThread = CreateThread(NULL, 0, SomeFunction, NULL,
0, &dwThreadId);

// Suspend our thread until the new thread terminates.
WaitForSingleObject(hThread, INFINITE);

// We no longer need access to the new thread.
CloseHandle(hThread);
break;

这块代码在响应进程加载该DLL的时候创建一个线程,然后等待线程消亡,而线程消亡时会向该进程中的DLL通知DLL_THREAD_DETACH,执行DllMain(),构成死锁。DisableThreadLibraryCalls()未奏效的原因是该函数只是告诉系统这个dll不接收DLL_THREAD_DETACH通知,但如果进程中有其他dll需要接收,进程还是需要去获取DllMain()的锁,还是会构成死锁。


三、DllMain()与C运行时库的关系

*** 使用linker选项/ENTRY可以告诉链接器DLL的入口函数

当使用微软的链接器时,如果指定了/DLL开关,则链接器会将__DllMainCRTStartup()作为入口函数。__DllMainCRTStartup会在转发DLL_PROCESS_ATTACH到DllMain()之前,初始化CRT,保证全局C++对象初始化,在DLL_PROCESS_DETACH到了之后,先先转发给DllMain()然后销毁全局C++对象。

CRT提供的入口函数会被编译进DLL的代码段(.text section),exe文件也是如此。CRT其他的函数会有msvcr**.dll导出。**为编译器版本号。 

*** CRT提供的缺省DllMain()

__DllMainCRTStartup()不关注DLL_THREAD_ATTACH和DLL_THREAD_DETACH的通知。

如果用户没有提供DllMain(),CRT会认为用户也不关心这两个通知,会合成一个DllMain(),在里面调用DisableThreadLibraryCalls()。


参考文档:
1、Best Practices for Creating DLLs
2、DllMain entry point

 

转载于:https://www.cnblogs.com/shokey520/p/3663911.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值