概述
最近用Delphi编写DLL比较多,总结几条经验方便以后回顾。
需求背景:DLL接口自身是向主调方提供服务,考虑到主调方的不定性以及响应速度问题,需要支持多线程。
实现思路:DLL在初次加载或者被唤醒的时候会调用DLLMain函数(Delphi的Main函数头已被隐藏,实际上就是主文件中的Begin End),触发DLL_Process_Attach事件。可用全局变量DLLProc来处理触发的事件所调用的函数。
DLL在退出的时候会调用DLLMain函数(Delphi的Main函数头已被隐藏,实际上就是主文件中的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;
最后
以上就是勤恳宝马为你收集整理的原创 DLL编写经验总结(一)使DLL支持多线程的全部内容,希望文章能够帮你解决原创 DLL编写经验总结(一)使DLL支持多线程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复