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

(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!

-----------

Listing 3.11 Implementing shared memory in a DLL

library shareme;

uses Windows, SysUtils, Classes;

const

pCounter: ^Longint = nil;

function GetProcessCount : Longint; stdcall; export; begin

Result := pCounter^; end;

procedure MyDLLHandler (Reason: Integer);

const

 

 

 

hMapObject : THandle = 0;

 

var

 

 

 

fInit

: Boolean;

 

 

begin

 

 

 

case Reason of

 

 

DLL_PROCESS_ATTACH : begin

{

create a named file

mapping object }

hMapObject := CreateFileMapping (

 

$FFFFFFFF,

{

use paging file }

 

nil,

{

no security attributes }

 

PAGE_READWRITE,

{

read/write access }

 

0,

{

high 32 bits of size }

 

sizeof (longint), {

low 32 bits of size }

'SharedMem'

{ name of object }

);

{the first process to attach initializes the memory } fInit := (GetLastError <> ERROR_ALREADY_EXISTS);

{get a pointer to the file-mapped shared memory } pCounter := MapViewOfFile (

hMapObject,

{ object to

map view of }

FILE_MAP_WRITE,

{ read/write access }

0,

{ high 32-bits of offset }

0,

{

low 32-bits of offset }

0

{

default:

map entire file }

);

{ initialize or increment the count } if (fInit) then

pCounter^ := 1 else

pCounter^ := pCounter^ + 1;

end;

DLL_PROCESS_DETACH : begin

{decrement the count } pCounter^ := pCounter^ - 1;

{unmap shared memory from the process's address space } UnmapViewOfFile (pCounter);

{close the handle to the file mapping object } CloseHandle (hMapObject);

end;

(*

Thread attach and thread detach aren't handled

DLL_THREAD_ATTACH :

DLL_THREAD_DETACH :

*)

end;

end;

Exports

GetProcessCount index 1 name 'GetProcessCount';

begin

DLLProc := @MyDLLHandler; MyDLLHandler (DLL_PROCESS_ATTACH);

end.

You should take special note of the two lines of code in the DLL’s initialization section. The first line of code initializes the System unit’s DLLProc variable to point to the DLL’s handler function. I thought that this was all that was required, but it appears that Delphi won’t call the handler with a DLL_PROCESS_ATTACH value. So, the library’s initialization code calls its own handler function. In my opinion, this is a bug in Delphi’s handling of DLL initialization.

To test the shared memory, create a form that calls the DLL’s GetProcessCount function when the form is created, and have it display the count in a label field on the form. If you run multiple copies of the application, you should see the counter increment once for each process that attaches to the DLL. If you close one or more of the applications and open new ones, the process counter should reflect the net effect (that is, if you opened three, closed one, and then opened another, the last one you open should have a process count of 3).

Global memory handles like those allocated by SHAREME consume valuable Windows resources, so be careful how you allocate them. If you’ll be sharing a lot of different fields from a single DLL, you should put them all together into a single memory block (i.e. a record), and allocate just one memory block for the entire structure. This will minimize the Windows resources that the program uses. And be sure that your DLL correctly frees the memory blocks. If your DLL crashes or otherwise exits without freeing the memory block, that memory and the Windows resource will remain allocated until you reboot Windows. There is no way to free it once you’ve trashed the handle to the memory block.

Movin On!

If you’re interested in digging, there’s lots of stuff to learn about DLLs. In this chapter, I’ve given you enough information for you to go exploring. If you have the Microsoft Developer’s Network CD-ROMs, you’ll want to look up DLLs in the index and read everything you can find. You also should learn more about CreateFileMapping and related file mapping functions, paying special attention to the differences between Windows 95 and Windows NT. You can do a lot of cool things with DLLs, but you’ve got to be careful. Good luck!

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!

-----------

CHAPTER 4

The Delphi Winsock Component

JOHN PENMAN

Encapsulating Winsock In A Component

Resolving Internet Address

Asynchronous Host Name Resolution

Cancelling An Asynchronous Operation

Resolving Ports And Services

Resolving Protocols

Objects are good…but components are better. Let’s make Internet access for Delphi a plug-and-play proposition by putting all our Winsock baggage into a VCL component.

The Internet—and networked environments in general—becomes more

popular every day. It’s natural, therefore, for programmers to want to integrate network services into their applications. Under Microsoft Windows, the Winsock API is the lingua franca for Internet access. Using the Winsock component described in this chapter as a starting point, you’ll soon be implementing many familiar TCP/IP-based programs such as FINGER, FTP, SMTP, POP3, and ECHO applications.

What Is Winsock?

Winsock is an abbreviation for Windows Sockets, an interface layer between a Windows application and an underlying TCP/IP network. The sockets interface originated with Berkeley Unix as the API to its TCP/IP network

stack. Winsock is based on the Berkeley Sockets API and includes most of the standard BSD API functions, as well as some Windows-specific extensions. Adding TCP/IP networking capability to your Windows programs is as simple as using the Winsock API and dynamically linking with WINSOCK.DLL, the library that implements Winsock.

The easiest way for a Delphi programmer to interface with the Winsock API is as a component. In this chapter, we’ll do just that by creating the WSock component, encapsulating the Winsock API. This produces several immediate benefits:

The API becomes part of the Delphi VCL;

Encapsulation promotes easier code reuse;

The client application sees a clean interface using properties and methods.

The WSock component is certainly Delphi-friendly, but it’s not comprehensive. WSock provides the framework you’ll use to create daughter components designed to handle any particular Internet protocol. A Winsock component already equipped to handle every conceivable Internet protocol would be a fat and complicated component. Instead, we’ll use the WSock component as the basis for new components that deal specifically with a particular protocol.

For example, creating a component for the Hypertext Transfer Protocol (HTTP) involves three steps:

1.Derive a new component from WSock.

2.Set the Service property to HTTP in the new component’s constructor.

3.Add the appropriate methods and properties for handling HTTP.

We’ll go through these steps in the next chapter to create a specific component for an FTP client application.

Dissecting WSock

The WSock component is based on the non-visual TWSocket class that, it turn, descends from TComponent. Because it’s non-visual, TWSocket is like a foundation of a house, normally hidden from view. The TComponent class provides the necessary methods and properties that WSock requires—but no more. Had I used TGraphicControl as an ancestor, the resulting TWSocket class would be more powerful, but with a corresponding increase in complexity and overhead. WSock provides the basic framework to set up and maintain a TCP/IP connection and supports both stream (TCP) and datagram (UDP) sockets.

To simplify the task of building TCP/IP networking components for Internet applications, our ideal Winsock component must perform the following basic housekeeping functions:

Start and stop Winsock;

Resolve host names and perform other conversion operations;

Create, maintain and destroy a connection (both TCP and UDP);

Send and receive data over a connection.

Like all networking life-forms, our Winsock component must initialize, clean up after itself, and report errors. Listing 4.1 shows the TWSocket class that performs these functions and much more. The majority of methods are in the protected section in the TWSocket class so that scion components can use them. These methods remain invisible to the client applications.

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!

-----------

Listing 4.1 The TWSocket Definition

unit WSock; interface

uses

SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs;

{$I wsapintf} (* Winsock implementation declarations *)

const

WSockVersionNo : String = '1.10'; WSockBuildDate : String = '190596';

SOCK_EVENT

=

WM_USER + 1;

 

ASYNC_EVENT

=

SOCK_EVENT +

1;

type

TAsyncOperationDone = procedure (Sender : TObject;

sSocket : TSocket) of object;

TConditions = (Success, Failure, None);

THostAddr = (HostAddr, IPAddr);

TOperations = (SendOp, RecvOp, NoOp);

TTypeOfCalls

= (Blocking, NonBlocking);

TSockTypes

= (SockStrm, SockDgram, SockRaw);

TServices

= (NoService, Echo, Discard,

Systat, Daytime, Netstat, Qotd, Chargen, ftp, telnet, smtp, time, rlp, nameserver, whois, domain, mtp, tftp, rje, finger, http, link, supdup, hostnames, ns, pop2,pop3, sunrpc, auth, sftp, uucp_path, nntp);

TProtoTypes = (IP, ICMP, GGP, TCP, PUP, UDP);

TAsyncTypes = (AsyncName, AsyncAddr, AsyncServ,

AsyncPort, AsyncProtoName, AsyncProtoNumber);

const

NULL : Char = #0;

{ This is required for end of data sent to host } CRLF : array[0..2] of char = #13#10#0;

MaxBufferSize = 255;

{strings for services property}

ServiceStrings : array[TServices] of String[10] = ('No Service',

'echo

',

'discard

',

'systat

',

'daytime

',

'netstat

',

'qotd

',

'chargen

',

'ftp

',

'telnet

',

'smtp

',

'time

',

'rlp

',

'nameserver',

'whois

',

'domain

',

'mtp

',

'tftp

',

'rje

',

'finger

',

'http

',

'link

',

'supdup

',

'hostnames ',

'ns

',

'pop2

',

'pop3

',

'sunrpc

',

'auth

',

'sftp

',

'uucp-path ',

'nntp

');

{ protocol strings }

 

ProtoStrings : array[TProtoTypes] of String[4] =

('ip

',

'icmp',

'gcmp',

'tcp ',

'pup ',

'udp ');

type

 

 

 

CharArray

= array[0..MaxBufferSize] of char;

TAddrTypes

= (AFUnspec,

{ unspecified}

 

AFUnix,

{ local to host (pipes, portals) }

 

AFInet,

{ internetwork: UDP, TCP, etc. }

 

AFImpLink,

{ arpanet imp addresses }

 

AFPup,

{ pup protocols: e.g. BSP }

 

AFChaos,

{ mit CHAOS protocols }

 

AFNs,

{ XEROX NS protocols }

 

AFIso,

{ ISO protocols }

 

AFOsi,

{ OSI is ISO }

 

AFEcma,

{ european computer manufacturers }

 

AFDatakit,

{ datakit protocols }

 

AFCcitt,

{ CCITT protocols, X.25 etc }

 

AFSna,

{ IBM SNA }

 

AFDecNet,

{ DECnet }

 

AFDli,

{ Direct data link interface }

 

AFLat,

{ LAT }

 

AFHyLink,

{ NSC Hyperchannel }

 

AFAppleTalk,

{ AppleTalk }

 

AFNetBios,

{ NetBios-style addresses }

 

AFMax);

 

const

 

 

 

ServDefault

=

NoService;

ProtoDefault

=

TCP;

 

SockDefault

=

SockStrm;

 

AddrDefault

=

AFINET;

 

PortNoDefault =

0;

 

type

 

TWSocket =

class(TComponent)

private

 

{ Private

declarations }

FValidSocket : u_int;

FParent

: TComponent;

FSockType

: TSockTypes;

FService

: TServices;

FProtocol

: TProtoTypes;

FAddrType

: TAddrTypes;