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

(Ebook - Pdf) Kick Ass Delphi Programming

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

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!

-----------

To properly compute the height and width of the string that would be written on a tab, I had to resort to routines within the Win95 API. I learned a couple of interesting things in the process. First, the Height sub-property of the Font property in a component includes the height of a character (ascender part plus descender part), but not the internal leading which is used for special purposes, like displaying umlauts (those two little dots) above some international characters.

I wanted to know the true height, which is provided by a call to GetTextMetrics. I created a general-purpose function called FontHeight that would return the height of the font on a component, given a handle to that component and a handle to its associated font. A check is made within FontHeight to make sure the map mode is MM_TEXT, meaning the value returned is for the screen and will be measured in pixels.

The companion routine, StringWidth, uses a similar technique to pass a string to GetTextExtentPoint32. The return value is the approximate length (in pixels) that will be required to display the string. (The value is only approximate because it doesn’t account for any kerning done within a font.)

The SetTabSizes method is called by the form’s OnCreate handler to see if the tabs need adjusting. If this routine determines that both TabHeight and TabWidth properties for the PageControl have been set to a non-zero value during design, SetTabSize takes over and adjusts the sizes according to the font metrics and the longest caption.

The TabGrid function uses the TabWidth and X-coordinate information provided during the drag to determine the tab being referenced, and from that, it returns a pointer to the associated string grid. PageControlDragDrop also uses TabGrid to determine which string grid will receive the string that will be dropped.

Just One More Thing…

Listing 14.2 reflects some additional capability I just couldn’t resist adding to this example: the ability to drag an item from a string grid and copy or move it to one of the other grids by dropping it on the grid’s tab. This required writing a common OnMouseDown handler for the grids, and extending the OnDragOver and OnDragDrop handlers for the PageControl. I also added CopyDrag, a boolean flag that is set whenever the Ctrl key is pressed and a drag is started in any of the grids.

DropGridString performs the lion’s share of the work when items are dragged from a string grid to a tab. If the control key was not held down during the drag, DropGridString executes some extra steps that turn a straight copy into a move, clearing out the selected item from the source grid and then squeezing out the dead space.

An executing version of the demo is shown in Figure 14.2. This little application is really a lot of fun to play with. You can easily drag items back and forth between the pages, copying and moving, zigging and zagging. I think sharing event handlers is a lot more fun than attending a wedding. Especially my own.

FIGURE 14.2 The shared events demo app in action.

End of entry, March 29.

The fax machine in Ace’s office began to whirr. Helen immediately jumped to her feet.

“Ace, there’s a fax coming in,” she said. “Hurry—it must be the test results!”

Breakpoint crossed the room and deftly ripped the page from the machine, just as the beep indicated it had finished printing. “Now we’ll see which one of us is right about this Bohacker accusation,” he said smugly.

He stood there, staring at the page and fidgeting for nearly a minute before Helen couldn’t stand it any longer.

“Well, what does it say?” she demanded. “Was it Bohacker, or wasn’t it?”

“Uh, it isn’t completely clear. You see, these quick tests aren’t always conclusive, and—”

“Let me see that,” she said, grabbing the page from his hand. She quickly skimmed the report and then turned to her companion.

“It says right here—and I quote: ‘The test results indicate a nearly point-for-point match between the two samples, with a congruence in the 95th percentile, perfectly consistent with DNA tests of this type.’ That means the

hair and blood samples match, doesn’t it?”

“Well, yes,” Ace admitted. “But—”

“Then it must be Melvin Bohacker, just as I said. And whereever he is, you can bet Madame X is there with him. Now all we have to do is find out where he has gone.”

“Norton City.”

“What?”

“Norton City,” Ace repeated. “Biff told me earlier this evening that Bohacker was going to Norton City sometime tonight. Trust me on this.”

“But where in Norton City,” she asked. “He could be in any one of a hundred places.”

“I think I have a way to find that out,” Ace said, as he strode across the room and flipped on his computer. “I’m going online—and I’m going to get some answers!”

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!

-----------

Using Memory Files

Casebook No. 16, April 1: I guess one of the most-often asked questions about Delphi is how to write an application that can limit itself to one instance in the system. During the past year, I’ve discovered several ways to accomplish that goal. But one of them was so much fun I thought I would document it here.

For an application to detect another instance of itself, it must be able to query the system in some way. Under Win 3.1, an application could check a handle called hPrevInst to see if there was already an instance running. But that all changed with Win95.

One way to accomplish the goal would be to use the WalkStuf unit I developed earlier. Using the ModuleSysInstCount function would return a value that would indicate how many copies of the program were already running. It would be simple for the application to abort execution if that count was something other than zero. But that wouldn’t work with NT.

A common technique for communicating information between applications is the use of a unique global key that is accessible to multiple instances of a program. A classic example is the use of a unique file. When an application starts up, it checks for the presence of a file with a certain name (e.g., ‘FOOBAR99.DAT’). If the file is present, there is another instance of the program already running. If the file is not found, the newly instantiated program creates it. When the program shuts down, it deletes the file.

One problem with this approach is caused by anomalies such as system crashes and power failures. Since the “flag” (in this case, a file) has been stored on a non-volatile medium, it’s still there when the errant system is rebooted. Under those conditions, the first instance that comes along will see the file, assume another instance is running, and shut down. That means exactly zero instances of the program will run. Some manual housekeeping is required to remove the file and get everything back to normal.

Win95 offers a much nicer alternative through its shared memory files. This time, the files are in volatile memory (or at least it’s treated that way, even if it’s being swapped between RAM and the hard disk). And unlike many of the operations within Win95, memory files can be shared between processes.

I created a simple application to test the theory that memory files could be used to detect multiple instances of a program. The running application is shown in Figure 14.3, and its code appears in

Listing 14.3.

FIGURE 14.3 The single-instance program at runtime.

Listing 14.3 A simple single-instance program

{———————————————————————————————————————————————————}

{

The One Instance Demo

}

{

INSTMAIN.PAS : Main Form

}

{

By Ace Breakpoint, N.T.P.

}

{

Assisted by Don Taylor

}

{

 

}

{ Application that demonstrates how to prevent

}

{ more than one instance of a program from running

}

{ in the Win95 environment.

}

{

 

}

{ Written for *The Delphi Programming Explorer*

}

{ Copyright (c) 1995, 1996 The Coriolis Group, Inc. }

{

Last Updated 4/1/96

}

{———————————————————————————————————————————————————}

unit InstMain;

interface

uses

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

type

TForm1 = class(TForm) ExitBtn: TButton; Label1: TLabel;

procedure ExitBtnClick(Sender: TObject); private

{Private declarations } public

{Public declarations }

end;

var

Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.ExitBtnClick(Sender: TObject); begin

Close;

end;

end.

Of course, the form does nothing by itself. The idea is for a multiple instance to detect the presence of a previous instance and then shut itself down. And while this could be done in the startup code of the form, it is much more polite to accomplish this work in a way that doesn’t display the new instance at all. That means taking care of it before the application even begins.

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!

-----------

Before the Beginning

A lot of people don’t seem to know that it’s possible to execute code in the project file, even before the application is initialized. That’s the case here. The project file for this experimental application is shown in Listing 14.4.

Listing 14.4 Project file for the One Instance Demo

{———————————————————————————————————————————————————}

{

The One Instance Demo

}

{

ONEINST.DPR : Project File

}

{

By Ace Breakpoint, N.T.P.

}

{

Assisted by Don Taylor

}

{

 

}

{ Application that demonstrates how to prevent

}

{ more than one instance of a program from running

}

{ in the Win95 environment.

}

{

 

}

{ Written for *The Delphi Programming Explorer*

}

{ Copyright (c) 1995, 1996 The Coriolis Group, Inc. }

{

Last Updated 4/1/96

}

{———————————————————————————————————————————————————}

program OneInst;

uses Windows, Forms,

InstMain in 'InstMain.pas' {Form1};

const

MemFileSize = 1024;

MemFileName = 'one_inst_demo_memfile';

var

MemHnd : HWND;

{$R *.RES}

begin

{ Attempt to create a file mapping object } MemHnd := CreateFileMapping(HWND($FFFFFFFF),

nil, PAGE_READWRITE, 0, MemFileSize, MemFileName);

{ If it didn't already exist, then run the app… } if GetLastError <> ERROR_ALREADY_EXISTS

then begin Application.Initialize;

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

end;

CloseHandle(MemHnd);

end.

This is a kick. First, an attempt is made to create a file mapping object with the CreateFileMapping API call. Whether the object already exists or is actually created, a handle to the object is returned and assigned to MemHnd. Calling CreateFileMapping with a handle value of $FFFFFFFF causes the operating system to use its own paging file instead of the conventional file system, so the file can be shared between processes; all the process needs to know is the name of the file. Although the file is set up for read/write, a call is not made here to MapViewOfFile, which would give the program access to the file’s contents through a pointer. For the purpose of this example, it’s sufficient just to check for the file’s existence.

If the memory file already existed at the time of the call to CreateFileMapping, a handle to the file is returned to the caller, and an error value of ERROR_ALREADY_EXISTS is sent to the system. If that error isn’t found by GetLastError, it means there isn’t an instance already running, and it’s safe to go ahead.

Because a handle was returned whether or not the file was created, the handle must be closed before the application finally shuts down. The first program to call CreateFileMapping creates the file mapping object; the last program to close a handle to it causes the system to destroy the object. This is the equivalent of deleting the file.

End of entry, April 1.

Ace clicked the Print button on a dialog and his laser printer came alive. He printed four pages of information, then pulled the sheets from the tray and examined them.

“Now there’s no doubt in my mind,” he said with a newly found excitement in his voice.

Helen was tempted to say something about her being right after all, but thought better of it. Besides, Ace was heading for the door.

“I’m coming with you,” she said, picking up her raincoat and purse.

“Sorry, Baby,” Ace replied. “This one might be dangerous, so you’re staying here. Wait by the phone in case something goes wrong.”

“I suppose you’re right,” she said reluctantly. “But be careful, Sweetheart.” Then she tenderly kissed him on the lips.

“I should be back in an hour or so,” he said. “If you haven’t heard from me by then, call the cops. Tell them I’m on a mission to bring in Bohacker!” One more kiss and he was gone.

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!

-----------

Preventing Program Execution

Casebook No. 16, April 2: It was interesting to explore how to shut down a program when it finds a previous instance running. But something kept bugging me. What about the times you don’t want an application to run unless another program is running?

This is the case with several demo versions of components, such as the Orpheus VCL library. If you create an application using what TurboPower Software calls the “trial” version of their components, they require Delphi to be running in order for the application to execute. How could something like this be accomplished?

The answer was so simple I almost couldn’t believe it. The running version of this experiment is shown in Figure 14.4. The main form’s code is shown in Listing 14.5, and the project source is detailed in Listing 14.6.

FIGURE 14.4 The Delphi Environment Detector running.

Listing 14.5 Code for the No Run Demo’s main form

{———————————————————————————————————————————————————}

{

The "No Run" Demo

}

{

NRUNMAIN.PAS : Main Form

}

{

By Ace Breakpoint, N.T.P.

}

{

Assisted by Don Taylor

}

{

 

}

{ Main form for the application that demonstrates

}

{ how to prevent execution if Delphi 2.0 isn't

}

{ executing.

 

}

{

 

}

{ Written for *Kick-Ass Delphi Programming*

}

{ Copyright (c) 1996 The Coriolis Group, Inc.

}

{

Last Updated 4/2/96

}

{———————————————————————————————————————————————————}

unit NRunMain;