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

(Ebook - Pdf) Kick Ass Delphi Programming

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

statements are then performed to complete the subclassing process. First, a pointer to the owner’s original WndProc is stored in OriginalWndProc. Next, SetWindowLong is used to tell Windows that the MsgReceiver’s WndProc (pointed to by NewWndProc) is the new place to send messages to the owner. Finally, a boolean (WndProcHooked) is set to indicate the subclassing process has succeeded. If the DLL loads correctly, the MsgReceiver’s RegisterIDStr method will be called, which will in turn call

RegisterWindowMessage and set the FMessageID field.

The MsgReceiver’s WndProc checks the incoming event to see if it matches FMessageID. If so, it attempts to call the handler specified in the OnIDMessage property. If the event doesn’t match FMessageID, WndProc calls the MsgReceiver’s Dispatch method. Since there are no special message handlers defined for the MsgReceiver, the event is automatically passed to the MsgReceiver’s DefaultHandler method, where we simply use CallWindowProc to pass the message to the owner’s original WndProc. We have accomplished exactly what is illustrated in Figure 15.4.

What has all this gained us? We’ve set up a pre-processing system for the form containing the MsgReceiver. Instead of having to know exactly what we’re looking for (the message ID) and what we’re going to do when we get it (the handler) at compile time, we have shifted the whole decision-making process to execution time. (In fact, we could even dynamically switch both the message ID string and the procedure chosen to handle it at any time during the program’s execution. A frightening concept.)

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!

-----------

Other Interesting Stuff

Just as there is a way to subclass a window, there must be a way to restore the system when the program terminates. This feat is accomplished in a couple of places. If the component receives a WM_Destroy message, it must immediately restore the original messaging, before anything else takes place; otherwise, there will be no valid window by the time execution gets to the MsgReceiver’s Destroy destructor—an ugly situation. The Handle WMDestroy method takes care of this, setting the WndProcHooked variable False to indicate that subclassing has been eliminated.

The Destroy destructor accomplishes the same task, assuming subclassing is still in place when it is called. Once subclassing has been eliminated, the destructor can safely free the object instance for NewWndProc. Before calling the inherited destructor, though, the component is unregistered and the DLL is unloaded.

Two other interesting things happen within MsgReceiver’s OnCreate handler. First, before creating the component we must make sure the potential owner is a qualified, card-carrying member of the TWinControl family. If it isn’t, we won’t have a MainWndProc or WndProc to work with, and the results won’t be pretty. If the owner is not a TWinControl or descendant, an exception is raised before the inherited Create constructor can be called.

Second, we only want to allow one MsgReceiver component per form. Can you imagine keeping track of several levels of subclassing? Only if you’re a masochist. After the TWinControl test, a check is made for prior instances of a TMsgReceiver type in the owner’s list of components. If a prior is found, an exception is raised, and we’re outta here!

One last thing: MsgReceiver contains a read-only property called Receiver

Num, the value returned when the component is registered with the DLL.

Using the same overall procedure as I had used for the MsgSender, I created a bitmap for the TMsgReceiver object. Done at last—well, almost.

Creating a Receiver Demo

“You’re really doing well,” Dinah said. “I haven’t seen our guests this interested in a long time. Even Mr. Bohacker wasn’t able to command such attention.”

I suppose I needed the encouragement. But I realized that this time I really was doing well. I couldn’t believe how well the code was coming together. And to be able to pull this off under such extreme pressure made it all the sweeter.

And I really was commanding respect. Most of the programmers were intently watching my every move, hanging on every syllable leaving my mouth. Of course, there were a few exceptions. Probably 20 or 25 old fogies were napping at any given time. The three women sitting in the last row who I thought were knitting were actually surfing the Web through a wireless link to their laptop PCs. But there was one guy that really bugged me.

“Psssst. Psssssssst.” I leaned away from the microphone, attempting to attract Dinah’s attention. She finally looked up from the copy of Weekly World News she was perusing.

“What’s with the guy in the leftmost seat in the front row?” I whispered. “He’s been sitting there this whole time, just staring off into space. I haven’t even seen him blink.”

“That’s Herbie,” she whispered back. “He’s a little, uh, you know… We just say he’s in Permanent Screen Saver mode.”

I pulled the candy bar out of my pocket and tore off the wrapper. I still had two applications to write, and I was in need of some extra energy. I bit off the end of the bar and nearly gagged. The Foo Bar was the candy confection universally chosen by programmers worldwide. Its delicate balance of fat calories, sugar, and caffeine made it the perfect productivity snack food. Today I had grabbed a Foo Bar++ from the machine, thinking it would have even more of the ingredients my body needed to make it through this endless afternoon. It wasn’t until I had snarfed a big bite that I realized the ingredient that had been added for extra boost was ground dried prunes. I took a gulp of water from the glass perched on the lectern and then shoved the remainder of the bar back in my pocket.

With the component design complete, I needed to create a demo application for each component—two programs that would highlight most of the features of the components.

From the several suggestions pitched at me by the audience, I chose a scenario where a sender application would send predetermined codes to a receiver, causing it to set a series of indicators. We decided to emulate the little lights on some automobile odometers that indicate when you should change your oil or filter, or rotate your tires. The receiver demo app would illuminate red or green indicators to indicate the condition, as transmitted by a sender app. In fact, we

could have multiple instances of both sender and receiver apps if we wished; the methods we had chosen for communication should support that concept.

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!

-----------

I decided to write the receiver demo first, because it seemed the easier of the two. In fact, it was pretty simple. The first thing was to come up with a set of command constants to use for private message IDs. I developed the Constants unit shown in Listing 15.7.

Listing 15.7 Constants for the Sender and Receiver demo applications

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

{

Message Broadcasting in Delphi 2

}

{

CONSTANT.PAS : Constants Unit

}

{

By Ace Breakpoint, N.T.P.

}

{

Assisted by Don Taylor

}

{

 

}

{ Constants for use by the Sender and Receiver

}

{ applications.

}

{

 

}

{ Written for *Kick-Ass Delphi Programming*

}

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

}

{

Last Updated 5/2/96

}

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

unit Constant;

interface

const

{ Command codes } mdSetAll = 100; mdSetChangeOil = 101; mdSetChangeFilter = 102; mdSetRotateTires = 103;

mdResetAll = 200; mdResetChangeOil = 201; mdResetChangeFilter = 202; mdResetRotateTires = 203;

{ Status codes } mdNoReply = 0; mdReady = 1; mdSuccess = 2; mdRcvChange = 3;

implementation

end.

Creating the Receiver demo was a breeze. A picture of the design version, next to the Object Inspector, is shown in Figure 15.5. The code is shown in Listing 15.8.

FIGURE 15.5 The Receiver demo at design time.

Listing 15.8 Code for the Receiver demo

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

{

Message Broadcasting in Delphi 2

}

{

RECVMAIN.PAS : Receiver Main Form

}

{

By Ace Breakpoint, N.T.P.

}

{

Assisted by Don Taylor

}

{

 

}

{ This demo application receives commands from

}

{ the Sender application, through the use of the

}

{ MsgSender and MsgReceiver components.

}

{

 

}

{ Written for *Kick-Ass Delphi Programming*

}

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

}

{

Last Updated 5/2/96

}

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

unit RecvMain;

interface

uses

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

StdCtrls, ExtCtrls, MsgRcvr, Constant;

type

TReceiverForm = class(TForm) ExitBtn: TButton; MsgReceiver1: TMsgReceiver; Panel2: TPanel;

HndLabel: TLabel;

Label2: TLabel; RcvNumLabel: TLabel; Label1: TLabel; Panel1: TPanel;

Panel3: TPanel;

Bevel1: TBevel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Bevel2: TBevel; ChangeOilInd: TPanel; Bevel3: TBevel; ChangeFiltInd: TPanel; Bevel4: TBevel; RotateInd: TPanel;

procedure ExitBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); function MsgReceiver1IDMessage(wParam: Word;

lParam: Longint): Longint; private

{Private declarations } public

{Public declarations }

end;

var

ReceiverForm: TReceiverForm;

implementation

{$R *.DFM}

procedure TReceiverForm.ExitBtnClick(Sender: TObject); begin

Close;

end;

procedure TReceiverForm.FormCreate(Sender: TObject); begin

HndLabel.Caption := IntToStr(Self.Handle); RcvNumLabel.Caption := IntToStr(MsgReceiver1.ReceiverNum); ChangeOilInd.Color := clYellow;

ChangeFiltInd.Color := clYellow; RotateInd.Color := clYellow; end;

function TReceiverForm.MsgReceiver1IDMessage(wParam: Word; lParam: Longint): Longint;

begin

case wParam of

mdSetChangeOil : ChangeOilInd.Color := clRed; mdSetChangeFilter : ChangeFiltInd.Color := clRed; mdSetRotateTires : RotateInd.Color := clRed; mdResetChangeOil : ChangeOilInd.Color := clLime; mdResetChangeFilter : ChangeFiltInd.Color := clLime; mdResetRotateTires : RotateInd.Color := clLime;

end; { case }

Result := mdSuccess;

end;

end.

The centerpiece of the Receiver demo is the MsgReceiverIDMessage method. This is the handler specified in the OnIDMessage property of the MsgReceiver component. MsgReceiverIDMessage tests the wParam portion of the message to set the colors of the three indicators. It then returns a message result of mdSuccess, which will be returned to the MsgSender component issuing the command.

I could have simply defined a string constant for the IDString property of the MsgSender and MsgReceiver components in my Constants unit, and then assigned the string to the properties of each of the components at runtime. I guess after all this mysterious mumbo-jumbo, I was overcome by a fit of conformity to the standard way of doing things.

To demonstrate the ability of a MsgReceiver to get the index number assigned by the DLL, I displayed ReceiverNum in the top panel of the Receiver form. I also displayed the form’s handle value, the same value that would be registered by the DLL.

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!

-----------

Creating a Sender Demo

“That receiver demo-thingy isn’t such a big deal,” said the old man with the bucket of chicken, as he took a big bite out of a thigh. “I could do just as well—even on one of my ‘bad’ days.”

“Me, too,” said the bald and toothless old geezer sitting next to him, as he wiped off the grease running down his friend’s chin with a paper towel.

“Any of us could, in the Old Days,” someone agreed.

“Yeah, we didn’t have it so easy back then,” came another voice. “Didn’t have all these new-fangled development tools. Had to walk ten miles to school in the snow. And the only debugger we had was a can of Raid.”

“You think that’s bad?” someone else chimed in. “We had to walk 50 feet across ice-cold linoleum, just to get from our cubicles to the vending machines. And we had to write everything in assembly code.”

I looked around the room. It was getting more tense by the moment.

“You’re all a bunch of dweebs,” said a heavy-set man in the fifth row, as he stood up and faced the crowd. “You all go around humming the background tunes from Doom episodes. Where I was working, we didn’t even have assemblers. We had to write everything with ones and zeros. There were times we ran out of ones, and we had to make do.”

The scene probably would have turned into a full-scale riot, except for a fortuitous event. Suddenly, the door at the back of the room flew open and hit the wall so hard it sounded like a small explosion. Everyone instantly stopped arguing and turned to the door to see who had made the noise, and as they did I could hear several people suck in their breath. Framed in the doorway was a tall, slender man with a grizzled face and a toothpick protruding from between his lips. His full-length coveralls were sky-blue, an insignia adorning the left breast pocket, and he wore a leather belt with a spray bottle hanging low from each side. In his right hand he held a rubber squeegee.

“Anybody seen Eddie today?” he growled, the toothpick following every movement of his lower lip. He stood there for several seconds, pounding the business end of the squeegee against the palm of his left hand. Receiving no answer to his question, he eventually grunted something indiscernible and then ambled on down the hallway.

I shot Dinah a questioning glance, and she responded without my having to ask.

“That was Brad, our Chief of Janitors,” she explained. “He’s looking for Eddie Rivers, one of our, well, problem guests.”

“A man with a problem? Doesn’t sound at all unusual. Everybody here seems to have some problem or another.”

“Not Eddie. His is a recurring problem. Error 212: Stream registration error. It happened three times, yesterday alone.”

I turned to face the audience. The crowd had once again quieted down, and it was now time for the final piece of this whole puzzle—a demo that would transmit commands to the Receiver demo. But I wanted the Sender demo to be much more. After all, I was up against Bohacker again, and my reputation was on the line. I had to perform Big Time.

I decided to pop a timer on the form, to force a periodic query of what the DLL had registered. By monitoring that information, I could pull off some pretty cute stuff. A snapshot of the design version of the form is shown in Figure 4.6. The final version of the code is detailed in Listing 15.9.

FIGURE 15.6 The Sender demo at design time.

Listing 15.9 Code for the Sender demo

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

{

Message Broadcasting in Delphi 2

}

{

SENDMAIN.PAS : Sender Main Form

}

{

By Ace Breakpoint, N.T.P.

}

{

Assisted by Don Taylor

}

{

 

}

{ This demo application sends commands to the

}

{ Receiver application, through the use of the

}

{ MsgSender and MsgReceiver components.

}

{

 

}

{ Written for *Kick-Ass Delphi Programming*

}

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

}

{

Last Updated 3/31/96

}

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

unit SendMain;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, MsgSendr, ExtCtrls, Constant;

type

TSenderMainForm = class(TForm) SendBtn: TButton;

ExitBtn: TButton; MsgSender1: TMsgSender; RefreshTimer: TTimer; RecipientGroup: TGroupBox; AllRB: TRadioButton; OneRB: TRadioButton;