最近在把本人做的一个软件中的一些代码独立出来成为DLL模块供系统的其他组件调用。这些代码的最大特点是会在单元的Initialization中创建全局的静态对象,这些对象是数据库操作的封装,并在Finalization中释放。通过FastMM作为内存管理器并调整FastMM的参数,可以方便地直接使用Delphi的动态字符串进行参数传递。经过一轮鼓捣后,总结了一些问题如下:
1、FastMM要打开ShareMem的相关几个选项,可以修改INC文件实现;
2、需要向DLL传递Application.Handle,并在Dll中把接收到的值赋给DLL自己的Application.Handle。否则DLL中的窗体会接收不到键盘热键或者丢失某些消息;
3、DLL中的窗体不能设置默认最大化,需要在创建窗体后WindowState := wsMaximized这样来最大化,否则最大化后的窗口位置不对;
4、如果使用了ADO,由于ADO组件使用了COM接口,需要CoInitialize初始化。但是Delphi在COM的初始化中特意检查了当前程序是否DLL,如果是则跳过CoInitialize。很多人认为这个是Delphi的错误,但实际上这个是Microsoft的要求(可以在MSDN中查函数CoInitialize或CoUninitialize,有专门的说明)。就此来看,貌似只要在涉及到ADO的单元中加上CoInitialize和CoUninitialize便可。但是,由于Microsoft特意指出的,无法控制初始化/释放的顺序,结果会导致在Initialization中创建,在Finalization中释放的ADO对象在释放时可能由于已经CoUnitiialize而释放出错。解决办法只有:1)、所有ADO相关的对象都不能在Initialization/Finalization中处理;2)、使用动态加载的DLL 而不是静态加载,此时需要在主程序加载DLL前先执行CoInitialize。
5、进一步的试验发现,静态加载并设置了共享MemoryManager的DLL会导致FastMM在退出时的内存泄露报告功能消失,原因不明。因此,所有用到FastMM的DLL都应该动态加载。
最后贴一段我的DLL初始化代码:
varOldDllProc: TDLLProc;
procedure ThisDllProc(Reason: Integer);beginif Reason = DLL_THREAD_ATTACH thenIsMultiThread := True; // for FastMM
// for ADOcase Reason ofDLL_PROCESS_ATTACH,DLL_THREAD_ATTACH:CoInitialize(nil);
DLL_PROCESS_DETACH,DLL_THREAD_DETACH:CoUninitialize;end;
if Assigned(OldDllProc) thenOldDllProc(Reason);end;
beginOldDllProc := DllProc;DllProc := ThisDllProc;ThisDllProc(DLL_PROCESS_ATTACH);end.
本站微信订阅号:
本页网址二维码: