在Delphi中调用API函数 葛为民冯焱 
  一、概述   Delphi作为一种面向对象的可视化开发工具,以其开 
发程序的高速度和编译代码的高效率越来越受到广大编程 
人员的喜爱。Delphi本身提供了包括界面设计、数据库操 
作、报表打印和Internet等在内的数十个组件,开发者使 
用它们可以非常容易、快速地制作出所要的应用系统,同 
时所需要的编程量却非常地小。除此之外,delphi同时秉 
承了borland公司产品一贯的编译效率高,速度快特色。   Delphi2.0版本以上的产品完全支持32位应用程序的 
开发,完全支持windows95和windowsNT提供的所有API函 
数。应用程序接口(API)是windows提供的任何Windows应 
用可以访问的函数的集合。尽管Delphi已经提供了非常强 
大的开发组件(VCL),但灵活使用API函数一定可以使你 
的程序增色不少。    二、状态键的检查   当今不少流行软件的编辑窗口(包括Delphi的代码编 
辑窗口)的底部都有一个状态条用来显示一些状态信息, 
比如当前光标的位置、页码消息和状态键的状态。什么是 
状态键呢?我们知道键盘上大多数按键只有在按下时才能 
为系统所识别,而状态键的共同特点就是他们好似一个开 
关,每按一次就切换到相反状态直至下一次按键为止。通 
常键盘的状态键包括[NumLock],[ScrollLock],[C 
apsLock]和[Insert]这四个键,在编辑窗口中显示状 
态键的状态可以使你的界面更友好,更有利于方便用户。   使用delphi强大的开发功能和API提供的GetKeyboa 
rdState()函数,你可以轻松地在你的程序中实现状态 
键检测这一功能。   也许有些读者要问:我可以使用delphi提供的OnKe 
yPress函数捕捉按键动作来完成这一功能,又有什么必要 
调用API函数呢?这就涉及到状态键的另一个特点:即它 
的状态与程序运行无关。比如说你在word中按下insert键 
后再切换到delphi中输入代码,这个键的状态仍然保持不 
的状态仍然保持不 
变。而如果只使用OnKeyPress函数,那么当你的程序在后 
台运行时就无法捕捉到在前台程序中发生的按键动作,所 
以当切换到你程序时也就无法正确反映状态键的状态。因 
此需要使用API的GetKeyboardState()函数来检查键盘状 
态。当调用GetKeyboardState()函数时,你需要在程序 
中开辟一个256字节的缓冲区用来存储键盘上各个键的状 
态(最简单的方法你可以声明一个TKeyboardState变量 
)你可以根据缓冲区中相应位置的值来判断键盘状态,下 
表显示了系统常量和其相应的按键。(你如果想查看所有 
的键值列表可以在help菜单选择windowsAPI中输入关键 
字virtualkeycodes,然后按下Show键)   常量按键名称   VK—INSERT[Insert]键   VK—NUMLOCK[NumLock]键   VK—CAPITAL[CapsLock]键   VK—SCROLL[ScrollLock]键 
  键盘缓冲区每一位都有特定的格式,对于状态键来说 
,最低位是1时表示状态键处于ON状态,你可以使用delph 
i提供的Odd()函数来确定这一位的状态。为了使程序显 
示正确的状态键的状态,你需要定期调用GetKeyboardS 
tate()函数来不断的查询键盘状态,实现这一功能最简 
单的方法是使用Timer组件。   下面举一个小例子来说明如何具体实现这一调用功能 
,在这个例子中我们将检查[NumLock]键的状态并把它 
显示在屏幕底部的状态栏。   从Component模板Win95页中选择StatusBar组件,按 
如下所示设置它的属性   AlignalBottom   Height20   从system页中的选择Timer组件并把它放入窗体,双 
击Timer组件弹出OnTimer事件的代码编辑窗口,按如下所 
示添加代码: 
  procedureTForm1.Timer1Timer(Sender:TObject 
);   varKeyStates:TKeyboardState;   begin   GetKeyboardState(KeyStates);   begin   ifOdd(KeyStates[VK—NUMLOCK])then   StatusBar1.Panels.Items[0].Text:Κ′NUM 
′   else   StatusBar1.Panels.Items[0].Text:Κ″   end;   我们可以检验一下程序的运行结果。运行程序,可以 
看到状态条中正确显示了当前的状态,切换到另一个程序 
改变[numlock]键的状态再切换回运行程序,可以看到 
状态条的状态已经改变。一般说来,在程序中加入状态条 
显示相应信息对于用户来说是十分方便的。    三、改变提示框(hint)的特性   许多程序在特定的控件上都有提示框,当鼠标在这些 
控件上停一定时间以后就可以显示提示框。在Delphi中实 
现提示框是非常容易的,只要设定相应的属性即可,这里 
就不详细讨论了。但通常的提示框都是以黄色矩形框的形 
式显示在对应控件的左下角,以下这段代码说明了如何使 
用API改变delphi中提示属性的一些特性。有一点需要声 
明的是代码中使用到的GetIconInfo函数只适用win32(也 
就是说你只能在delphi2.0以上的版本中使用以下代码) 
。   把以下代码加入到主窗体的Oncreate事件中,加入代 
码后的主窗体的formcreate过程的代码如下所示: 
码后的主窗体的formcreate过程的代码如下所示:   procedureTMainForm.FormCreate(Sender:TObjec 
t);   begin   ...   Application.OnShowHint.ΚGetHintInfo;   end;   然后把以下过程声明加入到主窗体的public段   procedureGetHintInfo(VarHintStr:sting;VarCa 
nShow:boolean;varHintInfo:THintInfo);   最后,在主窗体的implementation部分加入过程的实 
现代码,加入完代码的过程如下所示:   procedureTMainForm.GetHintInfo(varHintStr:s 
tring;varCanShow:boolean;varHintInfo:THintIn 
fo);   var   II:TlconInfo;   Bmp:Windows.TBitmap;   begin   withHintInfodobegin//应该保证有控件使用定义 
了Hint属性   ifHintControlΚNILthenexit;   HintPos:ΚHintControl.ClientToScreen(Cursor 
Pos);   //把光标坐标系由相对于提示改为相对于屏幕   GetIconInto(Screen.Cursors[HintControl.Cur 
sor],II); 
sor],II);   //获得有关提示控制使用的有关光标的信息   GetObject(II.hbmMask,SizeOf(Windows.TBitm 
ap),ΝBmp);   //获得有关光标的位图(bitmap)信息   ifII.hbmColorΚ0then   inc(HintPos.Y,Bmp.bmHeightdiv2)   //如果光标不包括彩色位图,增加Y方向   else   inc(HintPos.Y,Bmp.bmHeight);   dec(HintPos.Y,II.yHotSpot);   //减掉y方向的热点位置   DeleteObject(II.hbmMask);   DeleteObject(II.hbmColor);   //清除位置句柄   end;   end;   通过改变HintPos.X和Y的值可以在任意位置显示提 
示框。Word7.0中滚动纵向滚动条时页码序号总是显示鼠 
标在左方,用以上代码实现这一功能可以说是易如反掌。 

解决方案 »

  1.   

    在Delphi应用程序中使用DLL 广西 李澄 
      Delphi与VisualBasic、VisualFoxPro等软件一样, 
    属于RAD工具(快速应用开发工具)。适合开发32位或16位 
    /32位混合应用程序。Delphi所使用的程序语言是Object 
    Pascal,是结构化、面向对象的编译型语言,具有高执行 
    效率、可重用性、易维护性,及较强的异常处理能力、类 
    封装能力等。VB与Delphi相比,VB不能对程序进行编译, 
    只能解释执行,更重要的不同是Delphi具有较强的继承性 
    ,Delphi的应用程序可编译DLL模块,VB却无法编译,只 
    能调用C编译的DLL。而Delphi不仅可调用C++产生的DLL 
    模块,同样C++程序也可调用Delphi所产生的DLL部件。 
    这样交互调用,无须重复开发,大大缩短了生产周期。    一、用Delphi创建DLL   Delphi的DLL创建并不复杂,下面向大家介绍Delph 
    i的DLL创建方法。   1、首先创建一个新的DLL项目(NewProject),因为 
    DLL与调用它的主程序要分开编译。如果DLL模块已经建立 
    在调用它的项目中(Project),则将它的窗体(Form) 
    从Project移出,另建一个新的项目(NewProject)。只需 
    从File菜单选中NewProject项,然后将DLL的Pas模块文件 
    加入到项目中,再将其自动建立的Form1删除即可。   2、在DLL的DPR文件中把Program关键字改为Librar 
    y,申明为动态链接库,在USES语句后面加入ExPorts语句 
    ,指明调用DLL的函数名。   3、如果主程序的DPR文件已有DLL窗体CreateForm的 
    语句,则将其去掉。   4、在DLL的Pas文件中Type......End后加入该 
    DLL的函数或过程的声明,形式如:   FunctionName(argment):Boolean;export;   该函数或过程应加入窗体的Create和Free(产生和释 
    放)方法。 
    放)方法。   5、对项目进行编译即可。    二、DLL的调用   调用DLL有两种方法,一种是在应用程序装载时调用 
    ,另一种是在应用程序运行时调用。首先介绍装载时DLL的 
    调用:   (1)装载时调用DLL   在调用DLL的Pas文件中,对DLL函数进行外部声明, 
    声明应位于Implementation的Uses语句后,形式如下:   Implementation   UsesDialogs;   FunctionName(argment):Boolean;far;Externa 
    l′CallName′;   ......   其中External关键字后面的引号内的字串是DLL的文 
    件名。声明以后即可在Pas文件任何地方引用DLL函数。   装载时调用DLL的优点是速度较快,程序间也可共享 
    代码。   (2)运行时调用DLL   DLL的另一种调用方法是在运行时调用。要调用到Win 
    dows的API函数:loadlibrary,Getprocaddress等。主要 
    用于调用DELPHI和其它语言,特别是C++编译的DLL。   假定你的DLL包括一个函数:   FunctionMyFunc(aparam:word):string;export 
    ;   首先在程序Type类型声明处加入一句:   Type 
      TMyfuncΚfunction(aparam:word):string;   此句的作用如同C++中声明的函数指针。   然后定义如下变量∶   Var   aptr:TFarproc;   lhnd:THandle;   s:string;   其中Aptr,lhnd两变量声明必须有,s是DLL函数返回 
    值,视情况而定。   在调用DLL处加入如下语句进行DLL装载:   lhnd:ΚLoadlibrary(′路径ιDLL文件名′);{ 
    如lhnd:ΚLoadlibrary(′c:ιaaιbb.dll′); 
      aptr:ΚGetprocAddress(lhnd,′Myfunc′);   下面可直接调用DLL了:   s:ΚTMyfunc(bptr)(60);{根据函数填相应的 
    变量参数}   调用完以后,用FreeLibrary释放DLL占用的内存:   FreeLibrary(lhnd);   下面给出一个DLL的创建以及运行时调用的示例,该D 
    LL主要用来检查输入的口令是否正确,窗体含有一个Edit 
    编辑框,两个按钮Button,一个标签Label,在编辑框内 
    输入口令,根据比较结果返回真假值。  。鹠ain.pas主程序(运行时调用DLL)}   unitMain;   interface 
      usesWinTypes,WinProcs,Classes,Graphics,   Forms,Controls,StdCtrls,   ExtCtrls;   type   TForm1Κclass(TForm)   Edit1:TEdit;   Label1:TLabel;   Button1:TButton;   Bevel1:TBevel;   GroupBox1:TGroupBox;   StatusLbl:TLabel; 
      procedureButton1Click(Sender:TObject);   end;   TGetPassΚfunction(aa:string):boolean;   var   Form1:TForm1;   getpass:TGetpass;   lhnd:THandle;   aptr:TFarproc;   implementation   usesDialogs;  。鏡*.DFM} 
     。鸌mportroutinefromDLL.Takespasswordtomatchan 
    dreturnsboolean  .}  。鹒unctionGetPassword(Password:string):Boo 
    lean;   far;external′CHKPWORD′;}  。鸆allpasswordcheckroutine,showstatusinformca 
    ption.}   procedureTForm1.Button1Click(Sender:TObject 
    );   begin   ifEdit1.Text ′′then   begin 
      MessageDlg(′Entersamplepasswordfirst′,mt 
    Information,[mbOK],0);   Edit1.SetFocus;   end   else   begin   lhnd:Κloadlibrary(′Chkpword.dll′);   aptr:Κgetprocaddress(lhnd,′GetPassword′ 
    );   ifTGetpass(aptr)(Edit1.Text)then   StatusLbl.Caption:Κ′Verifiedpassword′   elseStatusLbl.Caption:Κ′Invalidpassword′ 
    ; 
    ;   freelibrary(lhnd);   end;   end;   end.     。鹍llform.pasDLL模块}   unitDllform;   interface   usesWinTypes,WinProcs,Classes,Graphics,For 
    ms,Controls,   Buttons,SysUtils,StdCtrls; 
      type   TPasswordFormΚclass(TForm)   Edit1:TEdit;   Label1:TLabel;   BitBtn2:TBitBtn;   BitBtn1:TBitBtn;   end;   functionGetPassword(Password:string):Boole 
    an;export;   implementation   usesDialogs;  。鏡*.DFM}   functionGetPassword(Password:string):Boole 
    an;   var   PasswordForm:TPasswordForm;   begin   Result:ΚFalse;   PasswordForm:ΚTPasswordForm.Create(Applica 
    tion);   try   withPasswordFormdo   ifShowModalΚmrOKthen   ifUpperCase(Edit1.Text)ΙΛUpperCase(Passw 
    ΛUpperCase(Passw 
    ord)then   MessageDlg(′InvalidPassword′,mtWarning,[ 
    mbOK],0)   else   Result:ΚTrue;   finally   PasswordForm.Free;   end;   end;   end.   本程序在Windows3.1,Delphi1.0及Windows95,de 
    lphi2.0环境下调试通过。 .0环境下调试通过。