利用Delphi扩充VB函数



  很多编程爱好者对VB、Delphi两种编程工具都十分了解。如何把Delphi的优点为VB所用成为编程者十分感兴起的话题。VB比Delphi 更易学习掌握,但VB函数太少,往满足不了实际应用的要求。

  如何利用Delphi来扩充VB函数呢?当然,利用Delphi扩充VB函数可以是直接由Delphi编写动态链接库文件,象Windows API函数那样由VB直接调用,这种方式称为直接调用。本文讲述的是另一种调用方法,即根据Delphi内部函数源代码设计思想,利用Windows API编写VB的函数。

  我们知道,Delphi除其它特点外,最大的特点就是开放性:大多Delphi内部函数、控件等都能在...\Source子目录下找到其源代码。仔细分析不难发现,Delphi函数、控件等所用的语句基本是汇编语言、Windows API函数等所构成。虽然VB内部函数较少,但仍可用Windows API函数进行扩充。对于大多数编程者来说,直接用Windows API编程难度较大,很多时候只知其一不知其二,用API编写的函数并不完善,缺乏通用性。而Delphi的内部函数源代码毕竟为专家所写,且经过长期调试是成功的。

  Delphi的函数FileExists意为文件名是否存在,返回为逻辑值,即文件存在时为真,反之为假。下面就以FileExists为例来说明如何利用Delphi的思想来编写VB的FileExists函数,以起到抛砖引玉的作用,其它用Windows API函数写的Delphi函数基本仍可按此原理推出VB的函数。

  首先进入Delphi,任写一Fileexists函数,鼠标在其上停留片刻,Delphi就会提示该函数出自sysutils.pas中。

  新建工程文件名为Project1.dpr,另存为Pfileexists.dpr;去掉Form1窗体的对窗体描述的文本部分(即扩展名为Dfm的相关文件),对Unit1.pas 另存为uFileExists.pas 。

  在文件PFileexists.dpr中,只保留Uses 中的Forms和uFileexists.pas,去掉其它引用。在Begin...End 程序体中加入以下代码:

  d:='c:\windows\notepad.exe';

  if fileexists(d) then

   application.MessageBox(pchar(d+' is exist'),'提示',0)

  else

   application.MessageBox(pchar(d+' is not exist'),'提示',0);

对uFileexists.pas 文件,去掉Uses的全部引用部分。编译运行程序,Delphi就会提示函数Fileexists无效(没有声明)。于是在加入...\Source\RTL\SYS\sysutils.pas和....\Source\WIN\windows.pas两文件。

  在Pfileexists.dpr中去掉对sytutils.pas 和Windows.pas 的引用。

  分析、逐步调试,把Windows.pas和sysutils.pas 有关的类型、常量、函数声明、函数执行体等加入ufileexists.pas中。

  Pfileexists.dpr源程序代码如下

  program Pfileexists;

   uses

   Forms,//application.messagebox要用到该声明

   uFileexists in 'uFileexists.pas';//调用FileExists函数用得上

   {$R *.RES}

   var d:string ;//声明文件名为字符串型

   begin

    d:='c:\windows\notepad.ex';

    if fileexists(d) then

     application.MessageBox(pchar(d+' is exist'),'提示',0)

    else

     application.MessageBox(pchar(d+' is not exist'),'提示',0);

    end.

  uFileexists.pas源程序代码如下

   unit uFileexists;

   type DWORD = LongWord;

   BOOL = LongBool;

   Const//常量取值

   MAX_PATH = 260;

   INVALID_HANDLE_VALUE = DWORD(-1);

   FILE_ATTRIBUTE_DIRECTORY = $00000010;

   kernel32 = 'kernel32.dll';//API函数引用的动态链接库名

   type//类型

    LongRec = packed record

    Lo, Hi: Word;

   end;

   THandle = LongWord;

   _FILETIME = record

   dwLowDateTime: DWORD;

   dwHighDateTime: DWORD;

  end;

   TFileTime = _FILETIME;

   _WIN32_FIND_DATAA = record

   dwFileAttributes: DWORD;

   ftCreationTime: TFileTime;

   ftLastAccessTime: TFileTime;

   ftLastWriteTime: TFileTime;

   nFileSizeHigh: DWORD;

   nFileSizeLow: DWORD;

   dwReserved0: DWORD;

   dwReserved1: DWORD;

   cFileName: array[0..MAX_PATH - 1] of AnsiChar;

   cAlternateFileName: array[0..13] of AnsiChar;

  end;

   TWin32FindDataA = _WIN32_FIND_DATAA;

   TWin32FindData = TWin32FindDataA;

   file://函数声明

   function FileExists(const FileName: string): Boolean;

   function FileAge(const FileName: string): Integer;

   function FindFirstFile(lpFileName: PChar;

   var lpFindFileData: TWIN32FindData):

   THan dle; stdcall;

   function FindClose(hFindFile: THandle): BOOL; stdcall;

   function FileTimeToLocalFileTime(const lpFileTime: TFileTime;
                    var lpLocalFileTime:TFileTime): BOOL; stdcall;

   function FileTimeToDosDateTime(const lpFileTime: TFileTime;
                    var lpFatDate, lpFatTime: Word): BOOL; stdcall;

   implementation

   function FileExists(const FileName: string): Boolean;

    begin

     Result := FileAge(FileName) -1;

   end;

   function FileAge(const FileName: string): Integer;

    var

     Handle: THandle;

     FindData: TWin32FindData;

     LocalFileTime: TFileTime;

    begin

     Handle := FindFirstFile(PChar(FileName), FindData);

     if Handle INVALID_HANDLE_VALUE then

      begin

       FindClose(Handle);

       if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then

        begin

         FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);

          if FileTimeToDosDateTime(LocalFileTime, LongRec(Result).Hi,
                           LongRec(Result).Lo) then

            end;

          end;

         Result := -1;

        end;

  function FindFirstFile; external kernel32 name 'FindFirstFileA';

  function FindClose; external kernel32 name 'FindClose';

  function FileTimeToLocalFileTime; external kernel32 name

   'FileTimeToLocalFileTime';

  function FileTimeToDosDateTime; external kernel32 name

   'FileTimeToDosDateTime';

  end.

  仔细分析uFileexists.pas 的代码,不难发现Delphi用了六个函数,其中Fileexists为主函数,FileAge为Delphi写的中间函数,其余四个函数FindFirstFile、FindClose、 FileTimeToLocalFileTime、 FileTimeToDosDateTime 为Windows API函数。

  Delphi中的Result在VB中表述为直接写函数名即可,LongRec类型在VB中无,经实践对LongRec(Result).HI,LongRec(Result).Lo在VB中用FileAge代替即可。

  下面是在VB中如何写FileExists函数

  进入VB,新建一工程文件名为工程1.vbp,窗体文件名为Form1.pas,添加名为 Module1.bas的模块文件。在Form1窗体中加入Command按钮,在Click事件中加入以下代码。

  Dim D As String

  D = "c:\windows\notepa.exe"

  if FileExists(D) Then

   MsgBox D + " is exist"

  Else

   MsgBox D + " is not exist"

在模块中用API文本查看器,加入uFileExists.pas中的四个API函数FindFirstFile、FindClose、FileTimeToLocalFileTime、 FileTimeToDosDateTime,并加入相应的声明、类型等代码。

   Form1.frm的源代码如下

   VERSION 5.00

   Begin VB.Form Form1

    Caption = "Form1"

    ClientHeight = 3945

    ClientLeft = 2325

    ClientTop = 1530

    ClientWidth = 6420

    LinkTopic = "Form1"

    ScaleHeight = 3945

    ScaleWidth = 6420

   begin VB.CommandButton Command1

    Caption = "Command1"

    Height = 495

    Left = 600

    TabIndex = 0

    Top = 840

    Width = 3135

   End

  End

   Attribute VB_Name = "Form1"

   Attribute VB_GlobalNameSpace = False

   Attribute VB_Creatable = False

   Attribute VB_PredeclaredId = True

   Attribute VB_Exposed = False

   '以上代码在VB中是不可见的

   Option Explicit

   Private Sub Command1_Click()

    Dim D As String

     D= "c:\windows\notepa.exe"

     if FileExists(D) Then
      MsgBox D + " is exist"
     Else
      MsgBox D + " is not exist"

     End Sub
   Module1.bas的源代码如下

    Attribute VB_Name = "MyModule" '该段代码在VB中是不可见的

    Option Explicit

    Public Const FILE_ATTRIBUTE_DIRECTORY = &H10

    Public Const MAX_PATH = 260

    Public Const INVALID_HANDLE_VALUE = -1

    Type FILETIME

     dwLowDateTime As Long

     dwHighDateTime As Long

    End Type

    Type WIN32_FIND_DATA

     dwFileAttributes As Long

     ftCreationTime As FILETIME

     ftLastAccessTime As FILETIME

     ftLastWriteTime As FILETIME

     nFileSizeHigh As Long

     nFileSizeLow As Long

     dwReserved0 As Long

     dwReserved1 As Long

     cFileName As String * MAX_PATH

     cAlternate As String * 14

    end Type

   Declare Function FindFirstFile Lib "kernel32" Alias "
           FindFirstFileA" (ByVal lpFileName As String, lpFindFileData As
           WIN32_FIND_DATA) As Long

   Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long

   Declare Function FileTimeToLocalFileTime Lib "kernel32"
          (lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long

   Declare Function FileTimeToDosDateTime Lib "kernel32"
          (lpFileTime As FILETIME, ByVal lpFatDate As Long, ByVal lpFatTime As
           Long) As Long

   Function FileExists(FileName As String) As Boolean

     FileExists = (FileAge(FileName) -1)

   End Function

   Function FileAge(FileName As String) As Integer

    Dim di As Long

    Dim Handle As Long

    Dim FindData As WIN32_FIND_DATA

    Dim LocalFileTime As FILETIME

    Handle = FindFirstFile(FileName, FindData)

    If Handle INVALID_HANDLE_VALUE Then

     FindClose (Handle)

     If (FindData.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) = 0 Then

      di = FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime)

      if FileTimeToDosDateTime(LocalFileTime, di, di) = 0 Then

        FileAge = 0

        FileTimeToLocalFileTime FindData.ftLastWriteTime, LocalFileTime

        If FileTimeToDosDateTime(LocalFileTime, FileAge, FileAge) = 0 Then

          Exit Function

        End If

       End If

      end if
     end if  
   FileAge = -1

   End Function

运行程序,VB程序与Delphi程序具有相同的效果。只要变化文件名D的值,D在盘中是否存在就会在对话框中提示是否存在。

  以上代码在Windows95/98 中文版 Delphi5.0英文版 VB5.0/6.0中文版下通过。据此原理,还可写出在Delphi中有而VB中无的其它函数来。