原创 DLL编写经验总结(一)使DLL支持多线程

最近用Delphi编写DLL比较多,总结几条经验方便以后回顾。

需求背景:DLL接口自身是向主调方提供服务,考虑到主调方的不定性以及响应速度问题,需要支持多线程。

实现思路:DLL在初次加载或者被唤醒的时候会调用DLLMain函数(DelphiMain函数头已被隐藏,实际上就是主文件中的Begin End),触发DLL_Process_Attach事件。可用全局变量DLLProc来处理触发的事件所调用的函数。

DLL在退出的时候会调用DLLMain函数(DelphiMain函数头已被隐藏,实际上就是主文件中的Begin End),触发DLL_Process_Detach事件。可用全局变量ExitProc来处理触发的事件所调用的函数。 

Delphi源码如下:

var

  OldExitProc:pointer;


begin

    DLLProc:=@MyDLLHandler;//由于DLLProc原事件已经执行完成,此处可以不再保存原事件

    MyDLLHandler(DLL_Process_Attach);//执行自定义方法

 

    OldExitProc:=ExitProc;//暂存退出后处理函数地址

    ExitProc:=@MyExitProc; //让系统调用自定义函数处理事情,在MyExitProc中需要赋值回来。

end.

 

为了限制不同时执行某些关键区域,使用Delphi Windows下的CriticalSection

在DLL映射时创建,在接口中运用Enter、Leave,在退出时销毁

 
var
  FSection: TRTLCriticalSection;//定义一个关键区域用于线程互斥执行
//关键区域进出
procedure Enter(OutType:string);
begin
  _log('Enter FSection',OutType);
  EnterCriticalSection(FSection);
end;

procedure Leave(OutType:string);
begin
   _log('Leave FSection',OutType);
   LeaveCriticalSection(FSection);
end;
//关键区域使用
procedure MyDLLHandler(Reason: integer);
begin
  case Reason of
    DLL_Process_Attach: //整个DLL的初始化代码
      begin
          _log('DLL_Process_Attach', 'FSection');
          InitializeCriticalSection(FSection);
      end;
    DLL_Process_Detach: //整个DLL的善後程序
      begin
        DeleteCriticalSection(FSection);
        _log('DLL_Process_Detach', 'FSection');
      end;
    DLL_Thread_Attach: //当主叫端开始一个Thread时
      begin
        _log('DLL_Thread_Attach', 'FSection');
        StartMyThreadsAndWaitBegin();
      end;
    DLL_Thread_Detach: //当主叫端终止一个Thread时
      begin
        _log('DLL_Thread_Detach', 'FSection');
        StopMyThreadsAndWaitEnd();
      end;
  end;
end;
procedure MyExitProc;
begin
  _log('MyExitProc','FSection');
  ExitProc:=OldExitProc;//恢复退出的事件
end;

procedure StartMyThreadsAndWaitBegin();
begin
  _log('StartMyThreadsAndWaitBegin','FSection');
  Exit;
end;

procedure StopMyThreadsAndWaitEnd();
begin
  _log('StopMyThreadsAndWaitEnd','FSection');
  Exit;
end;


关键区域在接口中运用举例:

{
   created by: JustinYang 2016-09-23
   function: 托盘解绑
   Param in: Ahandle窗体句柄, serverIP 访问服务器IP,serverPort 服务器端口,s_TrayID 托盘编号,i_TrayRFID 托盘RFID
   Param Out: 整型 -1 网络异常;-2 托盘编号长度不对; -3 RFID大小异常; 1 解绑成功 0 解绑不成功 
}
function upFreeTray(AHandle: THandle; serverIP: PChar; serverPort: integer; s_TrayID:PChar; i_TrayRFID:Int64): integer; export; stdcall;
var
  p_serverIP: string;
  P_serverPort,j: Integer;
  tOld,tNew:TDateTime;
  trayID:string;
  trayRFID:Int64;
  hw:Integer;
begin
  try
    try
      Enter('FSection');

      j:=-1;
      result:=j;
      _log(' IP:'+serverIP+' Port:'+IntToStr(serverPort),'upFreeTray');
      if Length(string(s_TrayID)) <3 then s_TrayID :='';
      _log(' Begin upFreeTray IP:'+serverIP+' Port:'+IntToStr(serverPort)+' Tray:'+IntToStr(i_TrayRFID)+':'+s_TrayID+' at '+DateTimeToStr(Now),'upFreeTray');     

      CoInitialize(nil);
      Application.handle := AHandle;
      
      trayID:=string(s_TrayID);
      trayRFID:=i_TrayRFID;
      if (Trim(trayID)='') and (trayRFID <= 0) then
      begin
        _log(' End upFreeTray '+IntToStr(trayRFID)+':'+trayID+'  at '+ DateTimeToStr(Now) + ' result:'+IntToStr(j),'upFreeTray');
        result:=0;
        Exit;
      end;

      DllDataModule := TDllDataModule.Create(Application);


      p_serverIP := string(serverIP);
      if serverPort <= 0 then
        P_serverPort := 8095
      else
        P_serverPort := serverPort;
      DllDataModule.Channel.Host := string(p_serverIP);
      DllDataModule.Channel.Port := P_serverPort;
    except
      on e:Exception do
      begin
          j := -1;//网络连接失败
          _log('When dll access network occours:'+e.Message,'upFreeTray');
          Exit;
      end;
    end;
    try
       j := ((DllDataModule.RemoteService as INewService).upFreeTray(trayID, trayRFID));
       if j > 0 then j := 1;
    except
      on e:Exception do
      begin
        j:=-4;
        _log('When dll access server occours:'+e.Message,'upFreeTray');
        Exit;
      end;
    end;
  finally
    DllDataModule.free;
    result:=j;
    _log(' End upFreeTray '+IntToStr(i_TrayRFID)+' '+s_TrayID+'  at '+ DateTimeToStr(Now) + ' result:'+IntToStr(j),'upFreeTray');
    CoUninitialize;
    Leave('FSection');
  end;
end;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值