在程序开发中,往往要在程序启动或模块被加载时,需要做一些初始化的工作(例如:资源加载、内存创建、变量初始化或执行函数[脚本]等);
而在程序结束或模块被卸载时,需要做一些清理的工作(例如:资源回收、内存释放、状态清理或执行函数[脚本]等)。
+++++++++++++++++++++++++++++++++++++
首先,我们使用下面例子,来测试下静态全局对象在exe与dll中的构造和析构时机。
整个程序结构如下:
DllTest.dll动态连接库测试代码:
1 #include "stdafx.h" 2 #include "dllTest.h" 3 #include <cstdio> 4 5 BOOL APIENTRY DllMain( HANDLE hModule, 6 DWORD ul_reason_for_call, 7 LPVOID lpReserved 8 ) 9 { 10 switch (ul_reason_for_call) 11 { 12 case DLL_PROCESS_ATTACH: 13 { 14 printf("DLL: DLL_PROCESS_ATTACH\n"); 15 } 16 break; 17 case DLL_THREAD_ATTACH: 18 { 19 printf("DLL: DLL_THREAD_ATTACH\n"); 20 } 21 break; 22 case DLL_THREAD_DETACH: 23 { 24 printf("DLL: DLL_THREAD_DETACH\n"); 25 } 26 break; 27 case DLL_PROCESS_DETACH: 28 { 29 printf("DLL: DLL_PROCESS_DETACH\n"); 30 } 31 break; 32 default: 33 { 34 printf("DLL: DEFAULT\n"); 35 } 36 break; 37 } 38 return TRUE; 39 } 40 41 42
43 44 static class CFirstLoader 45 { 46 public: 47 CFirstLoader() 48 { 49 printf("DLL: CFirstLoader Construct\n"); 50 } 51 ~CFirstLoader() 52 { 53 printf("DLL: CFirstLoader Destruct\n"); 54 } 55 } s_firstLoader; 56 57 static class CSecondLoader 58 { 59 public: 60 CSecondLoader() 61 { 62 printf("DLL: CSecondLoader Construct\n"); 63 } 64 ~CSecondLoader() 65 { 66 printf("DLL: CSecondLoader Destruct\n"); 67 } 68 } s_secondLoader;
ConsoleTest.exe主程序测试代码:
1 #include "stdafx.h" 2 3 static class CFirstLoader 4 { 5 public: 6 CFirstLoader() 7 { 8 printf("EXE: CFirstLoader Construct\n"); 9 } 10 ~CFirstLoader() 11 { 12 printf("EXE: CFirstLoader Destruct\n"); 13 } 14 } s_firstLoader; 15 16 static class CSecondLoader 17 { 18 public: 19 CSecondLoader() 20 { 21 printf("EXE: CSecondLoader Construct\n"); 22 } 23 ~CSecondLoader() 24 { 25 printf("EXE: CSecondLoader Destruct\n"); 26 } 27 } s_secondLoader; 28 29 int main(int argc, char* argv[]) 30 { 31 printf("EXE: main\n"); 32 33 printf("EXE: Call LoadLibrary\n"); 34 HINSTANCE hDll = LoadLibrary("dllTest.dll"); 35 36 if (NULL != hDll) 37 { 38 printf("EXE: Call FreeLibrary\n"); 39 FreeLibrary(hDll); 40 } 41 42 return 0; 43 }
程序输出来的调用日志:
EXE: CFirstLoader Construct
EXE: CSecondLoader Construct
EXE: main
EXE: Call LoadLibrary
DLL: CFirstLoader Construct
DLL: CSecondLoader Construct
DLL: DLL_PROCESS_ATTACH
EXE: Call FreeLibrary
DLL: DLL_PROCESS_DETACH
DLL: CSecondLoader Destruct
DLL: CFirstLoader Destruct
EXE: CSecondLoader Destruct
EXE: CFirstLoader Destruct
通过分析日志,我们可以得到如下结论:
1. EXE中的静态全局对象的构造在main函数调用之前,析构在main函数调用之后。
2. DLL中的静态全局对象的构造在DLL_PROCESS_ATTACH之前,析构在DLL_PROCESS_DETACH之后。
3. EXE与DLL中的静态全局对象的构造顺序与定义的先后顺序保持一致,析构顺序则正好相反。
利用这一点,我们可以在static CFirstLoader s_firstLoader的构造与析构行为,来自动地进行初始化和清理工作。
这样做的好处是:无需外部显示调用来完成,程序简洁,非常cool!