[Delphi]DLL封装登录框架实现代码复用


======================================================
注:本文源代码点此下载
======================================================

dll封装登录框架实现代码复用

(说明:发布在电脑编程技巧与维护2007年第4期上)

摘 要 本文介绍用dll封装通用的软件注册,系统登录对话窗体、修改密码窗体和关于窗体。形成登录框架,供不同软件系统调用,实现代码复用。

关键字 dll,delphi,登录对话,注册表,软件保护,代码复用

一、前言

在软件系统的开发过程中,为了维护软件所有者的权益和保证系统的安全性,软件需要注册授权后才能运行,操作员需要登录授权后才能登录使用。对于软件公司,这部分重复工作量很大。能不能把这部分功能封装起来,实现代码复用呢?

本文提出用dll封装登录框架的新方法,新开发一个项目时,只需要几行代码调用就可以分别实现软件注册,系统登录,修改密码和关于对话框等功能。

二、dll简介

dll(动态链接库,dynamic link library)简单来说是一种可通过调用执行的已编译的代码模块。当某个函数或过程需要被使用时,才从硬盘调用它进入内存,一旦没有程序再调用该dll了,将其从内存中清除。多个应用程序调用同一个dll,在内存里只有一个代码副本。而不象静态编译的程序那样每一个都必须全部的被装入。装载dll时,它将被映射到进程的地址空间,同时使用dll的动态链接并非将库代码拷贝,而仅仅记录函数的入口点和接口。

dll还能带来共享的好处。一家公司开发的不同软件可能需要一些公用的函数/过程,这些函数/过程可以被封装为dll,供不同的软件调用。本文就利用dll这一优势,来实现代码复用。

三、设计与实现

1、数据库设计

首先在sql server2000中新建一个数据库,命名为deanmis。然后在deanmis数据库中建立表tsys_user,如图1所示:

图 1 tsys_user表结构

在表tsys_user中添加一条操作员信息,如图2所示:

图 2 tsys_user表中数据

2、建立dll

打开delphi7,新建一个工程,保存,再打开file|new|other|new|dll wizard,修改library名称为deanlogin

加入4个form窗体及相应控件,如图3所示:

图示3 软件界面

我们用setconn方法来设置数据库连接字符串,再用checkpwd函数来调用系统登录对话框。如果登录成功,返回登录信息,通过exports引出例程名称。注意对于传出参数要在参数前加var,主要代码如下:

library deanlogin;

uses

fastmm4,sysutils,classes,controls,forms,windows,

ufrmlogin in 'ufrmlogin.pas' {frmlogin},//登录对话框

ufrmregistry in 'ufrmregistry.pas' {frmregistry},//软件注册

ufrmchangepw in 'ufrmchangepw.pas' {frmchangepw},//修改密码对话框

ufrmabout in 'ufrmabout.pas' {frmabout},//关于对话框

ucommon in 'ucommon.pas',//简单加解密函数

umac in 'umac.pas';//获取计算机网卡mac作为机器识别码

var

myconn:string;//定义公共变量,数据库连接字符串

{$r *.res}

procedure setconn(conn:pchar); stdcall;

begin

myconn := strpas(conn);

end;

//验证系统登录,如果登录成功返回登录id,用户名和姓名

function checkpwd(apphandle:thandle;var opid:pchar;var opname:pchar;var opusername:pchar):boolean; stdcall;

var

frmlogin:tfrmlogin;

resultmodal:integer;//窗体返回值

begin

opid:=pchar('');opname:=pchar('');opusername:=pchar(''); result:=false;

if myconn = '' then exit;

application.handle:= apphandle;//把调用程序的句柄传递给dll,避免任务栏出现dll窗体的实例

frmlogin:=tfrmlogin.create(nil);

try

frmlogin.adoq.connectionstring:=myconn;

resultmodal:=frmlogin.showmodal;//打开登录对话窗体

if resultmodal=mrok then

begin

opid:=pchar(frmlogin.sopid);

opname:=pchar(frmlogin.sopname);

opusername:=pchar(frmlogin.sopusername);

result:=true;

end;

finally

frmlogin.free; //释放资源

application.handle:=0;

end;

end;

exports//导出例程名称

setconn,checkpwd;

begin

end.

3、登录窗体和软件注册

首先登录对话框通过注册表检测软件是否已经注册,如果未注册显示注册按钮并提示用户注册。如果注册成功,把注册码写入注册表,供下次登录校验。

procedure tfrmlogin.btregistryclick(sender: tobject);

var

_registry:tregistry;

begin

//打开注册窗口

hardcode:=trim(getmacaddress);//得到机器识别码,即mac

with tfrmregistry.create(self) do

begin

eid.text:=hardcode;

if showmodal=mrok then //如输入的注册码正确,则把注册码保存到注册表

begin

_registry := tregistry.create;

with _registry do

begin

rootkey:=hkey_local_machine;

if openkey('software\deanzhang',true) then

writestring('mis',ecode.text);

free;

end;

hasreg:=true;

checkreg;//根据注册情况,设置窗体上的控件

end;

free;

end;

end;

如果验证软件已经注册,需向数据库校验用户登录信息,登录成功返回登录用户信息。

procedure tfrmlogin.btloginclick(sender: tobject);

var

username, userpw: string;

begin

modalresult := mrnone;

username := trim(eusername.text);

userpw := euserpw.text;

//………………校验输入数据

if userlogin(username, userpw) then begin

loginok := true;

modalresult := mrok;

end;

end;

function tfrmlogin.userlogin(const username, userpw: string): boolean;

begin //向数据库验证登录信息

screen.cursor:=crhourglass;

try

adoq.close;

adoq.sql.text:='select * from tsys_user where fusername=:username';

adoq.parameters.parambyname('username').value:=trim(username);

adoq.open;

except

messagebox(handle,'网络错误!','错误提示',mb_iconhand+mb_ok+mb_defbutton2);

result := false;

exit;

end;

if adoq.isempty then

begin

screen.cursor := crdefault;

messagebox(handle,'无效的用户名!','错误提示',mb_iconhand+mb_ok+mb_defbutton2);

eusername.setfocus;

result := false;

exit;

end;

if not (adoq.fieldbyname('fpwd').asstring=trim(userpw)) then

begin

screen.cursor:=crdefault;

messagebox(handle,'密码错误!','错误提示',mb_iconhand+mb_ok+mb_defbutton2);

euserpw.setfocus;

result := false;

exit;

end;

if adoq.fieldbyname('fusersign').asstring<>'1' then

begin

screen.cursor:=crdefault;

messagebox(handle,'此用户已禁用!','信息提示',mb_iconwarning+mb_ok+mb_defbutton2);

result := false;

exit;

end;

screen.cursor:=crdefault;

_opid:=adoq.fieldbyname('fid').value; // 操作员编号

_opname:=adoq.fieldbyname('ftruename').value; //操作员姓名

_opusername:=adoq.fieldbyname('fusername').value;//操作员登录用户名

if adoq.active then adoq.close;

result := true;

end;

要返回的登录信息,我们通过定义属性来完成。如下:

property sopid: string read getopid write setopid;

4、其它窗体

其它窗体和登录对话窗体类似,通过changpwd函数来调用修改密码窗体、showabout过程来调用关于窗体。注意要传入调用程序的句柄,不然会在任务栏出现被调用窗体的实例。

四、调用

dll的调用有两种方式,一种是静态(隐式)调用,一种是动态(显式)调用。静态调用方法简单,但dll会在启动调用程序时即被调入。动态调用相对比较复杂,仅在调用外部例程时才将dll装载内存,节约内存空间。

dll动态调用的原理是首先声明一个函数/过程类型并创建一个指针变量。为保证该指针与外部例程指针一致以确保赋值正确,函数/过程的声明必须和外部例程的原始声明一致。接下来通过windows api函数loadlibrary引入指定的库文件,loadlibrary的参数是dll文件名,返回一个thandle。如果该步骤成功,再通过另一个api函数getprocaddress获得例程的入口地址,参数分别为loadlibrary的指针和例程名,最终返回例程的入口指针。将该指针赋值给我们预先定义好的函数/过程指针,然后就可以使用这个函数/过程了。最后使用api函数freelibrary来减少dll引用记数,以保证dll使用结束后可以清除出内存。

本文调用实例设置数据库连接采用静态调用,其它窗体调用采用动态调用,静态调用声明:

procedure setconn(conn:pchar); stdcall; external 'deanlogin.dll';

动态调用声明:

hchangpwd: thandle;

checkpwd:function(apphandle:thandle;var opid:pchar;var opname:pchar;var opusername:pchar):boolean; stdcall;

调用登录窗体:

procedure tfrmmain.formcreate(sender: tobject);

var

popid,popname,popusername:pchar;

bcheckpwd:boolean;

begin

setconn(pchar(cnnstr));//设置数据库连接字符串

hcheckpwd:= loadlibrary('deanlogin.dll');

try

@checkpwd:=getprocaddress(hcheckpwd,'checkpwd');

bcheckpwd:= checkpwd(application.handle,popid,popname,popusername);

finally

freelibrary(hcheckpwd);

end;

if bcheckpwd then

begin//如果登录成功,给状态栏赋值opid:=strpas(popid);opname:=strpas(popname);opusername:=strpas(popusername);

statusbar1.panels[1].text:=opid;statusbar1.panels[3].text:=opusername;

statusbar1.panels[5].text:=opname;

end

else application.terminate;

end;

注意,在dll用到ado来连接数据库,在调用程序uses里面需引入adodb单元。dll的搜索路径的顺序是:当前目录;path路径;windows目录;widows系统目录(system、system32),要确保调用的dll在以上路径能找到。

五、结束语

本文通过对登录框架的dll封装,熟悉dll的开发和调用过程。把复用的代码封装,实现代码复用。以上程序在delphi 7,sql server 2000 sp4, windows 2003 sp1环境下编译通过。在源程序中还引入fastmm(http://fastmm.sourceforge.net)内存管理,替换了borland的内存管理器,提升了内存管理效率,并不再需要任何dll的支持。

参考文献

1、 delphi帮助文件


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值