zoukankan      html  css  js  c++  java
  • DLL封装登录框架实现代码复用

     

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

    (说明:发布在电脑编程技巧与维护2007年第4期上)
    摘 要 本文介绍用DLL封装通用的软件注册,系统登录对话窗体、修改密码窗体和关于窗体。形成登录框架,供不同软件系统调用,实现代码复用。

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

    一、前言

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

    本文提出用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

    加入4Form窗体及相应控件,如图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系统目录(systemsystem32),要确保调用的DLL在以上路径能找到。

    五、结束语

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

    参考文献

    1、 Delphi帮助文件

  • 相关阅读:
    背包九讲
    hdu 2602 Bone Collector(01背包)
    hdu 1176 免费馅饼(类似于hdu 2084 数塔那道题目 )
    hdu 1114 PiggyBank(完全背包)
    hdu 2084 数塔
    hdu 1058 Humble Numbers【丑数】
    hdu 1114 PiggyBank【完全背包】
    hdu 2602 Bone Collector (01背包经典入门)
    hdu 2602 Bone Collector【01背包】
    【Python】python的各种函数
  • 原文地址:https://www.cnblogs.com/13590/p/697789.html
Copyright © 2011-2022 走看看