• Delphi静态和动态调用dll的实例


    DLL 的两种调用方式在Delphi 中的比较

         编写DLL 的目的是为了输出例程供其他程序调用,因此在DLL 的工程文件中要把输出的例程用Exports 关键字引出。在调用DLL 的应用程序中,需要 声明用到的DLL 中的方法,声明格式要和DLL 中的声明一样。访问DLL 中的例程有静态调用和动态调用两种方式。静态调用方式就是在单元的 Interface 部分用External 指示字列出要从DLL 中引入的例程;动态调用方式就是通过调用Windows 的API 包括 LoadLibrary 函数、GetProcAddress 函数以及FreeLibrary 函数动态的引入DLL 中的例程。

      静态调用 方式所需的代码较动态调用方式所需的少,但存在着一些不足,一是如果要加载的DLL 不存在或者DLL 中没有要引入的例程,这时候程序就自动终止运行;二是 DLL 一旦加载就一直驻留在应用程序的地址空间,即使DLL 已不再需要了。动态调用方式就可解决以上问题,它在需要用到DLL 的时候才通过 LoadLibrary 函数引入,用完后通过FreeLibrary 函数从内存中卸载,而且通过调GetProcAddress 函数可以指定不同的例程。 最重要的是,如果指定的DLL 出错,至多是API调用失败,不会导致程序终止。以下将通过具体的实例说明说明这调用方式的使用方法。

    1 . 静态调用方式

     示例程序创建了一个DLL ,其中仅包含一个求两个整数的和的函数,在主程序中输入两个整数,通过调用该DLL ,即可求出两个整数的和。

    该DLL 的程序代码如下:

    library AddNum;
    uses
    SysUtils,
    Classes;
    
    {$R *.res}
    
    function AddNumber(Num1,Num2:integer):integer;stdcall; // 定义求和函数
     begin
      result:=Num1+Num2;
     end;
      exports
      AddNumber; // 引出求和函数
     begin
    end.
    

    主程序在调用该DLL 时,首先在interface 部分声明要调用的函数:

    var
    Form1: TForm1;
    
    function AddNum(Num1,Num2:integer):integer;stdcall;external 'AddNum.dll';
    

    然后在按钮控件的事件中写入如下代码:

    procedure TForm1.Button1Click(Sender: TObject);
    var
     Number1,Number2:integer; 
     Sum:integer;
    begin
     Number1:=strtoint(Edit1.Text);
     Number2:=strtoint(Edit2.Text);
     Sum:=AddNum(Number1,Number2); // 调用求和函数计算结果
     Edit3.Text:=inttostr(Sum);
    end;
    

    2 .动态调用方式 

    这个示例程序创建了一个显示日期的DLL ,其中包含一个窗体。

    程序中定义了一个ShowCalendar 函数,返回在这个窗体中设定的日期。函数定义如下: 

    function ShowCalendar(AHandle: THandle; ACaption: String): TDateTime;
    var
     DLLForm: TDLLForm;
    begin
     Application.Handle := AHandle;
     DLLForm := TDLLForm.Create(Application); // 创建并显示窗体
     try
      DLLForm.Caption := ACaption;
      DLLForm.ShowModal; // 显示方式为模式化
      Result := DLLForm.calDLLCalendar.CalendarDate; // 返回设定日期
     finally
      DLLForm.Free; // 用完后卸载该窗体
     end;
    end;
    

    在DLL 的工程文件中用exports ShowCalendar; 语句引出该函数。下面通过一个简单的应用程序测试一下该DLL 文件。新建一个工程文件,在窗体中放置一个Label 控件和一个按钮控件,在按钮控件的OnClick 事件中编写如下代码:

    procedure TMainForm.Button1Click(Sender: TObject);
    var
     OneHandle : THandle; // 定义一个句柄变量
    begin
     OneHandle := LoadLibrary('Clendar.dll'); // 动态载入DLL ,并返回其句柄
     try
      if OneHandle <> 0 then // 如果载入成功则获取ShowCalendar 函数的地址
       @ShowCalendar := GetProcAddress(OneHandle, 'ShowCalendar');
       if not (@ShowCalendar = nil) then
        // 如果找到该函数则在主窗体的Label1 中显示DLL 窗体中设定的日期
        Label1.Caption := DateToStr(ShowCalendar(Application.Handle, Caption))
       else
        RaiseLastWin32Error;
     finally
      FreeLibrary(OneHandle); // 调用完毕收回DLL 占用的资源
     end;
    end;
    

    从以上程序中可以看到DLL 的动态调用方式比静态调用方式的优越之处。DLL 例程在用到时才被调入,用完后就被卸载,大大减少了系统资源的占用。在调用 LoadLibrary 函数时可以明确指定DLL 的完整路径,如果没有指定路径,运行时首先查找应用程序载入的目录,然后是Windows 系统的 System 目录和环境变量Path 设定的路径。  

      

      

      

  • 相关阅读:
    编写高质量的代码,改善c#程序的157个建议_之1~10
    文件指针创建失败!File *fp失败
    一拜天地
    现金流中的机会,及其评估(摘抄)
    隐藏Mac Dock 中的某个图标
    vim快捷方式
    mac 快捷键
    mysql explain
    druid 连接池配置
    分布式数据库中间件
  • 原文地址:https://www.cnblogs.com/approx/p/12110916.html
Copyright © 2020-2023  润新知