Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

(Ebook - Pdf) Kick Ass Delphi Programming

.pdf
Скачиваний:
284
Добавлен:
17.08.2013
Размер:
5.02 Mб
Скачать

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Kick Ass Delphi Programming

Go!

Keyword

(Publisher: The Coriolis Group)

Author(s): Don Taylor, Jim Mischel, John Penman, Terence Goggin

ISBN: 1576100448

Publication Date: 09/01/96

Search this book:

Go!

-----------

Drag1, the first draft of a program that implements FMDD, is shown in Listings 2.1 and 2.2. A screen shot of the completed program is shown in Figure 2.1.

Listing 2.1 DRAG1.DPR

program drag1;

uses Forms,

dragfrm1 in 'dragfrm1.pas' {Form1};

{$R *.RES}

begin

Application.CreateForm(TForm1, Form1); Application.Run;

end.

Listing 2.2 DRAGFRM1.PAS

unit dragfrm1;

interface

uses

SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,

{

ShellAPI defines the drag and drop functions. The functions are implemented in SHELL32.DLL.

}

ShellAPI; type

TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; Button2: TButton; Label1: TLabel;

Label2: TLabel;

procedure

FormCreate(Sender: TObject);

procedure

AppMessage(var Msg: TMsg; var Handled: Boolean);

procedure

FormClose(Sender: TObject; var Action: TCloseAction);

procedure

Button1Click(Sender: TObject);

procedure

Button2Click(Sender: TObject);

private

 

{ Private

declarations }

procedure

WMDropFiles (hDrop : THandle; hWindow : HWnd);

public

 

{ Public declarations } end;

var

Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject); begin

Application.OnMessage := AppMessage;

{

Call DragAcceptFiles to tell the drag and drop manager that you're accepting files.

}

DragAcceptFiles (Handle, True); end;

procedure TForm1.WMDropFiles (hDrop : THandle; hWindow : HWnd); Var

TotalNumberOfFiles, nFileLength : Integer; pszFileName : PChar; pPoint : TPoint;

i : Integer; InClientArea : Boolean;

Begin

{

hDrop is a Handle to the internal Windows data

structure which has information about the dropped files.

}

{

Determine if the files were dropped in the client area

}

InClientArea := DragQueryPoint (hDrop, pPoint); if InClientArea then

Label2.Caption := 'In client area' else

Label2.Caption := 'Not in client area';

{

Find out total number of files dropped by passing -1 for the index parameter to DragQueryFile

}

TotalNumberOfFiles := DragQueryFile (hDrop , $FFFFFFFF, Nil, 0);

for i := 0 to TotalNumberOfFiles - 1 do begin

{

Get the length of a filename by telling DragQueryFile which file your querying about ( i ), and passing Nil

for the buffer parameter. The return value is the length of the file name.

}

nFileLength := DragQueryFile (hDrop, i , Nil, 0) + 1; GetMem (pszFileName, nFileLength);

{

Copy a file name.

Tell

DragQueryFile the file

you're interested in (i)

and the length of your buffer.

NOTE: Make sure that the

length is 1 more than the filename

to make room for the nul

character!

}

DragQueryFile (hDrop , i, pszFileName, nFileLength);

Listbox1.Items.Add (StrPas (pszFileName));

{ free the allocated memory... } FreeMem (pszFileName, nFileLength);

end;

{

Call DragFinish to release the memory that Shell allocated for this handle.

NOTE: This is a real easy step to forget and could explain memory leaks and incorrect program performance.

}

DragFinish (hDrop); end;

{

AppMessage captures application messages. Assign this method to the Application.OnMessage property in FormCreate.

}

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean); begin

case Msg.Message of

WM_DROPFILES : WMDropFiles (Msg.wParam, Msg.hWnd); end;

end;

procedure TForm1.FormClose (Sender: TObject; var Action: TCloseAction); begin

{ Don't accept files anymore } DragAcceptFiles (Handle, False);

end;

procedure TForm1.Button1Click(Sender: TObject); begin

Listbox1.Clear;

end;

procedure TForm1.Button2Click(Sender: TObject);

begin Close;

end;

end.

FIGURE 2.1 The completed Drag1 program.

The only real trick in DRAGFRM1.PAS is the line in TForm1.FormCreate that reads:

Application.OnMessage := AppMessage;

This line of code tells Delphi to pass Windows messages on to the TForm1.AppMessage procedure. This is the Delphi way of performing traditional handling of Windows messages. We have to do it this way because neither Delphi’s TControl class, nor any of its descendents (like TForm), know anything about WM_DROPFILES, so that message isn’t wrapped up in a nice Delphi event like OnDropFiles. More’s the pity.

There’s nothing especially wrong with the code in Listing 2.2. It works, which is the most important thing, but it’s large, it has lots of places where you can make mistakes, and (perhaps worst of all) it’s ugly. All that icky Windows code in the middle of a pure Delphi program just ain’t right! (Texans have such colorful ways of mangling the language.)

There’s another problem, too, but it’s caused by Delphi’s message handling machinery. Suppose you have two forms that want to respond to WM_DROPFILES messages. If each form assigns its own message handler to Application’s OnMessage event, only the second form will get messages. The first form’s message handler is overwritten by the second. There are a number of ways around this problem, and we’ll discuss some of them after we’ve taken care of that ugly Windows code.

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

Go!

Keyword

To access the contents, click the chapter and section titles.

Kick Ass Delphi Programming

(Publisher: The Coriolis Group)

Author(s): Don Taylor, Jim Mischel, John Penman, Terence Goggin

ISBN: 1576100448

Publication Date: 09/01/96

Search this book:

Go!

-----------

What to Do with Windows Code?

The answer to the question is “encapsulate it.” That’s what Delphi does, and does very well. The whole point of Delphi is to insulate you from the sordid little details of Windows programming so that you can concentrate on the important parts of your application. We’ll do the same with FMDD—wrap it up into a pretty little Delphi unit called FMDD.

Rather than have the form handle all of the details of WM_DROPFILES processing, we’ll define a function in the FMDD unit that the form’s OnMessage handler can call to retrieve an object that contains all available information about the drag and drop event. This object will include everything that we obtained from the Windows FMDD interface, but it will be all packaged together in a single, more manageable structure that looks like the following:

TDragDropInfo = class (TObject) private

FNumFiles : UINT; FInClientArea : Boolean; FDropPoint : TPoint; FFileList : TStringList;

public

constructor Create (ANumFiles : UINT); destructor Destroy; override;

property NumFiles : UINT read FNumFiles;

property InClientArea : Boolean read FInClientArea; property DropPoint : TPoint read FDropPoint; property Files : TStringList read FFileList;

end;

In addition to the TDragDrop structure, the FMDD unit defines three functions: AcceptDroppedFiles,

UnacceptDroppedFiles, and GetDroppedFiles. The first two simply encapsulate the DragAcceptFiles function. The third, GetDroppedFiles, is called in response to the WM_DROPFILES message and returns a TDropInfo object. The code for the FMDD unit is shown in Listing 2.3.

Listing 2.3 The FMDD unit that encapsulates the Drag and Drop interface

{

FMDD.PAS -- File Mangler Drag and Drop

}

unit fmdd;

interface

uses Windows, Classes;

type

TDragDropInfo = class (TObject) private

FNumFiles : UINT; FInClientArea : Boolean; FDropPoint : TPoint; FFileList : TStringList;

public

constructor Create (ANumFiles : UINT); destructor Destroy; override;

property NumFiles : UINT read FNumFiles;

property InClientArea : Boolean read FInClientArea; property DropPoint : TPoint read FDropPoint; property Files : TStringList read FFileList;

end;

function GetDroppedFiles (hDrop : THandle) : TDragDropInfo; procedure AcceptDroppedFiles (Handle : HWND);

procedure UnacceptDroppedFiles (Handle : HWND);

implementation

uses ShellAPI;

constructor TDragDropInfo.Create (ANumFiles : UINT); begin

inherited Create; FNumFiles := ANumFiles;

FFileList := TStringList.Create; end;

destructor TDragDropInfo.Destroy; begin

FFileList.Free; inherited Destroy;

end;

procedure AcceptDroppedFiles (Handle : HWND); begin

DragAcceptFiles (Handle, True); end;

procedure UnacceptDroppedFiles (Handle : HWND); begin

DragAcceptFiles (Handle, False); end;

function GetDroppedFiles (hDrop : THandle) : TDragDropInfo; var

DragDropInfo : TDragDropInfo;

TotalNumberOfFiles, nFileLength : Integer; pszFileName : PChar;

i : Integer;

begin

{

hDrop is a Handle to the internal Windows data

structure which has information about the dropped files.

}

{

Find out total number of files dropped by passing -1 for the index parameter to DragQueryFile

}

TotalNumberOfFiles := DragQueryFile (hDrop , $FFFFFFFF, Nil, 0);

DragDropInfo := TDragDropInfo.Create (TotalNumberOfFiles);

{

Determine if the files were dropped in the client area

}

DragDropInfo.FInClientArea :=

DragQueryPoint (hDrop, DragDropInfo.FDropPoint);

for i := 0 to TotalNumberOfFiles - 1 do begin

{

Get the length of a filename by telling DragQueryFile which file your querying about ( i ), and passing Nil

for the buffer parameter. The return value is the length of the file name.

}

nFileLength := DragQueryFile (hDrop, i , Nil, 0) + 1; GetMem (pszFileName, nFileLength);

{

Copy a file name.

Tell

DragQueryFile the file

you're interested in (i)

and the length of your buffer.

NOTE: Make sure that the

length is 1 more than the filename

to make room for the nul

character!

}

DragQueryFile (hDrop , i, pszFileName, nFileLength);

{Add the file to the string list } DragDropInfo.FFileList.Add (pszFileName);

{free the allocated memory... }

FreeMem (pszFileName, nFileLength); end;

{

Call DragFinish to release the memory that Shell allocated for this handle.

NOTE: This is a real easy step to forget and could explain memory leaks and incorrect program performance.

}

DragFinish (hDrop); Result := DragDropInfo;

end;

end.

In order to make the existing test program use the new interface, we just have to change a few lines of code. First, change the reference to unit ShellApi in the unit’s uses statement to FMDD. Then, change the form’s event handlers as shown in Listing 2.4.

Listing 2.4 Using the new File Manager Drag and Drop interface

procedure TForm1.FormCreate(Sender: TObject); begin

Application.OnMessage := AppMessage; FMDD.AcceptDroppedFiles (Handle);

end;

procedure TForm1.WMDropFiles (hDrop : THandle; hWindow : HWnd); var

DragDropInfo : TDragDropInfo; i : Integer;

begin

DragDropInfo := FMDD.GetDroppedFiles (hDrop);

{Determine if in client area } if DragDropInfo.InClientArea then

Label2.Caption := 'In client area' else

Label2.Caption := 'Not in client area';

{add each file to the list box }

for i := 0 to DragDropInfo.NumFiles - 1 do begin Listbox1.Items.Add (DragDropInfo.Files[i]);

end;

{ Destroy the DragDropInfo object } DragDropInfo.Free;

end;

procedure TForm1.FormClose (Sender: TObject; var Action: TCloseAction); begin

{ Don't accept files anymore } FMDD.UnacceptDroppedFiles (Handle);

end;

I don’t know about you, but I find it much easier to use this new interface. In the spirit of Delphi, we’ve removed the Windows handling code from our application’s code, and we’ve put it into a unit where we don’t have to look at it or worry about it. The FMDD unit handles all the mucking around in Windows internals and returns an object—something that we know how to handle. The result is less (and much cleaner) code that’s easier to write and maintain.

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.