站长手记 - 站长手记
打印】【收藏此页
用Delphi编写使用到ADO的DLL的一些问题
作者:本站:苏信东  来源:WaveCN.com  发布日期:2009-07-22  最后修改日期:2009-09-25  

最近在把本人做的一个软件中的一些代码独立出来成为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初始化代码:

var
  OldDllProc: TDLLProc;

procedure ThisDllProc(Reason: Integer);
begin
  if Reason = DLL_THREAD_ATTACH then
    IsMultiThread := True; // for FastMM

  // for ADO
  case Reason of
    DLL_PROCESS_ATTACH,
    DLL_THREAD_ATTACH:CoInitialize(nil);

    DLL_PROCESS_DETACH,
    DLL_THREAD_DETACH:CoUninitialize;
  end;

  if Assigned(OldDllProc) then
    OldDllProc(Reason);
end;

begin
  OldDllProc := DllProc;
  DllProc := ThisDllProc;
  ThisDllProc(DLL_PROCESS_ATTACH);
end.