Open navigation menu
Close suggestions
Search
Search
en
Change Language
Upload
Sign in
Sign in
Download free for days
0 ratings
0% found this document useful (0 votes)
479 views
Delphi in A Nutshell
Uploaded by
Görkem Polat
AI-enhanced title
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF or read online on Scribd
Download now
Download
Save Delphi in a Nutshell For Later
Download
Save
Save Delphi in a Nutshell For Later
0%
0% found this document useful, undefined
0%
, undefined
Embed
Share
Print
Report
0 ratings
0% found this document useful (0 votes)
479 views
Delphi in A Nutshell
Uploaded by
Görkem Polat
AI-enhanced title
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF or read online on Scribd
Download now
Download
Save Delphi in a Nutshell For Later
Carousel Previous
Carousel Next
Save
Save Delphi in a Nutshell For Later
0%
0% found this document useful, undefined
0%
, undefined
Embed
Share
Print
Report
Download now
Download
You are on page 1
/ 576
Search
Fullscreen
y ‘i y DELPHI IN A NUTSHELL A Nesktop Quick ReferenceA Desktop Quick Reference Ray Lischner Beijing + CumirigDelphi in a Nutshelt by Ray Lisehner Copynght © 2000 OReilly & Associates, Inc. All nghts reserved, ranted in the United States of America Published by O'Reilly & Associates, Inc, 101 Mortis Street, Sebastopol, CA 95472, Editor: simon Hayes Production Editor: siuiclense Newell Cover Designer: ‘lie Volckhausen Printing History: March 2000: First Edition. "Nutshell Handbook, the Nutshell Handbook logo, and the O'Reilly logo are registered trademarks of O'Reilly & Associates, Inc. The assocration between the image of a Ivnx and the topic of Delphi isa trademark of O'Reilly & Asseerates, Tne Many of the designations used by manufacturers and sellers to distinguish their products are clasmed as trademarks. Where those designations appear in this book, and O'Reilly & Associates, Inc. was aware ofa trademark claim, the deagnations have been prnted in caps of initial caps. While every precaution has been taken inthe preparation ofthis book, the publisher assumes no responsibilty in exits or umssions, of for damages resulting from the Use of the information contained heresn, Library of Congress Cataloging-in-Publication Data Lschner, Ray, 1961— Delph un a nutshell / by Ray Lischner ecm ISN 1-56592-059-5 (alk. paper) 1. Delphi (Computer file) 2. Computer software—evelopment I. Title (QA7676.D47 156 2000 005.208-de2 99-086244 ISBN: 1-56592.059.5 (7/001 wmTable of Contents Preface Chapter 1—Delpbi Pascal Units Programs Libraries Packages Data Types Variables and Constants Exception Handling. File YO. Functions and Provedures Chapter 2—The Delphi Object Model Classes and Objects Interfaces, Reference Counting Messages soe Memory Management... Old-Seyle Object Types Chapter 3—Runtime Type Information Virtual Method Table Published Declarations ‘The Typlnfo UnitVirtual and Dynamic Methods Initialization and Finalization Automated Metiuds Interfaces Exploring RTT Chapter 4—Concurrent Programming ‘Thread and Processes The TThread Class ‘The BeginThread and EndThread Functions .. Thread Local Storage Processes Futures Chapter 5—Language Keference Chapter 6—System Constants Variant Type Codes Open Array Types Virtual Method Table Ottsets Runtime Error Codes, Chapter 7—Operators Unary Operators ‘Muldplicaive Operators Additive Operators Comparison Operators Chapter 8—Compiler Directives Appendix A—Command-Line Tools Appendix B—The SysUtils Untt Index 90 n a oo) 35 103 108 109 109 19 127 422 22 23 424 25 428 428 430 81 432 435 473 488 543Preface Borland’s Delph is a combination of a modem programming language, an inte- trated development environment (IDE), and the visual component library (VCL) Delphi's IDE i readily familiar 19 anyone who has wee smi tools. Ror example, 4 WYSIWYG form editor lets you design a window visually, with drag-and-drop cape, Mute inporany, tie framework 18 objectonented, extensible and custom able, due to the power and flexibly of the Delphi programming language. The hear of Delphi is the Delphi Pascal programming language, which has key features to support the IDE and VCL. It has all the power of a’ modem object nented langsinge, along withthe elegance and simpliciyy of Pascal Debbi in a Nutsbell is a comprehensive reference manual for Delphi Pascal t covers the entice language, and it also highlights ways to use the language efec- tively Eapctieuced Delphi prugraumers cat use dhs book as an alphabeical reference, Newcomers to Delph should spend exta time with the first few chap- ters. [hope that everyone wil find something of value in these pages. Not Your Father's Pascal Delphi Pascal is one of many object-onented variants of Pascal. Over the years Delphi has evolved and is no longer recognizable as the Pascal you used in school all those many years ago. In addition wo unitbused audular programy andl robust class model, Delphi Pascal has a number of other modem language features, including the following: © Intertaces (similar to Java™ and COM sntesfaces) + Unicode stangs + Properties + Exception handlingDelphi started as a Windows programming language and envitonment, and many Delphi programmers (myself included) consider Delphi to be the best Windows development tool available. Deiphr includes full support for COM and ActiveX, an, objectonented widget library (called the Visual Component Library, or VCL). and. 4 rapid-application development environment that 1s extensible and customizable, Delphi for Linux AAS Lite this, Borland is hard at work porting Delphi to Linux. Peshaps when you ‘ead this, Delph for Linux will be available, bringing its integrated development enuonmient fo X-Windows, including ts WYSIWYG form edlfor, multtier data base support, and full CORBA suppor. Until Borland finishes this work and releases Delphi for Linux, can only specu- late abour how the final product will look. (No, T don't get any specal msde snformation.) You can rely on the core language heing the same in both Delphs for lunux and Delphi for Windows, including classes, objects, interfaces, strings, dynamic arrays, exception, aut the basic data types. Most of the builtin subrou tines will work the same under Linux as under Windows Some language features described in this book are clearly Windows specific, such as the CéShow and Dl1Proc vanables or the Pindifinstance function. If you Want to write code thar 1s portahle herween Windows and Linux, you must avoid these Windows-specific features, Delphi for Windows 1s the best development environment for writing Windows applications and libraries. To attaun this preaues poston, Delph has incorporated. a number of Windows-specifc features. Borland has a goal of making Delph for Linux the best Liqux development environment. To achieve that goal, we can expect Delphi ta include some Linux-specfic features, ‘Ym just guessing. but I believe ic will he foasihle to write code that 1s portable between Windows and Linux. However, you will have to sacrifice some features that are unique to each envirumuent. Wrtung components that are easily portable, specially interactive controls, will probably be a daunting task. Making an appli- cation that is portable will most likely be easier, About This Book ‘The first four chapters of this book present information om haw effectively, and subsequent chapters form the language reference proper. Chapter 1, Delpbi Pascal, discusses the differences between Delphi Pascal and ‘sandard Pascal. If you have used Tusbo Paceal or other variants of Object Pascal, you should ge Chapter 1 a quick read to lear about the new features that are unique t0 Delphi Pascal. Similarly, if you haven't used Pascal since your college days (all those years ago). you must rearl Chapter 1 to leatn about the new and. nifty features in Delphi Pascal. You mught be surprised at how far the language hhas come over the yeas Chapter 2, The Dolpbr Object Model, discusses classes an Ulyeuts m greater depth. If you have used other vanants of Object Pascal, you must read this chapter ise Delph bill Preface ae —_ abecause Delphi's object model 1s quite different. IF you have experience with other ‘object-onented programming languages, read Chapter 2 to learn the differences between Delp sind valet languages, sult a9 Java snd Or Chapter 3, Runtime Type Information, covers the key to Delphits integrated devel ‘opment environment. RTTI 1s not documented in Borland!’ offical help files, but anyone writing or using components (that 1s, every Delphi programmer) should understand the nature of RTTT, including its imitations and proper uses. Chapter 4 tells you everything there is to know about RTTI, and then some. Chapter 4, Concurrent Programming, 36 about using Delphi in a modern, muli- threaded, multiprocessor world. Delphi includes several language fearues to help ‘you write multithreaded applicauons, but these features can be difficult to use if you do not have much expenence with the ticks and traps of multithreaded programming. This chapter gets you started uting Delphi elfectively to write ‘modern applications, Chapter 5, Language Reference, 8 the bull of the book. The alphabetical refer- cence lists every keyword, direcuve, subrouune, type, and vanuble an the Delpla Pascal language and its system units. Full examples show you how to use the language correctly and effectively Chapter 6, System Constants, contains tables of related constants, Chapter 51s large fenonigh without adding these literals Maving them 10 a separate chapter makes the complete reference easier to use. Chapter 7, Operators, describes all the arithmetic and other operators in Delp Pascal. Symbols do not alphabetize wel, so listing the symbol operators in thet con chapxer makes i ease find information about a particular operator. Chapter 8, Compiler Directives, lists all the specal comments that you can melude sn yout source code to control how Delphi compiles and links your program. Appendix A, Command-time Tools dscns the usage and options for the vanious ‘commandline tools that come with Delphi, These tools are not related to the Delpin Pascal language, but they are often overlooked and can be extremely ‘seful for the Delph profesional Append B, Tho Syst: Uni list all the subroutines, ypes, nd varables in the SyaVtils unit. This unit not bul nto the compiler (asthe System uni 1). Its ‘not part of the Delpht Pascal language, but 13 part of Deiphi's euntime lbeary Nonetheless, many Delphi professionals have come to rely on SysUtils as though ic were part of the language, and indeed, many subroutines in SysUeils are supe- tiv dew eyuivaeuts is Use Syste uk (oul ay AusiPus used Uf FOS) Conventions Used in This Book ‘The following typographical conventions are used sn this book Constant width Used for Delph entifcrs sud symbols, uicludling all keywords aud dite tives. In the language seference, constant wicth shows the syntax elements that must be used exactly as Shown. For example, the array declaration Prefacerequires the square brackets and other symbols. and the tyne, array, and of keywords to be used as shown: type name = array(Index type, ...] of nase type: Constant width italic Used in the language reference for syntax elements that must be replaced by your code. In the previous example, you must supply the type Name, the Index type, and the Rase type. Constant Width Bold Used in longer code examples to highlight the lines that contain the language ‘element being described. alte Used to indicate variables, filenames, directory names, URLs, and glossary Note Icons the ourrounding text. g ‘The owl icon designates a tip, suggestion, or general note related to & ‘The turkey icon designates a warning related to the surrounding tex. For More Information ‘When you have a question about Delph, you should fist consult the Delphi help files. Delphi also comes with numerous examples (in the Dems directory) that are ‘often more helpful than the help files, 1f you still cannot find the answer you seek, try posing your question to one of the many Delphi newsgroups. Several standard newsgioups exist, and Borland mai. tains its own newsgroups on its server, forums.borland com. In panticula, oriand pubic. delphi.objectpascal 1s the appropriate newsgroup for questions related to the Delphi Pascal language If you want to know about Delphi's integrated development environment, about the visual component library, or other topics on Delphi programming, the two ‘most popular books are Mastering Delphi 5, by Marco Cann (Sybex, 1999) and Delph 5 Developer's Guide, by Steve Terxesra and Xavier Pacheco (Sams, 1999), If you find errors or omissions an this book, please bring them to my attention by sending email to nussbell@iempest-sw:com. I receive t00 much email to answer © Preface‘every message indivdually, but be assured that I tad everything (everything that makes it past my anti-spam fiers, anyway). How to Contact Us “The information in this book has bon tested and verified to the best of our ability, Dut mustakes and oversights do occur. Please let us know about ettors you may find, as well as your suggestions for future editions, by writing to: Oxeilly & Associates, Inc 101 Morns Street Sebastopol, CA 95472 (800) 998-9938 Gin the U.S. ot Canada) (707) 820-0515 (international or local) (707) 829.0104 (fax) ‘You can also send us email messages. To be put on our muzling list or to request a catalog, send mail to: ‘
[email protected]
To ask technical questions or to comment on the book, send email to: bookquestionstorelly com To find out about errata and any plans for fuure editions, you can access the ook’s web site at eww oreily.comieatalog/delphs For more information about ths book and others, see the O'Reilly web site sun oreilly.com Acknowledgments I thank Tim O'Reilly for taking a chance with his fist Delphi tile. I look forwaed to reading and writing other Delphi boolis published by O*Relly “The technical editors—Allen Raner and Hallvard Vasshotn—did an excellent ob of spotting my mistakes. Hallvard's copious and detailed comments were snvahuable. Any remaming mistakes are ones that Cade afl Une ediors finshed thes ao cough work. 1 thank my editor, Simon Hayes, and the entice team at 'Reily—Bob Herbstman, ‘Troy Mot, and the design and production staff—for turning my humble manu- scp soto this polished book you tee now None of my books would be possible without the suppor of family 1 thank my wife, Cheryl, and the once-and-future programmer, Anus, who makes it all wworthtie PrefaceCHAPTER 1 Delphi Pascal Delph Pascal 1 an objectonented extension of wadtionl Pascal. It is not quite a proper superset of ISO standard Pascal, but if you remember Pascal from your School days. you will easy pick up Delphi's extensions. Delph not ps a fancy Pascal, though. Delphi adds powerful object-oriented feaures, without making the lungusge woo complicated. Delph tas asses and objects, exception handling, multithreaded programming, modular programming, dynamic and static linking, OLE automaton, and much, much more ‘Thus chapter describes Delphi's extensions to Pascal, You should already be familar woth tridtional Pascal or one of the other poplar extensions to Pascal, such as Object Pascal. If you already know Borland's Object Pascal from the Turbo Fascalproduets, yOu Will need to leam a new object model (detailed in Chapter 2, ‘The Delpbs Obyct Model), plus other new Features, Bottand uses the name “Object Pascal” to refer to Delphi's programming language, Dut many other languages use the same name, which resuls in confusion. This book uses the name "Delphi Pascal” to refer to the Delph programuning language, leaving Object Pascal forthe many other obyct-orented variations of Pascal Units Delphi Pascal is a modular programming language, and the basic module is called ‘unit To compile and link a Delphi program, you need a program source file and any number of additional units sn sousce or abject form. The program source fle w usually called a project source file because the project can be a program or a library—that is, a dynamucally linked library (DLL). When Delphi links a program or library, it can statically like all the units into a Single exe ur all Ble, or Gu dymaanically link wo unis dhat ure an packages. package 1s a special kind of DLL that contains one or more units and some extra logic that enables Delplu to hude the differences between a statically linked unitand a dynamically linked unit in a package See the section “Packages,” later in thus chapter, for more information about packages, Forms and Files Some units represent forms. A form is Delphi's term for a window you can edit with Delphi's GUL builder. A form descnption is stored in a .dfm file, which contains the Forme layout, contents, aad prupeties Every fm file has an associated pas file, which contains the coe fur dia form, Forms and .dfm files are part of Delphi's integrated development environment ADE), but are not part of the tormal Delphi Pascal language, Nonetheless. the language sncludes several features that exist solely to support Delphi's IDE and form descriptions. Read about these features sn depth in Chapter 3, Runtime Type Information. ‘which maintains compatibility with the fist version of Delph, Ver. sons 2 and later produce only 32-bit programs, so Delphi's linker convers the df resource to a 32-bit resewece automatically Th binary .dfm files are usually compatible with all versions of Delphi Delphi 5 also suppunes extual .dfn files, Ihese files are plain text and. are not compatible with por versions of Delphi, at least not without conversion back to the binary format. The only way to tell whether a dfn file ie binary of text ia to ope te file and check the contents. An easy way to do this programmatically 1s to test the frst {tee bytes, which are always SFF SOA $00 sn a bunary .djin file, g A binary fm file w actually a 16 bit eo (Windows resuuiee) fe, Table 1-1 beefy describes the fles you are likely to tind in Delphi and what they: are used for. Files marked with “(IDE)" are not part of Delphi Pascal, hur ane used by the IDE, Table 1-1: Delp Files: Extension | Description pg) Proc group TD tet | Compiled package (Opec! hand uf DED ft | Options forthe command line compiler dep | Compiled package efomation, needed lnk with a package der | Component bmap resource (DE) dou | Cale yet code jm | Porn descnption ADE) dof | Project options fle (DED dpe} source te tor bulding a package dpe | Main source file fora program o rary dire | Resource snpt for resourcestring decantions Chapter 1 Delbbs PascalTable 1-1. Delphs Files (continued) Extension sk Desktop layout UDB) ‘pas Unit source code Windows resource (every dpirhas an associated rms file) Separating Interface from Implementation ‘A unit has two pans: interface and implementation. The interface part declares the types, vanables, constants, and routines that are visible to other unite. The imple ‘mentation section provides the guts of the routines declared in the interface section. the implementation section can have additonal declarations that are private 10 the unit's implementation. Thus, units are Delphi's primary means of information hiding, (One unit can tse another unit, that is, import the declarations from that other unit A change to a unit interface requires a recompilation of all unite that woe the changed declaration in the modified unit. Delphi’s compiler manages this automat- scally, o you don’t need to use makeliles to compile Delphi project. ‘You can use a unit in the interface or implementation section, and the choice 1s important when building a project If unit A uses unit B sn its interface section, changes to unit B's interface are propagated as changes to unit A's interface. Delpht must recompile all the unite that use unit A. ‘+ Ifunit A uses unit B in its implementation section, only unit A must be recom- piled to use the new declarations in unit By Units cannot have circular references in thes interface sections. Sometimes, you will run into wo clase declarations that contain mutually dependent declarations. ‘The sumplest solution is to use a single unit, but if you have reasons to declare the classes in separate units, you can use an abstract base class in one or both units to climinate the circular dependency (See Chapter 2 for more information.) Inittalizing and Finalizing Every unit can have an sniualzation and a finalization section. Code an every initialization section runs before the program or library's main begin-end block. Code in the finalization section runs after the program terminates or when the brary is unluaded. Delphi runs the inialization sections using « deptifist traversal of the unit dependency tree, In other words, before a units snitiaization ‘code runs, Delpht runs the initialization section of every unit it uses, A unit 1s initialized only once, Example 1-1 demonstrates how Delphi initializes and final- Example 1-1. Showing the Order of Unis Initialtzation program Bamplel_t; ‘ses unitay (Steptype Console) mis 3Example 1-1. Showing the Order of Unit intalization (continued) agin Weltetas("Reawpie LoL main program) end. interface inplenantation inieializatioas Weiteln ‘unica initialization’); tanalization Weitetan(unita finalization’): en. unit units; sntertave inplesentaticn anitialization Weitain("mniep initializati finalization lwrfretn( ‘inst finalisation’) ena. When you compile and run Example 1-1, be sure to nin it from a command [promps, not the IDE, of else the console will appear and disappear before you can see the output. which is shown ax Fxampte 1-2 Example 1 2- The Output from Running Example 1-1 We \nsshet Sema units initialisation sunita iniesalization Banple 1-1 main progran units finalization The System and Systnit Units ‘The System und Sysmnit units are automatically included in every unit, o all of the declarations in these units are effectively part of the Delphi Paseal language, and the compiler has special knowiedge about many of the functions and proce. dures in the Syotem and Oystnit units Chapter 5, Language Reference, 1s a complete reference to the system routines and declarations meant for your use Programs ‘A Delphi progiau looks sunllar to a traditional Pascal program, stating with the rogram keyword and using a beginend block for the main program Delphi programs are usually short, though, because the real work takes place in one or ‘more separate unite, In a GUL application, for example, die una program usually 7 Chapter 1~ Delphi Pascalcalls an initialization procedure, ereates one or more forms (windows), and calls a procedure for the Windows event loop. or compatibility with standard Fascal, Delphi allows a parameter list after the program name, but—like most modern Pascal compilers—it notes the identifiers listed there, In a GUT application, you cannot use the standard Pascal /O procedures because there ie no input device to read from and no output device to write to. Instead, ‘you can compile a console application, which can read and wete using standard Pascal VO routines. (See Chapter 8, Compiler Directives, to leam about the ‘Shox/Type directive, which tells Delph to build a console or a GUI application.) |A program's uses declaration lists the units that make up the program. Each unit rname can be followed by an in directive that specifies a filename. The IDE and ‘compiler use the filename to locate the units that malee up the project. Unit ‘without an in directive are usually library units, and are not part of the projects source code. If 2 unit has an associated form, the IDE also stores the form name in ‘3 comment, Example 1-3 shows a typical program source fle Example 1-5: Typical Program Pile progean Typical) Fors, Main in ‘Vain.pas' ainForm), Movestusé in ‘MoreStuff.oae' (Forn2}. els in “Ueits.pas (gr +885) begin ‘Aophication Initialize; ‘oplication,CreateForm(MainForm, Mainform) ‘pplication. CreateForm(1Form2, Forn2); deplicaticn. amy end. The Forms unit part of the standard Delphi library, so it does not have an in. directive and source file, The other units have source filenames, so Delphis IDE manages thoce files ao part of the project. To learn about the $R compiler direc- tive, see Chapter 8, The Application object 1s part of Delphi's visual component library and is not covered in this book. Consult Delph’s online help tor informa: tion about the Application object and the rest of the VCI Librartes ‘A Delphi library compiles to a standard Windows DLL. A library source file looks the same ae a program source file, except that it uses the Libvary keyword instead of progran A Lbrary yprcally has an exports declaration, which lists the roulines that the DLL exports. Ihe exports declaration 1s optional, and if you intend to use @ unit in a library. is usually best to put the exports declaration in Libraries 3the unit, close to the subroutine you are exporting. If you don't use the unit in a Iibrary, the exports declaration has no impact. ‘The min body of the brary—its begin-end block—executes each time the library is loaded into an application. Thus, you don't need to write a DLL proce dure to handle the DLL_PROCESS_ATTACH event, For process detach and thread ‘events, though, you must write hauler. Assign the handler to the DLIProe var- able. Delphi takes care of registering the procedure with Windows, and Windews calls the procedure when a process detaches or when a thread attaches or detaches. Feample 1-4 shows a simple DLL procedure. Esample If DIL Auach and Derach viewer we none rocedure Log const Mog: string); begin MessageBox(0, Phar (tog), ‘Attacher', tb toontnformation + Hb.OK); euvedure actachuetacnroc|Reagon: Integer) ; begin ase Reason of DiL_Process Detach: Log(‘nararh Procees!) DiLtread Attach: tog(‘Attach Thread’); Di_stread Detach: tog( ‘Detach Tawa") else og (nim resent"); ena; begin 11 This code runs each tine the DU, ie Loaded into a new process. Lagl'Retach Proceea') DiiPrec += GhteachDetachProc: Using Dynamic Memory ‘When using a DLL, you must be careful about dynamic memory. Any memory allocated by a DLL fs freed when the DLL 1s unloaded. Your application might fetain pointers to that memory, though, which can cause acess violations of ‘worse problems if you aren't careful. The simplest solution is to use the ShareMen unit as the fst unit in your application and it every Mbrary the application loads, ‘The ShareMe unit redirects all memory requests to a single DL (BorlndM Mtl, ‘which is loaded as long as the application is running, You can load and unload DLLs without worrying ahout dangling pointers Sharing Objects ‘Sharettem solves one kind of memory problem, but not another: class identity If lass A is used in the application and in a DIL, Delphi cannot tell that both © Chapter 1 Delph Pascalsmodles nse the same class. Although hath modiles use the same class name, this doesn't mean the classes are identical, Delphi takes the safest course and assumes the classes are different, f you know better, you have no easy way 10 form Delph Sometimes, having separate class sdentites does not cause any problems, but if ‘your program ines to use an object reference across a DLL boundary, the is and fas operators will not work the way you expect them to, Recause the DLL thinks class A is different from the application's class A, the is operator always returns alse. ‘One way wo crcurvert das problemas uw pass obyecisweruss DLL boundaries, IF you have a graphic object, for example, don't pass a TBitmap object, but pass a ‘Windows handle (XBTTMRP) instead. Another solution 1s to use packages. Delphi 3c entities in packages to avoid thie problem. automatically manages the c Setting the Image Base When you create a library, be sure to set the Image Base option, Windows must load every module (DLL and application) at a unique image base address. Delphi's default is $00400000, but Windows uses that address for the application, so it ‘cannot load a DUL at the same address, When Windows must move @ DLL. to a different address. you mcur a performance penalty. because Windows must rewrite a relocation table to reflect the new addresses. You cannot guarantee that every DLL will Lave « uunque addiess because you Cannot cool the audesses Uther DLL authors use, but you can do better than the default. You should at least make sure your DLLs use a different umage base than any of the standard Delph pack- ages and Windows DLLs. Use Windows Quick View to check a fle’ image base, Packages Delphi can link a unit statically with a program or library, of it can link units dynamically To link dynamucally to one of more units, You must put those units sn a package, which is a special kind of DLL. When you write a program or library, you don't need to worry about how the units will be linked. IF you decide to use & package, the unit in the package are not linked into your .exe or ll, but snstead, Delphi compiles a reference to the package’s DLL (which has the extension bp! for Borland Package Library) Packages wvold dhe problems of DLLs, namely, mimagmy memory and class alent: ties. Delplu keeps track ofthe classes defined in each unit and makes sure that the application and all associated packages use the same class identity for the same clace, 20 the 49 and aa operators work correctly Design-Time Versus Runtime Delphi's IDE uses packages to load components, custom forms, and other design- time units, cuch as propery editors, When you write components, keep thet designstime code in a design-ime package, and put the actual component class ia 4 runtime package. Applications that use your component can link statically with the component’s dew file or link dynamically with the runtime package that Packages 7Contains your component. By keeping the design-time envle in a separate package, you avoxd linking any extraneous code sto an application, Note that the designstime package requires the muntime package because you ‘cannot link one unit sto multiple packages. Think of an application ut library a5 4 collection of units, You cannot include a unit more than once ina single rogram—at doesnt matter whether the units ae linked statically or dynamically ‘Thus, if an application uses two packages, the same unit cannot be contained in both packages. That would be the equivalent of linking the unit rwice, Building a Package To build a package, you need to create 2 dl file, or package source file, The
// mide TACSOUNC. AMA end; Tsavingexccount = clase(TAccount) public 1/ Can call TSavingsAccount.Audlt and Taccount AUG procedure Audit kind: Tandireind); ewerload, end Checking: Theckingkecount; savings: Teavingsscccunt; begin ‘Checking 1= Theckingtocount Creat Savings := TSavingsdcccunt Crear Checking. adit; 11 Bere because Thecount Audit is hidden ‘Savings Pasty 10 Okay because Auli iv Overloaded Savings Audit (autiagty); 7 Okay Secking.auaic auineernan); // okay Constructors [Every class has one or more constructors, possibly inherited from a base class. By ‘convention, consiructors are usually named Create, although you can use any ‘name you like, Some constrictor names start with Create, but convey additianal information, such a CreateFromPile or CreatePronStrean Usually, though, the simple name Create is sufficient, and you cat use mietiod overloading 10 define multiple constructors with the same name. Another reason to overload the name Create is for compatibility with Cr+ Builder. C++ does not permit different Consinictor names, you must use overloading to define multiple constructors. 4 Chapter 2— Toe Delphi Object ModelCalling a constructor A constructor 36 2 hybndl of object and class methods. You can call using an object reference or a class reference. Delphi passes an additional, hidden param- eter w indicate how it was called, If you call a constructor using a class reference, Delphr calls the class's NewInstance method to allocate a new instance of the class. After calling NewEnstance, the constructor continues and initializes the fobject. The constructor automatically sets up a try-except block, and if any exception occurs inthe constructor, Delphr calls the destructor, ‘When you call a constructor with an object reference, Delph does not set up the exy-except block and does not call NewInstance. Instead, st calls the constructor the same way it calls any ordinary method. This lets you call an inherited ‘constructor without unnecessary overhead. with an object reference, rather than calling t with a clase reference ‘A common error sto try £0 create an object by calling a constructor and assigning it to the object variable. begin . eceunt Create; 1 wecoos Account = TSavingsAccount Create; // right ‘One of Delphi's features is that you have total control over when, how, and ‘whether to call the inhesited constuccut. This les you waite some powerful and interesting classes, but also introduces aa area where it 1s easy to make mistakes. Delph always constructs the derived class first, and only if the derived class calls the inherited constructor does Delphi construct the base class. C++ constructs classes in the opposite direction, stating from the ancestow class ancl coasteting, the denwved class last. Thus, if class C inherits from B, which inherits from A, Delphi consiructs © firs, then B, and A last. Crt consttuets A first, then B, and finally C Virtual methods and constructors Another significant difference between CH¥ and Delphi is that in C+, a constructor always runs with the virtual method table of the class being constructed, but in Delphi, the virtual methods are those of the derived class, even when the base class is heing constructed. As a result, you must be careful when ‘writing any virtual method that might be called from a constructor. Unless you are careful, the object might not be fully constructed when the method is called. To avoid any problems, you should override the AfterConstruction method and ‘use tat for any code that needs to wait until the object is fully constructed. If you override AftexConstruction, be sure t call the inherited meta, wu. ‘One conetructor can call another conetructor. Delphi can tell the call ¢ from on. object reference (namely, Sef), soit calls the constructor as an ordinary method. Glasses and Objects 4‘The most common reason to call another constmictor is to put all the initialization ‘code ina single constructor. Example 2-7 shows some different ways to define and call constructors ‘Example 2-7- Declaring and Calling Constructors ‘Teustoner = class... end ‘Taccount = class private ‘Balance: currency; ‘tamper: cardinals fOustonar: TOustoner; public constructor Create Customer: TOustonet]; virtual; destructor Destroy; override; ena; ‘TavingsAccount = clase tRacount) €InterestRate: Integer; // Scaled by 1000 patie constructor Craate|Custoner: TCustemer) ; override; overload: constructor Create(Custaner: Toustoner; ‘interestRate: Tteyer) ‘overload: 11 ote that TSavingstecount does not need a destructor. Te simply end) Accountitber: Cardinal L ‘constrictor TAccount Create(Custoner: TOustoner) featm “inherited create; 11 Call Tobjece.ceeate, Bhebe: := Aowwntmmber; —// Assign a Unigie accoMnE riber. ne (Accountitmber) ; roustoner = Customer 1) Wotity custerer of new account. Ccustoner-Attachtooount (Self): end destructor Thocount Destroy; begin (1 TE the constructor fails before setting fOustener, the field 17 Will be nil, Release the accomt only 1f Customer {8 not nil, Af Custener © nil then ‘Customer Releasetocount (Self); 11 eat Tehject. Destroy, inherited Destroy const DefaultinterestRate = 5000; // St. scaled ty 10n0 ‘D Chapier 2 The Delphi Object ModelExample 2-7: Declaring and Calling Constructors (continued) constructor TSavingstccout.Create(Custener: Teustower) beain 7) Call a sibling constructor. Create(Custoner, DefaultinterestRate); end: constnuctor TeavingeNovount (Customer! TOuctonary Intarcothatortntogee) begin inherited Create(custener) FintereatRate := Interesttates ea Destructors Destructor, lke Consuuciurs, Gahe att estes hidden parameter, The Ort call wo a destructor passes True for the extra parameter. This tells Delphi to call FreeInstance (o free the object. I the destructor calls an inherited destructor, Delphi passes False as the hidden parameter to prevent the inherited dectructor from trying to free the same object. declare additional destructoxs, but you should’ take advantage of that feature. Declaring multiple destructors 4s confusing and serves ‘no useful purpose, g A class usually has one destructor, called Destroy Delphi lets you Betore Delphi stants the body of the destructor, it calls the virtual method, BoforeDestruction. You cin overide Reforebeatruction to assert program state or take care of other business that must take place before any destructor stay, This leo you write a class safely without worrying abou how oF whether any denved classes will call the base class destructor, destructor, but You must not redeclare the Free method. When iree ing an object. you should call the Free method and not the destruc tor. The distinction is important, because Pree checks whether the cubject reference iy nil and calls Destroy only for non-nd2 refer- ‘ences. In extraordinary circumstances, a class can redefine the Pree method (such as TInterface in the seldom-used VirtIntf unid, ‘which malee it that much more important to call Free, not Deatoy. & ‘When writing a class, you might need to override the Destroy Ifa constrictor of Afterconatniction method mises an exception, Delphi ate ‘matically calls the object's destructor. When you write a destructor, you must remember that the object being destroyed might not have been ‘completely constructed. Delphi ensures that all fields start out at zero, but if the exception Glasses and Objects HB‘occurs in the middle of your constructor, some fields might be initialized and some might still be zero, Ifthe destructor just frees objects and pointers, you don't need to worry, hecanse the Pree method and ExeaMem procedure both check for ‘nil pointers. Ifthe destructor calls other methods, though, always check first for a ‘add pouster, Object Life Cycle For most objets, you call a constructor to create the object, use the object, and then call Free W fice the olyeu. Delph handles all te other detals Tor you Sometimes, though, you need to know a litle more about the inner mechanisms of Delphi's object model. Example 28 shows the methods that Delph calls or sionulates when it creates and frees en object. Example 2-5: The Life Cyele of an Object ope ‘TSomething = class rocedire DeSanething; end; Refs rermathing: begin ef. TSaethiun.Craatey Ref. Dosoneting? Ret Free; end; 11 he hidéon code in the constructor locke comcthing 2ike this: function TSenething.Create(ToClassRef: Boolean): “Sanething; begin TE TeClasate€ then uy 1/ Bocate the new abject. Self := TSonething.tewinstance; 1/ Mestostance initializes the object in the came way that U7 InitInstance does. Tf you uverside Mewlastance, oth, U1 az do not cal the inherited Newinstance, you mt call 17 Initinstance, The call is shom below, 20 you know wt 1/ happens, bot renenber that ordinarily Delehi does not 11 actually call Tnitinstance. ntetnarancn (S16); 11 00 the eal work of the wuustewctor, Lat wlthoue all che V/ class reference overhead. Delphi does not really call the 17 constructor recursively. SelE.Create (Falco); Self Retertonaemict ion: except 11 16 any exception scours, Delph culuiaticaliy cats che 1/ object's destructor. F_ Chapier 2 The Delph Ohyect ModelFxample 2-8: The life Cycle of an Object cominued) self. Desteoy; «a Self.Cronte Pale) ; ena: // Tho biden code in the deetructor locks something 1ike this: ‘procedure TSonething.Destroy Deallocate: Boolean) tain EE Deallocate then 17 Delphi dosen't really esl) the destructor recursively, but 1/ this is whore the destrictor's real work takes place Self. Destroy False); 4 Deallocate then begin 71 Delph doesn’t really call Cleampinstance, Instasd, the 71 Breetnstance method dees the cleansp. Tf you override /| Weeetnstance and do not call the inherited Freelnstance, 1/ you most call Cleampinstance to clean up strings, 11 Ayramia arraye, ard Varant-type fel Self. Cleanpinstance; (Cali Prestnstance bo fee the Uujavt's wauey. Self Freetnstance Access Levels Like C4 and Java, Delph as difcrcat access levels that determine which vbjeus can access the fields, methods, and properties of another object, The access levels ae as follows: provate Declarations that are declared prwvate can be accessed only by the class's own ‘methods or by any method, procedure, or function defined sn the same units implementation section. Delphi dues ut have Cr+-siye fiend declarations of Java-style package level access. The equivalent in Delphi 1s to declare package or friend classes in the same unit, which gwes them access to the pprvate and protected parts of every clase defined in the came unit. protected A protected declaration can be accessed from any method of the class or its descendants. The descendent classes cant resile mi dilferet uns. public Public methods have unrestncted access. Any method, function, oF procedure ‘can access a public declaration, Unless you use the M+ compiler directive Gee Chapter 8, Compiler Directives for details), the default access level public Classes and Ohjoote 75published Published declarations are similar to public declarations, except that Delphi ‘sores runtime type information for published declarations. Some declarations cannot be published: see Chapter 3 for details. Ifa class or a hase class uses the $0 directive, the default access level is published. Delphi's IDE declares fields and methods in the intial unnamed sex tion of a form declaration, Because Porm inherits from ‘Tersistent, which uses the $M+ directive, the initial section is Published. In other Words, the LUE declares its tields and methods as published. When Delphi loads a form description (dfn file, it relies ‘on the published information to build the form object. The IDE relies fon the initial, unnamed section of the foun cass. I you modify that section, you run the nsk of disabling the IDE's form editor. automated ‘Automated declutatious ure sunalar w public declarations, except that Delphi Stores adaltional runtime type information to support OLE automation servers. ‘Automated declarations are obsolete; you should use Delphi's type library ‘editor instead, but for now, they remain a part of the language for backwaid compatibility A future release of Delphi might eliminate them entirely. (Chapter 5 describes automated declarations in more depth, ‘A derived class can increase the access level of a propery by redectaring the prop- ety under the new access level (e.g. change protected to public). You cannne decrease a property's access level, and you cannot change the visibility of afield for method. You can override a viral method and declare he uvenudden method a the same or higher access level, but you cannot decrease the access level, Properties ‘A propery looks like a field but can act like a method. Properties take the place uf accessor and mutator methods (sometimes called getters and setters), but have ‘much more flexibility and power. Properties are vita to Delphi's IDE, and you can also use properties in many other sinations A property has a reader and writer to get and set the property’ value. The rearer can be the name of a field, a selector for an aggregate field, or a method that ‘etums the property value. The writer can be a fick! naue, a selewior for an aggre- gate field, or a method that sets the property value, You can omit the writer to ‘make a read-only property You can also omit the reader to create a wrte-only Dpropenty, hut the nses for such a beast are limited. Omitting both the reader and the writer is pointless, so Delphi does not let you do so, ‘Most readers and writers are field names or method names, but you can also refer to part of an aggregate fill Geuurd or array). If a reader or writer refers to an. array element, the array index must be 4 constant, and the field's type cannot be a dynamic array Records and arrays can be nested, and you can even use variant G6 Chapter 7~ The Delphi Object ModalHiding a Constructor Sometimes, a class is not for public use, but is a helper class whose use 1s entirely subservient to another class. In that case, you probably want to make the constructors for the helper class pavate or protected, but ths is tricky TObject declares a public constructor: Create. Even though the helper class's constructors are private or protected, you can call the public (Create constructor inherited from TObject. Although you cannot change the access level of the inherited Create constructor, you can hide it with another public constructor. Because the | denved constructor should not be called, it can raise an exception. For example: bine ‘wrivateielper = class 11 Teublic 1s the only class allowed to 11 call the real constroctor: } constructor Create(Oxner TPublie); | ‘vecload public 1/ Bide Thject.Create, in ease someone 1/ Terivateielper instance. reintroduce; overload, end; ‘Teublic = clas | palic Gestiuctor Destroy; cna; constructor "Privateelper Crea begin aise Bxcepticn. Create Programing error’) constructor TPublic.creste; becin 1/ This Se the only place where 11 Trivatellelper is created, {lelper := TerivateHelper.Create(Self) ; Glasses and Objects 47records. Example 29 shows an extended rectangle type, similar to the Windows ‘TRect type, but because its a clas, it has properties and methods. Example 2-9: Properties Readers and Writers ‘ects = class IPersistent) Re TRect; function vecweiont: integer; function Getiidth: Integer; Procedure SetHeight const Value: Integer); Drocedure Setitideh (const. Valves Toragsr): public ‘constructor Cresto(conat Ri; ect), overtoats constructor Create(Left, Top, Right, Botan: Integer); overload constructor create(censt Topiett, BottonRight: Tpoint]; overload; procedure Assign(Scurce: TPersiatent); overrige; procedure Inflate(X, ¥: Integer) Drocodura Ineoroect (const Ry ects function tstipty: Boolean; funccion isuqual (const R: TRectR) Boolean, procedure Offset (x, ¥i Integer); Procedure Union(const R: TRECtE) + Property Topleft: TPoint read R.topLett write R.tepLeft; Property Bottonfight: Teint read R.DuttiaRiyhl, write R-BOCtemKghc: property Rect: TRect read R write Ry [property eight: integer read Getieight write Setieight; roperty Width: Integer read Getiideh weite Setiicth; published Droperty Loft: Incager vend R.taft write R.taft defauite 0p property Right: Integer read R.Right write R.Right default 0; [reperty Tops Intoger vend Mofop waite Ritoy default 0; [property Botton: Integer read R.Bottoa write R.Bottom detault 0; Array properties Properties come in scalar and array flavors. An array property cannot be Published, but they have many oiler wes. The array index can be any type, and you can have multidimensional arrays, too. For array-type properties. you must Use read and write methods—you cannot map an aray-type propery directly to an aeray-type field ‘You can designate one array property 2s the default property. You can refer to the default property by using an object reference and an array subscript without mentioning dhe property name, as shown in Example 2-10. Example 2-10- Using a Default Array Property te ‘TBample = clase ‘GB Chapter 2— The Delphi Object ModelExample 2-10- Using a Default Array Property (continued) beoperty Teeus(1: Integer] mnceger resa vetiten write Setitem; Droperty Chars[C: Char): Coar read Gotchar write SetChsr; defal®; end ample: Temple, cr chars desl Brample := Tample.create; Y= Brample.ttors(d}; // must vention property nane explicitly t= Bamplel'#°1; 1) aeeay property is default © i= Bemple.chars["K']; // Same a8 previous line Indexed properties You can map many properties to a single read or waite method by specifying an dex umber tor each property. The index value 1s passed to the read and write methods to differentiate one property from another. ‘You can even mix array indices and an index specifier. The reader and writer ‘methods take the array indices as the first arguments, followed by the index copecifier. Default values A property can also have stored and default directives. This information has no semantic meaning to the Delphi Paseal language, but Delphi's IDE uses this infor ‘mation when storing form descriptions. The value for the stored directive is a Boolean constant, a field of Boolean type, of a method that takes no arguments and returns a Boolean result. The value for the default directive is a constant value of the same type as the property. Only enumerated, integer, and set-type properties can have a default value. The stored and default dircttives lave meaning only for published properties To distinguish a default array from 2 default value, the default array directive ‘comes after the semicolon that ends the property declaration. The default value directive appears as part of the property declaration. See the default directive ip Chapter 5 for details. Using properties A common approach to writing Delphi classes 1s to make all fields private, and declare public properties to access the fields. Delphi imposes no performance penalty for propertios that access fields direcly. By using properties you get the added benefit of being able to change the implementation at a future date, say t0 ‘add validation when a field's value changes. You can also use propenies 10 enforce restricted access, sich ag sising a readonly property to access 4 field whose value should not be changed, Example 2-11 shows some of the different ‘ways to dectare and use properties ‘Classes and Objects 49‘Example 2-11. Declaring and Using Properties pe ane: string; TextiNmber: string(9]; ena: ‘Tecomt = class foustener: Tousteners halance: currency: Suwnber: Cardinal, ‘procedure SetBalance(Newalance: Currency) vublished ‘property Balance: Currency read flalance write SetBalance; property Manber. Cardinal Feod Ohaver; /7 Cal caange account # property Custilane: string read {Custoner. Rane TSavingsAcceunt = clase(TRocaunt) private ‘EInterestRate: Totegers published property Intereathate, Integer Koad Cuvcresthate write flnteresthate default Detaultinterestiate; TLinkedtecout = clase(TObject) Accounts: array[0..1) of there: Function Getkcooint (Index: Integer); TAcoout; public 11 Two ways for properties to access an arzay: using an index 11 of reterring to an array elenent. reparty checking: TAcount index 0 read GetAccotnt Property Savings: TRocount read flccount(2}; ea ‘TocountList = clase ‘fist: Mist: function GetAccoune index: Integer}: TAecount; [Procedure SetAccount (Index: Integer Account: TMocount) function Getcont: Integer; protected property List public property Comt: Integer read GetCount Droperty Acoounts|undex: integer]: TAccount read GetRecount write SetAccount; default; ‘List read fhist; ond; procedure TAccount.SetBalance (NewBalance: Currency! Begin {LE MewBalance < 0 then raise Riveraramncepeion,veates ‘palence := Nevialance; sapter 2~ The Dolpa Objeci Model‘Example 2-11, Declaring and Using Properties (continued) ena) function TLinkéAccount.GetAocount Index: Inteser); Thocount: begin: ena; Arcomte( see) ‘fnetion Taccountbist atcount: Integer; begin Result. := List.Count end function TecountList.Getaccount Index: Integer): Thacount; begin Result := List Index) ‘rocedute TAccountList.SetAccount (Index: Integer Account: TAccount) begin fist [Index] := Account Glasstype properties Properties of class type need a litle extra attention. The best way to work with classtype properties is to make sure the owner abject manages the property object. In other words, don't save a reference to other objects, but keep a private copy of the property object. Use a write method fo store an abject By copying i. Delphi's IDE requires this behavior of published properties, and it makes sense for ‘unpublished properties, too. ‘The only exception to the rule for classtype properties is when a property stores a reference to a component on a form In that e252, the property must store an object reference and not a copy of the component elphi'e INF stores camponent references in 2 .dfn file by storing only the component name. When the .dfm is loaded, Delph looks Lup the component name fo restore the object relerence. If You must store an entire component within another component, yous must cel. cegate all properties ofthe inner component. Make sure the property's class inherits from TPereistent and that the class over- rides the Assign method. Implement your property’ write method to call Assign. (tersistent—in the Classes unit—is not required, but its the easiest way to ‘copy an object. Otherwise, you need to duplicate the Assign method in what. ever class you use.) The read method can provide diet access tothe field If the property object has an OnChange event, you might need to set that so your object Glasses and Objects 314s notified of any changes. Example 2-12 shows a typical pater for using a class type property The example defines a graphical control that repeatedly displays 4 bitmap throughout its extent, ling the bitmap as necessay The BiLuay prupenty sores a TBitnap object. ‘Example 2-12: Declannng and lang a Classe Property vit the; ncartace vweco yaUtile, Classes, Controls, Oxaphics, vine 7) tile a bitmap ‘Tile = clasa(TGzaphictontzol) ‘iteep: Teitmap: procedure cetDitmap Qiewitmap. ZDitnap) procedure Bitnapchanged|(Sender: TUbject) protected prooadure Faint; override; public constrictor Creste(Ouner: Trmpenent): evarriAe Gestructor Destroy; override, ubliohea property Align; Droperty sitnap: Tustmap resa taitnap write SetAtmap; property OnClick; ‘Property OncbiClick; 1 Many other properties are useful. tot wera emitted te ane spare, 11 Soe Neontrol for a full List. smptenencacion (mue) 1/ Create the bitmap when creating the control ‘construoter Mile.Croate(Owmers Tsepenent) begin Iohericea: Bitmap := Teitnap. Create ‘Bitmap crchange i= Bitmapchanged; ea; 1) Pree the bitmap when dcotzoying the control. Sestructor Mile. Destroy; egin Freche (£510) inherited end: 1/ nan the hemp changeo, redraw the conteel 52 Chapter 2 The Delpbi Object Model‘Example 2-12: Declaring and Using a Class-type Property (continued) procedure TPile.BitmapChanged( Sender: TObject) Degin Tnvalidate; ea; 1) Paint the control by tiling the bitmap. I€ there 12 no 17 wienep, don't paint anything. procedure Trile.Paint; X, Ys Integer: begin Af (Bitmap.mideh = 0) or (Remap. Height = 0) Phen Y= 0; while ¥ < clientheigne 30 begin Xi 0; while X < clenentath do begin Camrao. Dea, > Bitmap Inet, Bitmap. Width) 7 Ino(Y, Bitmap.teigh ena, ena 11 Sot a noe biteap by copying the TBitmap cbject. procedure Mile, SetBiteap NewBitmap: TBitmep); Degin ‘Bitmap. Assign (ewBitxap) + a; ea. Interfaces ‘An interface defines a type that comprises abstract vitual methods. Although a lass inherits from a single base class, it can implement any number of interfaces ‘An iateeface is similar to an abstract class (hat i, a class that has nv fields and all, ‘of whose methods are abstrac), but Delphi has extra magic to help you work with interfaces. Delphi's interfaces sometimes look like COM (Component Object Model interfaces, hut you don't need to know COM to use Delphi interfaces, and you can use interfaces for many other purposes. ‘You can declare a new interface by inheriting from an existing interface. An inter- face declaration Coutaing metludl and property declarations, but no elds. Just as all classes inherit from TObject, all interfaces inherit from Unknown The Tonknown interface declares thee methods: _AddRef, Release, and ueryinterface, If you are familiar with COM, you will recognize these methods. The frst two methods manage reference counting for the lifetime of the Tnuerfaces 53‘object that implements the interface. The third method accesses other interfaces an ‘object might implement. ‘When you declare a class that implements one or more interfaces, you must provide an implementation of all the methods declared in all the interfaces. The ‘lass can implement an interface’s methods, or it can delegate the implementation to a property, whoce value i an interface. The simplest way tw implement the ~AddRef, Release, and Queryinterface methods is to inherit them from ‘Tinterfacedobject or one of its derived classes, but you are free to inherit from any other class if you wish to refine the methods yoursal ‘A cass implements each of an interface's methods by declaring a method with the same name, arguments, and calling convention. Delphi automatically matches the class's methods with the interface’s methous. If you wnt to use « different method ame, you can redirect an interface method to a method with a different name. ‘The redirected method must have the same arguments and calling convention as. the interface method. Thi feature ic ecpecally important when @ class imple ‘ments multiple interfaces with identical method names. See the class keyword in {Chapter 5 for more information about redirecting methods A class cant delegate the mmplementation of an interfice 10 a property that uses the implements directive. The property's value must be the interface that the class \ants to amplement. When the object cast to that interface type, Delph: automat- ically fetches the property’s valuc and returns that interface, See dhe Lxylemenits directive in Chapter 5 for details. For each non-delegated snterface, the compiler creates a hidden field to store pointer (0 the interfice's VM. the interface field or tields follow immediately after the object's hidden VMT field. Tut as an object reference ss really a pointer to the: cbject’s hidden VMT field, an interface reference is a pointer to the interface's hidden VMT ficld. Delphi automatically snitalizes dhe laden felds when the ‘object 1s constructed. See Chapter 3 to learn how the compiler uses RTTI to keep. track of the VMT and the hidden field. Reference counting ‘The compiler generates calls to _AdARef and _Release to manage the lifetime of interfaced objects. To use Delphi's automatic relerence counting, declare a vari- able with an interface type. When you assign an interface reference to an mterface vanable, Delphi automatically calls _AddRe#. When the variable goes out of scope, Delphi automatically calls Relea. ‘The behavior of _AAARof and Release is entirely up to you. If you mile from ‘inter faceddbject, these methods implement reference counting, The _AddRef ‘method increments the reference count, and _Release decrements it, When the reference count goes to 7er0, Release frees the object. If you inherit from a different class, you can define these methods to do anything you want. You sliould implemen queryinterface correcily, though, because Delphi relies on it {0 implement the as operator.ypecasting Delphi calls Quexyinterface as part ofits umplementation of the a operator for interfaces, You can use the as operator to cast an anterface to any other interface type. Delphi calls Queryinterface to obtain the sew huterface reference, If Queryinterface retums an error, the as operator raises a runtime error. (The ‘SysUtils unit maps the runtime error to an EInt £CastBrrox exception.) ‘You can implement Queryinterface any way you want, but you probably want to use the same approach taken by TInterfacadbjact. Fxample 2-13 shows a class that implements QueryInterface normally, but uses stubs for _AddRef and Release. Late ut this secon, you'll see how useful this class can be Example 2-13: Interface Base Class Without Reference Counting function mbRefCout.queryInverface const IID:TGI2D; out Obi): Hesult begin Af Getintertace(TID. Obs) then Result oles Result :+ Windows. Nointerface; function awokes oune. telesst begin Repult cea: integers Interfaces and object-oriented programming ‘The most important use of interfaces 1s to separate type inheritance from class ‘mheritance. Class mheriance is an effective tool for code reuse A derived class casily inherits the fields, methods, and properties of a base class, and thereby avoids rcimplementing common meilwals, In a strongly typed language, such as Delphn, the compifer treats @ class as a type, and therefore class inheritance ‘becomes synonymous with type inheritance. In the best of all possible worlds, thonigh, types and classes are entirely separate. Textbooks on objectonented programming ofien desde an inheritance relation. ship as an “isa” relationship, for example, a TSavingsAccount “is” TAccount. Tnierfaces 33You can see the same idea in Delphi's is operator, where you test whether an Account vanable is TSavingsAccount. ‘Uutside of textbook examples, though, simple 1s relationships break down. A square is a rectangle, but that doesn't mean you want 10 derive TSquaze from ‘Rectangle. A rectangle 1s a polygon, but you probably don’t want to denve ‘TRectanyle fiom TRolygon. Class inheritance forces a derived class to store all the fields that are declared an the base class, but in this case, the dened class doesn't need that information. A ‘Square object can get away with storing a single length for all of ite cides. A Tectangle object, however, unust siore {WO lengths. A TPolygon obyect needs to store many sides and vertices. ‘The solution 1s to separate the type inheritance (a square 1s a rectangle 1s a polygon) from class nhentance (class C anhents the fields and methods of class B, Which inherits the fields and methods of class A). Use interfaces for type inherit lance, so you can leave class inheritance to do what it does best inheriting fields and methods, In other words, ISquare inherity from Rectangle, which wihevils fuss Polygon. The interfaces follow the “isa” relationship. Entirely separate from the Interfaces, the class TSquare implements TSquare, TRectangle, and TPolygon. ‘Rectangle implements IRectangla and TPalygon. inital 1. Delphi follows this convention for all interfaces. Note that it ‘The convention in COM programming 1s to name anterfaces with an |s a useful convention, but not a language requirement. (On the implementation side, you can declare additonal classes to implement code ‘euse. For example, Teaseshape implements the common methods and flds for all shapes. TRuctangle mers from iBaseshape and implements the methods in 8 way that make sense for rectangles. "Polygon also mherits from TBaseShape and implements the methods in a way that make sense for other kinds of polygons A drawing program can vse the shapes by manipulating TPetygon interfaces, Example 2-14 shows simplified classes and interfaces for this scheme. Notice how ach interface has a GUID (Globally Unique Identitier) in its declaration. The GUID is necessary for using Queryinterface. If you need the GIT af an inter. face (in an explicit call to Queryinterface, for example), you can use the interface name. Delphi automatically conven ut haterfuce ame 10 fs GUID. ‘example 2-14: Separating Type and Class Hierarchies ‘shape = interface 1 (Sor6De51-P4ES-1102-s8nc-o0104BcRCH4D) *) ‘procedure Dra (Canvas: Tanvaa): function Getroaition: Point; proseaire SetDooktion|Valust ‘Peint)s Droperty Position: TPoint zead GetPosition write setPosition: 56 Chapter 2— The Delphi Object ModelExample 2-14: Separating Type and Class Hierarchies continued) Polygon = interface (1shape) ((S0reD852-Pamp-11n2~88A0-0010¢eCAckAB}') turetion Maertices: Integer function thmcidees Integers function Sidetength Index: Integer) : Integer; function vertex(index: integer): 1HOint; ea: Rectangle = interface(IPelygan) ((S0R6D853-P4RB-1102-8830-001068CRC48R) *) eed Togisce ~ intertaco(tRectangle) ( (SoreD9s4-r4ae-1102-28nc-0010¢Bcace4B)"} ‘unecion sider unteger; end: ‘aseshave = class(MoRefCount. TShape) private ePoeitions Teint, function GetPosition: TPoints public constructor Create; virtual; ‘procedure Draw (Canvas: TCanvas): virtual: abstract: Droperty Fosition: TPoint read fFositicn write SetPesition; swoint) ‘olygon = class(TBaseshape, Polygon) ‘vertices: array of "Point; mblic procedure Draw (Canvas: Tamas): override: function Nawercices: Integer? Emotion tmbidees Integers function SideLength Index: Integer): Integer; fwcclon Vervex(Intex: anceger): 1e04nC? end ‘TRactangle = clase(Taseshape, TFelygen, IRactangle) private ‘Rect TRect; panic procedure Draw (Canvas: TCanvas); override: function tmvertices: anceger; fmction Mansides: Integer; function sidetength(Index: Integer) : Integer; function Vertex(Index: Integer): TRoint: end: ‘Tequare = slase(sBacoshape, TPolygen, TRectangle, Tequare) public ‘Procedure Draw Canvas: Tamas]; override function Side: Integer: interfaces 57Bxample 2-14: Separating Type and Class Hierarchies (continued) function mawvertices: Integer; function Masides: Integer function SideLength(Index: Intever) : Inteoer function Vertex (Index: Integer): TPoint, A deswed clase inherits the interfaces implemented by the ancestuns’ disses. Thus, ‘Rectangle inherits ftom TBaseshape, and THaseShape implements TShape so ‘TRectangle implements IShape. Inheritance of interfaces works a litle differ- cently Interface inheritance is merely a typing convenience, co you don't have 10 retype a lot of method declarations. When a class implements an interface, that does wot autuuatially mean the class implements the ancestor interfaces. A class implements only those interfaces that are listed in its class declaration (andl vn the declaration for ancestor classes). Thus, even though TRectangle inherits from Polygon, the Mectangle class must list TRecuaiisLe und TPOLygon explicit To implement a type hierarchy, you might not want to use reference counting. Instead, you will rely on explicit memory management, the way you do for normal Delphi objects. in this case, i's est to implement the _AddRef and _Release ‘methods as stubs, such as those in the MoRafCoant class in Example 2-13, just be careful not to have any variables that hold stale references. A variable that refers to an object that las been freed can cause problems if you use the vanable. ‘An interface variable that refers to an object that has been freed will certaunly cause problems, because Delph will automatically call ss Release method. In ‘other words, you never want to have vanables that contain invalid pointe, td ‘working with interfaces that do not use reference counting forces you to behave. COM and Corba Delphi mnterfaces are also useful for implementing and using COM and Corba objects. You can define 2 COM server that implements many interfaces, and Delphi automatically manages the COM aggregauon for you. the runtime library contains many classes that make it easier to define COM servers, class factones, and so on. Because these classes are not part of the Delphi Pascal language, they are not covered in thie book. Consult the product documentation learn mvre, Reference Counting ‘The previous section discusses how Delphi uses reference counting to manage the lifeime of interfaces. Stunys aud dyuatmc arrays also use reference counting to ‘manage their lifetimes. The compiler generates appropriate code to keep track of ‘when interface references, stamgs, and dynamic arrays are created and when the variables go out of scope and the objects, strings, and arrays must be desuuyed Usually, the compiler can handle the reference counting automatically, and every: thing works the way the you expect it to, Sometimes, though, you need to give a hint w the compiler. For example, sf you declare a record that contains a refer. ence counted field, and you use GetMem to allocate a new instance of the record, you must call In{tialize, passing the record as an argument. Before calling Froatfem you muct call Finalize. 58 Chapter 2— The Delph Object ModelSometimes, you want to keep reference to 9 string of interface after the variable {goes out of scope, that is, at the end of the block where the variable declared. For example, maybe you want £0 associate an interface with each item in 2 TMListview. You can do this by explicitly managing the reference count. When stonng the interface, be sure to cast it to TUnknown, call AddRef, and cast the Unknown reference to & raw pointer, When extracting the data, type cast the pointer o TUnknown. You can then use the as operator to cast the interface to any desired type, or just let Delphi release the interface. For convenience, declare a ‘couple of subroutines to do the diny work for you, and you can reuse these subroutines any time you need to retain an interface reference. Example 215, shows an example of how you can store an interface reference as the data associ ated with a list view item, Example 2 15: Storing Interfaces in a List View 1/ count 4 incremented and the interface will not be freed function RefTlkinown const Intf: Tnknown): Folnter penn att. _pdaret 11 Tecrement the reference cout. Result := Pointer(Intt); // Save the interface pointer. ea: 11 Release the interface whose valve is Drocedure ReleaseTUnkom(P: Pointer): nels Timon; begin Pointertanté) i= P: 1/ Delph releases the interface when Intf goes cut of scope. stored in the pointer Pr 17 yen the user clicks tne button, ade an interrace to tne Last. procedure TFornl..uttonlClick(Sender: TWbject): begin Feen.caytion := "Stuff; een. vate := Ketauninown(GetIntE as JUneNown) : ena 17 then the List view is destroyed or the List {ten {a destroyed 1) fer any other reason, release the interface, too. procedure MPorad.LiotvicwDeletion|Gender: TObject; Tem: TListrtem ; begin ona 11 then the user selects the List view item, do somthing with the 11 sesociated interface, provedise TPomd.LictVioviGlick(Gsndces Tobject); Rijoronce Crating 50Example 2-15: Storing Interfaces in a List View (combined) = TUnknown(ListView! selected.Oata) az yinterface; Ent Dosonathinglooful; ena You can also store stnngs as data. Instead of using _A@ARef, cast the string to 2 Pointer to store the reference to the string, then force the vanable to forget about the sinng. When the variahle goes aur of scape, Delphi will nat free the string, because the variable has forgotten all about it, After retneving the pointer, assign it tw a suing vatrable that f$ Gist 10 4 pointer. When the subroutine returns, Delphi automatically frees the string’s memory Be sure your program does not retain any pointers to memory that 18 about to be freed. Again, convenience subroutines simplify the tack, Example 2-16 shows one way to stove sigs ‘Example 2-16: Storing Sirings in a Lst View 17 save a sefecewe Co a string and recum a raw pointer U1 to the string. function Refstring const §: string) Pointer; ocal: string: bain Toca t= $3 // Tncrenent the reference cmt. Resull c+ Pointer (tocal); // Save che scring pointer. Pointer (tocal) i= nil; // Prevent decresent ing the ref cout ena) 1/ Release a string that wis referenced with RefSteing, rovedce Releasastring 2, olnter); begin Poamter tocal) 11 Delphi frees the string when Local qoes out of scape. end 1/ Ween the user clicks the button, add an item to the list view 17 apd save ah ellie, Mice Lela, procedure TFornl ButtoniClick (sender: Tbyect); Teens TListTtem; begin Tram = Tatiewt Troms. A84: Tten.Caption := Balti Text; eam Data = RefStalin (BUL2. Text); ea: // Release the string when the List view item is desteoved 11 for aay ren800, Drocedtire Tena! [4crWeviteletinn(Sendar: object) Team TLictTtan) + 60 Chapter 2 The Delph: Obyect ModelExample 2-16: Storing Stings in a List View (continued) begin Releasestring(Tten.Datal; end: 1) Retxiorg the string wen the user elects the Hist view Sten procedure Trorml ,LetVieviClick(Sender: Tbject) ser: string: begin Sf ListView Selected © nil then begin Ber «~ steing(Listvieut colacted tata); Stonttessage (St) Messages ‘Yow should be familiar with Windows messages: user interactions and other events generate messages, which Windows sends 10 an application. An application processes messages one at a time to respond to the user and other events. Each Jnd of message has a unique number and rwo integer parameters. Sometimes 2 parameter is actualy a pointer to a string or structure that contains more complex. Information. Messages form the heart of Windows evenclnven architecure, and Delpht has a unique way of supporting Windows messages. In Delphi, every object—not only window controls—can respond (0 messages. A ‘message has an unteger identifier and can contain any amount of additional infor- ‘mation. In the VCL, the Application object receives Windows messages and ‘maps them to equwalent Delphi messages. In other words, Windows messages are 8 special case of more general Delp messages. ‘A Delphi message Is 4 record where the fist avo bytes contain an integer mesage ‘identifier, and the remainder of the record is programmer-defined. Delphi's message dispatcher never refers 10 any part of the message record past the micssage aumber, 30 you are free to store any amount or kind of information in a message record. By convention, the VCL always uses Windows-siyle message records (Message), but if you find other uses for Delphi messages, you don't need to feel sa ennstrained To send a message to an object, fill in the message identifier and the rest of the message record and call the objects Dispatch method, Delphi looks up the imessage number an the object's message table. The message table contains pointers (0 all the message handlers that the class defines. If the class does not define a message handler for the message number, Delphi searches the parent clases message table. The search continues until Delphi finds a message handler or it reaches the TObject class. If the class and its ancestor lasses do not define a message handler for the message number, Delphi calls the objects DefaultHandler method, Window controls in the VCL override Default Handler (0 pass the message co the window procedure, other classes usually “Messages 61ignore unknown messages. You can overtide Defaultiandler to do anything you want, perhaps raise an exception, Use the message directive to declare a message handler for any message. See Chapter 5 for details about the message directive Message handlers use the same message table and dispatcher as dynanuc methods Each method that you declare with the dynamic directive 1s assigned a 16-bit negative number, whuch io really a message number. A call ty « dynamic method uses the same dispatch code 10 look up the dynane method, but ifthe method is ‘not found, that means the dynamic method is abstact, so Delphi calls AbstractErrorProc to repowt call an abstract method, Because dynamic methods use negative numbers, you cannot write 4 message handler for negative message numbers, that ss, message numbers with the most- ‘ignficant bit set to one, This limitation should st cause any problems for normal applications. If you need to define custom messages, you have the entire space above WHLUSER ($000) available, up to $7FFF Delphi looks up dynamic methods and messages in the same table using a linear vearch, 20 with large message tables, your application will waste time performing method lookups, Delphi's message system 1s entirely general purpose, so you might find a creative use for it. Usually, uiterfuces provide the same capabilty, but with beter perfor. ‘mance and increased type-safery Memory Management Delphi manages the memory and litetime of strings, Variants, dynamic arrays, and interfaces automatically For all other dynamically allocated memary, you—the programmer—are in charge. Its easy to be confused because it seems as though. Delphi automatically manages the meinory of components, too, but thats just a tack of the VEL. ‘Memory management 1s thread-safe, provided you use Delphi's classes or func- lions t0 create the threads. If you go straight to the Windows API and the CreateTfread function, you must set the Tawyltithresd variable to True, For ‘more information, see Chapter 4, Concurrent Programming, Ordinarily, when you construct an object, Delphi calls Newinstance to allocate and initialize the object. You ean overnde Newiustauve Ww cliange dhe way Delphi allocates memory for the object. For example, suppose you have an application ‘hat frequently uses doubly linked lists. Instead of using the general-purpose ‘memory allocator fr every node, its much faster to keep a chain of available ‘nodes for reuse. Use Delphi's memory manager only when the node lis is empty. IF your application frequently allocates and trees nodes, this special-purpose allocator ‘ean be faster than the general-purpose allocator. Example 2-17 shows simple amplementation of this scheme, (See Chapter 4 for a thread-safe version of this lace) D Chap 2~ Te Dap Objet ModelComponents Versus Objects The VCU's Component class has two fancy mechanisms for managing object lMfeumes, and they offen confuse new Delphi programmers, incking them toro thinking that Delph always manages object lifetimes. 1's umporant that you understand exactly how components work, so you won't be fooled. Every component has an owner. When the owner is freed, it automatically frees the components that it owns. A form owns the components you drop ‘on it, so when the form is freed, it automatically frees all the components on. | the form. Thus, you dont usually need to be concerned with managing the } lifetime of forms and components. When a form or component fies a component st owns, the owner also | checks whether has @ published fie of the same name as the compo- heat I 20, the owner acts that ld to mid. Thuo,f your form dynamealy fads or removes components, the forms fields always contain valid objet references of are nil. Don’t be fooled into thinkang that Delphi does ths for any ather el or obyert referee tre anes nly republished Beli (such 38 those astomatilly created when you drop a component on a form | sn the IDES form edo), and only when the field name matches the compo | Bxample 2 17; Custom Memory Managomont for Linked lasts "Diode ‘Miext, fPrevious: Mode; // Vodsa are under control of Thinkedist. procedure Relinkitetiext, NewPzevious: Tiode): constrictor Creste/Ment: ‘Thoda = nil: Previcus: Mode = nit); procedure RealPree; ass public (estrector Destroy; override: clase function Newinstance: Tobject; override; procedure Freelnstace; override Peonerty Next: Mle read Mt property Previous: Mode read fPrevious; 17 singly Janked Last of nodes that are tree tor reuse. 1/ caly the Next fields are used to maintain this List 11 pitocate @ nov node by getting the head of the Nodebist. 11 Reomsber to call InitInstance to initialize the node that was “Memory Management 3‘Bxample 2-17: Custom Memory Management for inked Lists (continued) 11 Tf the NodeList is expty, allocate 2 node normally. clase function Teade.ewtnstance: subjects begin IE MoceLsst = nil then Result := inherited Nowinetance else begin Result := NodeList; Initinstance(Resule) ; 11 ects the Nndetist wees only the Mont field, set the Previuus 1/ Held to a special value. If a program erroneously zefers to the 1/ Teevicus field uf a Exee node, you can see the special valve 11 aod fnew the cause of the error. BadPointerValueToPlagerrors » Pointer (SPOEENRAD) 11 Bree a node by aAAing £© to the head of the Medel 11 faster than using the general-purpose meviory manager 12 26 you want to clean yp Une List propery when the application 1/ Hinishes, call RealPree for each node in the List. the inherited 11 wreeinstance method frees and cleana up the node for real. procedure Mode. Real Pree; begin Inherited Preetnetanes, nds You can also replace the entire memory management system that Delphi uses. Install a new memory manager by calling SetMenoryManager. For example, you _mught want to replace Delphi's suballocator with an allocatnr that performs addi- tional error checking, Example 2-18 shows a custom memory manager that keeps a list of pointers the program has allocated a explicly checks each attempt to free a pointer against the lis. Any attempt to free an invalid pointer is refused, and Delphi will repor a runtime error (which Systtiis changes to an exception). As a bomus, the memory manager check that the list i» empty when the application ‘ends. If the list is not empty, you have a memory leak. Example 2-18: Installing a Custom Memory Manager unit checiaeaige; interface The Delps Object ModelFxample 2-18: Installing a Custom Memory Manager (continued) uses Windows function Chacktat (ize: Totegar): Pointers function Check#ree(Men: Pointer): Integer: function checkRealloc (ten. Pointer; Size, tnteges) Pointer, espFlags: Diord; // Tn a aingle-threaded application, you might 1/ went to set this vo Heap No Seriatize, Ixplenmntatton MaxSize = Maxnt av 4; te ‘TPointerarcay = arvay[1..MaxSize] of Pointers PPointerkeray = “TPoineerkrray: Heap: Mande; 1 Windows heap for the pointer List List. Ffoineeracray; —_// Let of allocated pointers Listsize: Integer; 11 Mhaber of pointers in the List astaliect ancegers 417 capacaty of ene poanter List 11 XE the List of allocated pointers is not empty when the program 1) Cimishes. that means you have a menory leak. Handling the memory 1) leak ip left a2 an exerciae for the reader procedure Henorvtesky 11 Meport the leak ¢0 the user, but remember that tne program is 1/ sting down, so you should probably stick to the Windows APE 1/ and not use the VoL. ena 1/348 a pointer t2 the Let. procedure Aédten(Nen: Pointer) begin if List © nil then begin 71 New List of pointers. Listaloe *= 8) [Mot += Hesphiloe(tenp, HospFlage, LigtAlice * eiacoE(tointce))y ea else Af Listsize >= Liscalloe enen begin 1/ Make the List bigger. Try to do it sommhat intelligentiy. SE ListAlloo < 256 then Listalloe := Listhlloc * 2 LatAllec = Letallec + 256; isc = Heapkeatioc (weap, Neapriags, List, Listalloe * Sizeot(Pointer)); ea) 11 2d a pointer to the List. “Memory Management 6%Example 2-18: Installing a Custom Memory Manager (continued) Ino(Lletsize) Est (uistsize) := mm; end; 1 took for a pointer in the List, and renwe it. Ratum true for // success, and False if the pointer is not in the list. function Rémrweten(Man: Pointer): Boolean, begin tor i= 1 to Listsise do 4if List (1) © Mon then agin Merwniimory(@List (51, OLee(r+1], (bisteie-2) * sizeot(roincer) 7 Dec(Listsiza); Reoule = Tou Baty 11 Replacenmnt wanzy sllocacor. function Checktet (size: Integer]: Pointers begin Result = Syacetsen(Size) deen (Result); ea U/ X€ the pointer isw't tn che 14t, don't cal the real 1/ Free functicn. Return 0 for success, and non-zero for an @rEOr 1/ Remove the old pointer and add the new one. which might he the 1 ane as the old one, or it might be different. Return nil for U1 an error, and Peiphi will xaiee an ewception. function CheckRealloc (en: Pointer; Size; Integer): Pointers bogin 4 not Renovelisn (em) Chen else begin Ragult :afyahan!Ieem(en, 320) 1 aan (Ret); ena 66 Chapter 2= The Delphi Object ModelFeample 2-18: Installing a Custom Memory Manager continued) procedure SetNetanager gre Mennrysanagaes begin Yar etien = checket, ‘ae. Fresiem = CheckFree; ge_RealLocien += CneceReal Lon SetMenorymanager gt) ene; esp = HeapCceate|0, teapPags, 0); Sebiieianager if Listsize © 0 then MenoryLeak; earner ey a + ea If you define @ custom memory manager, you must ensure that your memory ‘manager Is used forall memory allocation. The easiest way (0 do Us ist set te memory manager 0 2 units snitilization section, as shown in Example 2-18. The memory management unit must be the first unit listed in the project's uses declaration, Ordinarily, fa unit makes global changes sn its snitalization section, it should clean up those changes in its finalization section. A unit in a package might be loaded and unloaded many umes sn a single application, so cleaning up 1s impor tant. A memory manager is different, though. Memory allocated by one manager cannot be freed by another manager, so you must ensure that only one manager is ‘active un an application, and that the manager 1 active for the ensie duration of the application, This means you must not put your memory manager in a package, although you can use @ DLL, as explained in the next section Memory and DLLs If you use DiLs and ty to pass objects between DLLs or between the application and a DLL, you fun into a number of problems. Hirst of al, each DLL and EXE keeps its own copy of its class tables. The is and as operators do not work correctly for objects passed berween DLLs and EXEs. Use packages (described in ‘Chapter 1) to solve dhis problet, another pruble i that anny memory allocated ia DIL 1s owned by that DLL. When Windows unloads the DLL, all memory allo- ‘cated by the DLL is freed, even if the EXE or another DLL holds a pointer to that ‘memory This can be a major problem when using strings, dynamic arrays, and variants because you never know when Delphi will allocate memory automatically ‘he solution 1s to use the sharetiem unit as the first uni of your project and every DLL. The ShareMem unit insalls a custom memory manager that redirects all memory allocation requests t0 4 special DLL, Borlnd\Mdll The application docen't unload DortidMM until the applicstion exits. The DLL magic takee place ‘Memory Management 67transparently, so you don't need to worry about the details. Just make suce you use the ShareMen unit, and make sure itis the first unit used by your program and libraries. When you release your application to your clients or Customers, You will need to unclude BorlndMM al If you define your own memory manager, and you need to use DLLs, you must duplicate the magic performed by the Sharetiem unit. You can replace ShareMem ‘with your own unit that forwards memory requests to your DIE, which uses your custom memory manager. Example 2-19 shows one way to define your own replacement for the Ghasetfem wait. ‘txample 2-19: Defining a Shared Memory Manager 1/ Use this nit first so all memory allocations use the shared 11 memory maager. The exclication ant nt Mite must use thie untt. 1/ You canmot use packages because those DLLe use the default Borland 1) onared mano manager ater cave fumetion Checktet (Size: Integer): Pointer function CheckFree (Men: Pointer): Thtege fmetion ChectRealloc Wen: Pointer; Size: Integer); Pointer; {nplenentation BLL = "Chechaat.alD' fmction Checkiet (Size: Integer): Pointers external EL; fncticn Cheskrree ems Pointer): Integer, external DLL; fumetion CheckRealloc (Man: Pointer; Size: Integer): Pointer Procedure Sethewanager; Mgr: Dlenorymanager begin Mgr. Gaten + Checkcet; Myc. Peeetew i= ClsckF ree; Mgr Reallocten := Checkealloe; Settanoranager (ge); ea) inirtarizatson Setilanager; ‘he Check¥@4 DLL uses your custom memory manager and exports is functions so they can be used hy the Checkshareden unit, Example 220 chows the source code for the Chacka library. (68 Chapler 2= Toe Delphi Object Modelxample 2-20: Defining the Shared Memory Manager DLL brary checlan; 11 Replacement, for BoxIndMi.dl1 to use a custom nenory manager. Chechen: egorts Checkset, CheckFree, Checkealloc: besin ‘Your program and library projects use the CheckShareMem unit first, and all memory requests go 10 CheckMAL dll, which uses the errorchecking memory ‘manager. You don't often need to replace Delphi's memory manager, But as you can see, it sn difficult to de The memory manager that comes with Delphi works well for most applications, but it does noc perform well in some cases. The aver- ‘age application allocates and freee memory in chunks of varying sizes. If your application is different and allocates memory in ever- sncreasing sizes (say, because you have a dynamic array that grows fn small steps t0 a very large size), performance will sufer. Delphi's ‘memory manager will allocate more memory than your application needs, One solution 1s 10 redesign your program so it uses memory 1m a different pattern (say, by preallocating a large dynamic array). ‘Another solution is to weite a memory manager that better meets the ‘apceniized aceds of your application. For example, the new mem ‘ory manager might use the Windows API (GleapAlLocate, etc). Old-Style Object Types 1m adiion w css ypes, Delp supports an obsolete eype that uss the object keyword. Old-atyle objects exist for backward compatibility with Turbo Pascal, but they might be dropped entirely from future versions of Delph. Old-style obiect types are more like records than new-style objects. Fields in an fleLayle object are laid nur in the same manner as in records. If the object type does not have any virtual methods, there 1s no hudden field for the VMT pointer, for example. Unlike records, object types can use mhertance. Derived fields appear after inherited fields. Ifa class declares a vitwal method, is first field is the YMT pointer, which appears after all the anherited fields. (Unlike a new-style object, where the VMT pointer is always firt because Tobject declares virtual methods) Old-Shle Object Types 65An oldstvle object ype can have private, protected. and public sections, but aot published or automated Sections, Because it cannot have @ published section, un old abject type cannot hive sy runtime re Information An old ebsect type cannot implement interfaces. Constructors and destuctors work diferenty in old-style object types than in ew-syie clase types. To create an instance of an old Object ype ell the New procedure. The newly allocated obyet is intaized to all sero. I you declan» constructor, you can calli 28 part of the eal to Rew, Pass the constructor name sd arguments wo ie secon argument o New Simualy you cas call a destuctor ‘when you cll Dispose to fee the object instance. The destctor pamela ‘ments are the second argument to Diepose You don' have to alloite an old-syle abject instance dynamically You can treat the object type ae record type and declare object ype vanables ss vale level or local variables. Delphi automaticaly intalzes sting, dynamic ary, and Vara flelds, but doesnot maize oer tes inthe obec instance Unlike newsiyle class types, exceptions in old-style constructors do not automat- ‘cally cause Delphi to free a dynamically created object or call the destructor ‘70 Chapter 2— The Delphi Object ModelCHAPTER 3 Runtime Type Information Delphi's Integrated Development Environment (IDE) depends on snformation provded by the woupiler. This formation, called Runtime Type information (RTTD, describes some aspects of classes and other types. It's nota full reflection system such as you find in Java, but i's more complete than type identifiers sn Ces For ordinary, everyday use of Delphi, you can ignore the detaile of RTTI and just lec Delpiu do its thing. Sometimes, though, you need to look under the hood and understand exactly how RTTI works, ‘The only difference between a published declaration and a public declaration is RITI. Delphi stores RTTI for published fields, methods, and properties, but not for Public, protected, or private declarations. Although the primary purpose of RTTL 1s to publish declarations for the IDE and for saving and loading df files, the [UTI tables include other kinds of information, For example, virual and dynamic methods, interfaces, and automated declarations are part of a class's RTTI, Most 1 called type myformation This chapter explains all the details types also have R of RTTL Virtual Method Table ‘The Virtual Method Table (YM) ctores pointer to all the virtual methods declared for a class and its base classes. The layout of the VMTT 1s the same as in most C++ ‘implementations (inchiding Borland C++ and C++ Builder) and is the same format equived for COM, namely 2 list of posters tr methods Rach veal method of a class or its ancestor classes has an entry in the VMT Fach class has a unique VMT. Even if a class does not define any of its own viral ‘methods, but only inherits methods from its base class, it has its own VMT that lists all the virual methods it inherits, Because each VMT lists every virtual ‘method, Delphi can compile calls to virtual methods as quick lookups in the VMT. Because each class has is own VMT, Delphi uses the VM to identify 4 cass. In nfact, a class reference 1s really a pointer to a class's VMT, and the Classmype: ‘method retuins a pointer to the VMT. In addition to a table of vutual methods, the VMT includes other information bout a lass, such as the class name, a pointer to the VMT for the base class, ral pointers to many other RTTT tables. The other RTTT pointers appear before the fist Viral method in the VMI. Example 3-1 shows a record layout that 1s equivalent to the VMT. The actual list of virual methods hegins after the end of the ‘TUme record, In other words, you can convert a Telase class reference t0 a pointer to a "Wine record by subtracting the size uf te record, as shown in Example 31 ‘Example 3-1, Structure of a VMT Pim: = “cv ‘Tint = record SelfPtr: aelane: U1 Boinee fanaa to the start 11 of the vie 1/ he following pointers point to otlet RITE tales. Tf a class 1/ oes not have a table, the pointer is nil. this, moet classes 71 pave a nit intrvapie and AuteTable, for example, Intetable: PinterfaceTable; // Tnterface table antoTable Pautotable 11 Mutewation table Initrable: Pilea 1) Welds needing finalisation ‘ypemnto: Prypetnfo; _J/ Proparties & other info Bielaebles reieiafeble, —// Ptinte Letts PlethoaTable; —// Published methods woymetnodtable; // List of éymanic methods Pshortstring; // Points to the class nane Instancesize: Lengine:——// Stxa of each abject, im bytes Classtarent: “qlass; ——// immediate base class 1/ The following fielés point to speclal virtual methods that U7 ave hwerived fxem iubject. Safecallniception: Pointer; Afterconstruction: Pointer Beforedestruction: Pointer: Dispatch: Pointers Yewinatance: Pointer; Destroy: 1/ Mere begin the virtual meted pointers 11 Bach virtual method is stored as a code pointer, 0.9., 1) Visessidathoarabler array[L..Count] of Pointer, 11 Bit the compiler does not stare the cout of the mnber of 77 smite pointers in the table, end; ees Pint begin 11% get a Wine pointer from a clase reference, cast Ue Lia D Ghapir J Ranta Hip toon —Example 3-1. Structure of a VMT (continued) 1/ reference to the Punt type and subtract the size of the TMM 17 record, This 18 easily done with the Dec procedure: Vat = Pint (SoneObject.Clasetype} Dec it As you can see, the VMT includes pointers to many other tables. The following ‘sections deseribe these tables in more detail, Published Declarations ‘The only difference between a published declaration and a public one 1s that a published decluation tells die Compiler w store information in de VMT. Only, certain kinds of information can be stored, so published declarations face a number of restrictions: + In order to declare any published fields, methods, or properties, a class must have RTTT enabled hy using the $e directive or by inheriting from a clase that has RTL. (See Chapter 8, Compiler Directives, for details.) + Fields must be of class type (no other types are allowed). The class type must have RTT enabled. + Array properties cannot be published. The type af a published propery cane ‘not be a pointer, record, or array If it isa set type, it must be small enough t0 bbe stored an aur uneyer. In de current release of Delphi, that means the set can have no more than 32 members. ‘+ The published section cannot contain more than one overloaded method with each name. You can overioad methods, but only one of the overloaded meth- cds can be published. ‘The Classes unit declares TPersistent with the $+ directive, TPexsistent is usually used as a base class for all Delphi classes that need published declara tione, Note that "Component inherits from Persistent. Published Methods Delphi stores the names and addresses of published methods in a class's RTL ‘The IDE uces thio information to ctore the valuee of event properties in a dfn fie In the IDE, each event property is either nil or contains a method reference. The ‘method relerence includes a pointer to the method's entry point. (At design time, the IDE has no tre entry point, so it makes ane up. Ar mintime, your application uses the method's real entry point.) To store the value of an event propery, Delphi tooks up the mediod address in the class's RTTL, finds the corresponding ‘method name, and stores the name in the .dfm file. To load a .dfm file, Delobi reads the method name and looks up the corresponding method address from the lace RFT, A class's RTT stares only the published methods for that class, and not for any ancestor classes. Thus, to look up a method name or address, the lookup might fail for a denved class, in which case, the lookup continues wrth the base class ‘The MethodName and Methodaddress methods of TObiect do the work of Published Declarations 73searching a class's RTTI, then searching the hase clases RTTT, and so 09, up the mhertance chain, (See the TObject type in Chapter 5, Language Reference, for details about these methods.) The published! method table contains only’ the ‘method name and address. You can declare any method in the published section of a class dectaration. ‘Usually, though, Delphi's IDE creates the methods for you, When you double-click fan event property. for example, the IDF creates a method in the inital, unnamed section of the form class. Because a form class has RTTI enabled, the inital, lunnamed section is published. (Form classes have RIM because TPersistent is din ancestor class) ‘The method table starts with a 2-byte count of the number of published methods, followed by a record for each method. Each method record starts with a 2-byte size of the method coco, followed by the method address (4 bytes), and then, followed by the method name as a shor stung, that is, as a L-byte stnng length followed by the text of the sting. More Method RITI ‘The record size for a method is usually 2 + 4 + 1 + Length(Name), but some method records luave audlidonal information, The additional information is ‘not part of the official RTT for the class, Future versions of the compiler ‘might not generate this information, so you should not write any code that relies on it. The information ie anteresting, though, so take « luk at what Delphi hides in its method records. Delphi stores additional information for methods that use the stdcall. calling convertion and that have parameter and return types for which Delphi ordinarily stores tyne mformation, The extra information 1 stored afer the method name and mcludes the names and types of the parameters. ‘You caa tell thi extra information 1s preseut whit ie size of the method record is larger than it needs to be to store the record size, method address, ‘and method name. If the size 1s 4 bytes larger than it needs to be, that ‘means the methor! takes nn parameters. The extra 4 bytes are always eer. If the size is more than 6 bytes lager than it neers tae, the anformation for the method's parameters 1 stored following the sixth byte, (The extra 2 bytea do not scem to serve ay useful purpose, but they are not always zero.) Each parameter has a pointer to a TIypelngo record for the parant- eters type, followed by the parameter name (as a short string), followed by a teiling #0 byte. (See "The Typlafo Unit later in this chaptes, wy Tea about the Typetngo record.) Example 32 depicts the logical structure of the method table, Note that Deipl ‘cannot use these declarations verbatim because the record size varies t fit the size of the stangs. 74 Chapier 3 Runtime Type Information ~Example 3-2: The Layout of the Published Method Table ype "MiethodFaran = packed record ‘aypeinfo: PPIypeTnto; Tape: shortstring; 11 ha nana 18 foltoumd ty a Praiting #0 Hye ena: Size: Word: 1/ S20 of the TneNethod record, ‘scrass: Poanter: 11 Pointer to the nethed entry point Nane: packed shorestring; // Nane of the published method, 1/ Seve methods have sn edditional 4 zero bytes, which means the 1/ Some methods have an adaitional 6 bytes, followed by a series of 1/ Te seems that enly steal) methods have this extra information, 17 You can identity the extza into by the "Method. Size value being 1/ too big for just the Size, Addzess, and Name nenbere. The only 11 way to know how many paraneters are stored here is to check Bxtrastuft: array(l. FourOrsix] of Byte; Rarone: array(i.-Darantount] of TathodParcs, end (Crupiished method tabte 7 ‘TiathodTable = packed record count: word, Methods: array! 1. camt) of Method ea, Published Fields and Field Types Each published field has a name, a type, and an offset. The type is a class refer- ‘ence for the field's type. (Published fields must be of class type.) The offset is an offset (in bytes) nto the object's storage, where the field 1s stored ‘The published field table stars with a 2hyte count of the number of fields, followed by a d-byte pointer to a class table, followed by the field definitions Each field Uefaidon tsa record contuming a +-byte offer, and a 2-byte index into the class table, followed by the field name as a shor sting. ‘The class table list all the classes used by the published fields. Each field contains an index into this table. The class table starts with a 2-byte count, followed by a lic of class references where each class reference is 4 bytes. A class reference is a pointer to the clases VMT. Example 3-3 shows the logical layout of the field table. Because the records are Variable length, you cauiol use lisse declarations ai « Delp prograt, Example 3-3: Layout of the Published Field Table ( Piet class table } Prielaciasefuble = “[Picléclassrable ‘eielaclaseTable = packed record Published Declarations 73Example 3-3: Layout ofthe Published Field Table (continued) ‘count: Word Classes: packed arcay{1..count] of “Ilass; ed; ( Published fed xeooed ) ‘Wield « packed recor’ OEfset: tocamord: 11 yee offset of taeld sn the object. ) Classindex: Word; // Index in the Fialé-lasotable of the 1 elas type. Name; packed Shortstrina: // Nae of the gibtiehad flat. 5 ex ( pantished Heid table } ‘Tieumreble = packed record ‘count: Wore; MieldclascTable: PPieléClaseTable; Fields: packed array [1,.Count] of TField: eo Published Properties Published properties have lots of information stored about them: name, ‘ype, reader, writer, default value, index, and stored flag. The type is a pointer to a ‘Tiypatnfo ervord (discussed sn the next section). The reader and writer can be fields, methods, or nothing. The default value 1s an ofdinal value, non-ordinal properties don’ have default values the stored tlag can be a constant, «field ora method reference. The Object Inspector in Delphi’ IDE elles cm published peop. ferties, and Delphi uses the default and stored information wen saving and loading fn feo ‘The reader, writer, and stored fel cin be pointes to static methods, byte oles of vitual methods, or byt offsets of fields. Dynamic methods are not allowed, and ‘sav of vital methods must use the register calling convention (which 1 the default). Additionally. the stored value can he a constant True or False. Delphi stores these diferent kinds of values as follows + A constant True or False is stored a8 a literal zero or 1. Only the stored directive can have a constant Teve of Fase. Ir a veader ot wilet 2240, at ‘means the property does not have that particular directive, that 1s, the prop eny 18 write only or read-only, respectively + A fickd uffet stored with SRF in the most signicant byte, For example, a field stored at offset 42 ($2A) would have the value $FFOQOO2A. Note that published fields are rarely used to store property values, so its unlikely that you could look up the name of the field in the published fet table + A virtual method is stored with $FF 1m the most significant byte and the byte offset of the method 25 a Snallint in the low order 2 bytes. For example, the dnd vutual method is sored a8 SFEOOUDNE, (ihe frst virtual method has offset 0.) 76 Chapter 3 Runtime Type InformationPublished Fields and Components ‘When you drop a component on a form in Delphi's IDE, the IDE creates a published field declaration for that component. Delphi takes advantage of published fies sn the form class when saving and loading .dfm files, but the mechanisms Delphi uses are common to any component because they are implemented as methods of the Component. class, these tncks are not part ofthe Delphi language, but they affect most Delph programs. When a component (call it Owner) becomes the owner of another compo- nent (call it Chi), the child looks up its name (that is, the value of the Nave propery) in the owner. If Oumex has a published field with the came | ‘name as Child, the owner sets the value of its field to be a reference to the | child object. When Child is destroyed, Owner checks again for a published field of the same name, and if it finds a match, it sets the eld to ni Usually, the only time a Delphi programmer encounters this behavior 1s for the published fields of a form, When Delphi loads a fm, it creates the child components, The form class (which 10 the owner) notices that» compor nnent’s name matches that of a published field and automatically sets the Field to refer to the newly created component, Im other words, the Delph language does not treat components or forms specially Instead, the Tomponent class knows about published fields and ‘ses that information to manage the components it owns. Don't be fooled nto thinking that Delphs automatically manages the lifetime of all compo- nents just because it manages some components, | ‘The published field table is especially umpostant when loading a dim. When Delphi loads a component Irom a fm, it reads the name of the compo: nnent’s type as a string. Delphi needs a class reference for the class name, which it can look up an the field class table. If you write a component that stores a subcompuneut wind daa subcomponent is nue declared an a Published field, you will need to register its class explicitly by calling RegisterClass or RegisterClasses (both in the Classes uni). Regis: tering classes ie not a feature ofthe Delphi language. [A static method ss stored as an address, ¢ ., SOOI01BA2, The memory architec- ture of Windows prevents any method fiom having an address with $FP or $FE 1m the most significant byte, so there is no danger of conflicts or ambiguities. The default value can be stored only for integer, character, enumeration, or see types. If the programmer declares a property with the nodefault directive (which Js the same as omitting the default directive), Delphi stores the most negative integer ($80000000 or ~2,147,483,648) as the default value, In other words, you cannot have an mteger property whose default value i ~7,147 483,648 because Delphi would interpret that as being the same as nodefaullt. Published Declarations 77String, floating-pomt, Int64, Variant, and class-type properties cannot have default ‘values, and the nodefault directive has no effect. (Delphi always uses an empty string, 2210, Unassigned, o1 ‘nil as the default value for these types when reading and writing fm files.) lt you want the effect of defining a default value for these kinds of properties, you can play a tack in the clas’s construc tor: set the property's value when the user drops the component on 2 form, and not wliew Delpln loads the component from the .djm file. What makes this tricky 1s that the Competent State propery is not set until after the constructor returns. (Read about Componentstate in Delphi's help files.) Thus, you need to test the ‘owner's Conponentstate, as follows constructor TStringbefaul Create (owner: bbogin Af (omer = ntl) or (((esReading, esdesigning] * Ormer.ConbcnentState) = {cadestgning]) then SteingDroperty + ‘Dofsult value! ends ‘This trick does not save any space mn the cfm fle, but it achieves the goal of setting a default value for a property that does not ordi sarily take a default value. The primary purpose of a default value 4s to save space in a dfn file. If & prop: leny’s valuc is the same as the default value, Delp doesn’ store that value in the df. Ifa propery does not have a default value, Delphi always stores the value sn the dfn. Note that inherited forms get their default values from the ancestor form, which gets it frnm the dofaule directive. It ithe programmer's responsibilty t initialize a propery to its default value sn the class's construetor—Delphi doesn't do that automatically (See Hxample 35, later in this chapter, for help setting default property values.) ‘The index directive stores the index value for an indexed property If the prop= ceny 18 not indexed, Delphi stores the most negative integer asthe index value ‘The published property information also stores the name index, thats, the ordinal position of the propeny sn the clase declaration. The Object Inspector can zort properties into alphabetical order, which scrambles the declared order of a class's properties. The name index value gives you the orignal order, Delphi makes it casy to access « Uass's published propery information using the ‘Typingo unit, which isthe subject of the next section FR Chapter 3— Runtime Type InformationThe TypInfo Unit ‘The Typinfo unit declares several types and functions that give you easy ate to the published properties of an object and other snformation. The Object Inspector relies on ths information to perform its mage. You can obtain a lit of the published properties of 4 cass and get the name and type for each propery Given an object relerence, you can get of set the value of any published property “The Typetngo function retumns a pointer to a type information record, but if you don't use the Typingo uni, you cant aces anil in dit record and must instead weat the result as an untyped Pointer. The Typtnfo unit defines the real type, which ss F1ypetnfo, that i, a power to a TIypetnto record. The type information record contains type kind and the name of the type, The spe kd ssan enumerated value that tells you what kind of type it: integer, floating pon, string, ete Type Data ‘Some types have additional type data, as retumed by the GetTypebata function, ‘which rerums a vlypebata pointer. You can use the type data to get the names of an enumerated literal, the limits of an ordinal subrange, and more. Table 4-1 describes the data for each type kind, Table 3-1. Type Kinds and Thewr Data TihpeKind Literal | Assoctated Data Garay No associated data, ehchar Lionts of character subvange tkclass Class reference, parent clas, unit where class 1s declaced, and published properties. Uoyunccay [No assoctated dara for dynamic arrays tkBauneration | Ifthe rype isa subeinge of another type, the data includes a pointer to the base type and the limits of the subrange, otherwise, the data includes the limits of the subrange aid 2 packed list of counted strings for the names of the feruimerated literals, tkeloat, Floaring-pownr type: eumrency, comp, single, double, or extended (but not Real 48), eines Limits of integer subrange. eemnteger Limits of integer eubsange. tkInterface | Base interface, unit where the interface 1s declared, and the GUD. wasteing No ascoaated data for a long stang (Ansists:t) tidtethod Return type, land of method, and parameter names and. type names: eenecord [No associated data ekset Pointer to the enumerated type of the set elements. tkstring Maximum length of a shor stang, The Typinjo Tt 79 FpTable 3-1. Tybe Kinds and Their Data (continued) Thpekind Literal | Associated Data Exunnown No assocated data ~ tevariant No associated data, esichar Limite of wade character subrange. kustring [No associated data for a WideString. [Note that the prmary purpose of type information iy support Delphi's IDE and. for reading and writing dfn files. A secondary purpose is for initialization and finalization of managed types. It is not a general-purpose reflection system, as you find in Java, so information about records and arays, for example, i limita. Published Properties Many of the functions in the Typinfo unit make it easy for you to access the Published propenies of an object Instead of accessing the type information directly, you can call some functions to get or set a property value, determine whether the property should be stored, get the property type and name, and so on. ‘To get or seta property value, you need tw know what kind of propery type you are dealing with: ordinal, floating point, string, Variant, method, or Int64. Each kind of type has a pair of subroutines to get and set a propery value. If the prop- femy has methods for the reader or writer, the Typingo routines call those methenl, just as though you were getting or setting the propeny in the usual manner. Integer., character”, enumeration, set-, and classtype properties are ordinal. They sire their propery values in an integer, so You must use an integer to get OF set the propery value. When you get the propery value, cast it ro the desired type. To set the property value, cast the value 10 an integer. Example 34 shows a procedure that takes any ‘component as an acguineim inl teats whether tat component publishes a propery called Font whose type is a class type. If so, the procedure sets the component's font to Aral, 10 pt Example 3-4: Setting an Ordinal Property Procedure SetFontTotrial1Opt (Component: Teempanent) ; Font: Font; eopinfo, Phroptafo, besin U1 Parse fund out Sf the component has a Pont property. Propinfo := GetPropinfo(Ccmpenent, Font); 4f Propinfo = nil then ait: 11 Wert sve if the property bas class type. AE PeepInts.FroptypeRlinl ~ UAelane Un Bat) vont. 1 a¥ont.create; ty Pont.tlane i= "Arial; Font. Size := 10; 80 Chapter 3 Runtime Tipe Information‘Example 3-4: Setting an Ordinal Property (continued) 1/ Move sot che component's Font property. Securaprep(Ccmpanent, Proplnto, Integer (Pont); 11 Set0rdProp is just 1ike Conponent..Pont. := Font except that 11 the compiler doesn't need to know about. the Font property. 11 The component's writer nopies the Tent ckject, 22 thie 1 procedure must free ite Font to avoid a menory leak sinally. Pont ree; end You can get a list of PProptngo pointers if you need to Jeam aheut all of an ‘object's properties, or you can call GetPropIngo to learn about a single property The GetPropList function gets only piupeitis whse «ype kine! matches a set of type kinds that you specify You can use this to leagn about events (tktfethod) sirng-valued properties only (tkString, tkistring, tkwString), and so on Feample 3.5 shows a procedure that takes an object ae an argument and looks up all the ordinal-type properties, then gets the default values of those properties and Sets the property values to the defaults. You can call this function from a constructor 10 guarantee that the properties are prnperly initialized, thereby avoiding 4 possible error where the propery declaration has one default value, but the constructor has a differeut une Example 3-5: Setting Default Property Values // Sec the cetauit vaive tor alt publishes properties, ‘Procedure SetDofaultValues (Obj: TObject); Fekenuneration, tintager, Herman, eset, eHachae Prophist: PrropList ccoune, 4: anvegers Value! Integers begin 1/ Count the muber of ordinal properties rhat aan have 1) degaute values Comme 1= CotPropList (Obj, thOrdinad, afl), // allocate mewory to store the prop info & get the zeal prop List. \cecmen(vropuist, Count * S:260t PPropTnto)); oy GetzropList (Obj, thordinal, Proplist); 11 Loco throu all the ordinal prepertiog for Y += 0 to Count-i do J) XE Who propesty has a default value, est the yaupeaty value 71 to that default, Af vropuise(1) vetault © sopetault ten SetordProplObj, Propulet (1), PropList(1].Default) Sinaliy Freeion(Proatiat) + end; The Tiplnfo Unt Bi‘The routines in the ypInfo unit, while not documented, are straightforward and easy f0 use. The following list describes all the subroutines an the Typtnfo unit, for your convenience, Conaule the Typlnfoprar source file for further detils (provided you have at least the Professional edition of Delphi or C+ Builder) [Note that these lunctions perform little of no error checking, It is your respons- bility to ensure that you are calling the correct function foe the property and ite type. Changing the value of a read-only property or getting the value of a write- uly property, for example, results in an access violation, GotkinumNiame function ‘function Getiamttane Typetnto: PIypelnt Returns the name of an enumerated literal or an empty string if Value is out of range GotksnumProp function function GetBrunPrep (instance: TObject; Propinfo: PPrepInto) ering; overload: function GettumProp (Instance: TObject; const Propane: string): string; overload Retuins the nae of die enumerated Iteral that isthe propemy’s v GetBnunVale furetion function GetSrunifalve(Typelnfo: PIypetnto; const Name: string):Integer: Retums the ordinal value of an enumerated literal or =1 if the type has no eral with the given name, GetPloatProp function function GetFioatPrep (Instance: TObject; Propingo: PPrepingo) [Betended, overiced, ‘function GetFloatProp (Instance: Tbject; const Propane: stxing): ibxtenaec: overload: Gets the value of a propery with a floating-point ype, Gettnt6-4Prop function function Getint6¢Prop (Instance: Object) Prepinfo: PProplnto) : Intél, overloads, fimction GettntsdProp instance: TWbject; const Propane: string): sntss; overioaa; Gets the value of a property of type Tnté4 or any subrange that requires ‘more than 32 bits to represent. GetstethodProp function function OettetedrseyCustance: TOblect; Fropinto: ¥eropinto) : ‘Mletbod: overload: function GetethodProp(Instance: TObject; const Prepllane: string) ‘Method; overload; Gets the value of an event property GeatObjectProp function ‘function GetObjectPsup(ustance: TobJecti Eropinto: veropinto; Minclass: Telass = nil): TObject; overload; function GetobjectProp(Instance: TUbject; const Propltne: string: Minclass: ‘lass = nil): "Object; overload: falue: Integer): string: 82 Chapter 3— Runtime Type InformationGets the value of a class-ype property MinClass 1s the base class that you require for the propeny value; if the result is not of type MinClass or a descendant, Gat Object Prop reniene nf The default isto allow an object of any clas, GetObjectPropCtass function ‘function GetdbjectPropClace(Inotance: Nebject; Teoplnfo: Pxoptno} ‘Clase; overlosd; Fuictlus Getobjectrropclass instance: 1Ubject; const Propitane: string) : ‘elass; overioad: Gets the class type from the property's type data. Instance is used only to look up the propery information, so the fist version of this function (which already has the propery information in the PropIn€o parameter) does not refer to Instance, Get rdProp junction function GetOrdrep(instance: TObject Prapinta: #erepinfo) ‘vmgint; overload; function GetordPrep (Instance: Thject const Propllane, =telin) engint; overload; Gets the value of any ordinal type propery, or any property whose value fits mma 32 bit integer, eg, object, set, character, enumerated, oF iieger subrange, GetPropinfo function furctia Qetreuytute(Rypetite: PrypeIngO; Conse ropeame: string) PPrepinfo; overload; function GetPrepinfo Typetnto: PIypetnfo; const Proptime: string: ‘AEinds: TypeKinds): PEropInfo; overload; function Geteroptnto (Instance: TObject; const Propane: string; Axindss ‘typekinds = (])+ Bprepingoy overload fiction GetPrepInfo(aClass: Clase, const Propane: string; ‘Aeindss ‘Types ~ (1): FRewpinto; overload, Renims the PerapTnta pointer for a published propery or nit if the clacs does not have any such published property or ifthe named property does not have the correct type. The frst argument can be an object reterence, a class reference, or a class's type anformation (from the Typelngo function or Classinfo method). GetPropinjos procedure Drocedure GatPrapinfos(TyreTnfa Pypetnfa: PrapList: PPeopLtse): Gets a list ofall the PProptnfo pointers for an objec, in declaration order, Use the class’s type data to learn how many published properties the class has, s0 you can allocate the Propliot array GetProplist function function GetPropList (Nypetnto: Ptyperné Peoplices PErcpLict) + Integer; Gets an alphabetized list of FPropInfo pointers for the matching properties ff an object and returns a count of the number of properties stored in Proplist, Pass nil for the Peoplist paraucier wW get a count of the ‘number of matching properties. ‘ypeKinds: Typetinde; Tee Tipp OaGetPropValue function function GetPrepalue (Instance: Object; const Proptlane: string; PreferStrinas: Boolean = True): Variant: Gets the value of a published propery as a Variant. GetPropValue incurs more overhead than the other Get... functions, but is easier to use. If Proferstrings 1 True, GetPropValue will etore the property value ao a string, if this is possible GetsetProp function funation Cetesttrep (inetance: TWbject; Propiafo. PRLUpEACys Brackets: Boolean = False]: string; overloads ‘mation vecsetvrop(instance: Tonject; const Propane: string ‘Brackets: Boolean = Fale): string; overloads Gets the value of a settype propery and returns the value as a string, The format of the string 1 a ist of enumerated inerals, separated by commas and spaces, You can optionally include square brackets. The format is the same as that used in the Object Inspector. GetStrProp function function Gatstrbrrn(tnstanre: Thyject; Propings: PBropinéo) + stringy ‘overload; faction detotsPrep Instance TObject; Cush Raflane: veeleg) string: overload; Gets the value of a stnng-type property The propeny type can be tkstring, tkagtring, of EkHSteLng. In all cases, die prupenty value 1 automatically converted to string, GetTypeData function Tunccion veciypeustaiypeinto: Plypetnto): PIypeData; Returns 4 pointer to a type'e MypeData record, given its PIypetnge pointer. GetVariantPrep fuunction function GetVariantProp(Instance: Tobject; Proplnfo: PPrapinfo) function GetVariantProp (Instance: Object; const Proptiane: string) ‘Varlant; overioaas Gots the value of a Variant-type property |bPublishedProp function function TsPublishedPrep Instance: TOject; const Pregame: string): Booleans vselosdy fmction TsPublishedPrep|AClass: Tlase; const Proptiame: string) Rens True ifthe class has a published property of the given name, {sStoredProp function function IsStoredProp (Instance: TObject; Propinfo: FPropinfo) : Becleany overloads function TsStoredProp (Instance: TUbject; const Propltane: string) Dove; overioea: Renvens the value of the stored directive, If the etored directive 19 a method, IsStoredProp calls the method; if itis a field, the field's value is retumed, 84 Chapter 3~ Runtime Type InformationProplsType function function Propistype(Instance: TObject; const Propane: string; ‘rypekinds TypeFind) + Boolean) overload) function Proptstype(AClass: Class; const Progtane: sting: ‘Typetnl: FIypening) + Boolean; overload; Returns True if the named property exste and has the given type, PropType function function Propiype (Instance: TObject const Propane: string): ‘ypetind: overload; function Propiype(aClass: TClass; const Propane: string) Tryoenien; overiowds enim the type kind of 2 published propery or raises an RPxopertyExror exception ifthe class does not have a property with the given name. SetEnumProp procedure rocsire SctimuntroplInstance: Tobject) Propinfo: Feu Buty; const Value: string) overload; proceaure setinumrop{instance: Tobyect; const. Propilime: string ‘const Value: string}: overload: Sets the value of an enumerated-type propery, gven the name of an enumer- ated leral. If the value is not the name of an enumerated literal, ‘SetnumProp raises the EPropertyConvertError exception. If you have the ordinal value instead ofthe literal name, call SetOx€Prop. SetRoaiProp procedure procedure SetFloatProp (Instance: TWhJents Praptnfa: pPrepnt: Value: Extended) ; overload procedure CctFlostivep( Instance: Whject, const Fropitane, sti Lins Value: Extended); overload; Sets the value of a property with a floating-point type. Setint64Prop procedure procedure SetInt64Prop(instance: Tobjact PrepIntas PPrapinfo; ‘const Value: Int6l); overload rovodure SctInt64Mrop (Inotance: TObject; const Propiaae. string; const Value: Intl); overload; Sets the value of a property whose type is Int64 or a subrange that is larger than 32 bits SetMethodProp procedure procedure SetMethodPrep|Instance: TWbject; Propinfo: PRropingo; const Value. ‘Tietlnd) ; ures vad procedure Setéethodrep instance: TObject; const Propane: string: ‘const Value: TMethod) ; overloads Sete the valus of an event property. SetObjectProp procedure rocedure SetdbjectProp(Instance: TObject; Propin Value: Object), overland procedure SetobjectProp (Instance: TUbject; const Pregtane: string: ‘value: Tosject); overlosd;, Prrepintor The Typinfo Unit 83Sets the value of a classtype property, If Value is not of the correct type for the propery, SetobjectProp silently ignores the attempt to set the property ‘SetOrdProp procedure Drocedure SetOrdProp(tnstance: object; Prepinfo: PPropingo; Value: Lengint); owoelosds procedure SetordProp(Instance: Object; const Progilae: string; Valuer tongint)? overionds Sers the value of any oedinaltype property, including eete, obyectz, characters, and enumerated or integer properties. SetProp Value procedure procodurs SctPrepValue (Instance: TObject, cust Pauyttum: vteing; ‘conet Value: Variant) Sets the value of a propeny from a Variant. SetPropValue must be able to convert the Variant value to the appropriate ype fur die propeny, oF else it raises an EPropertyConvert Error exception. SetSetProp procedure [procedure sersecvroptunstance: IWoyact; Preprnto; PPropino; const Value: string); overlosd: procedure SetSetProp(Instance: Object; const Frogtiae: string; ‘const Value: strincl: overload: Sets the value of a setype property by interpreting a string as a list of enumerated literals. SetSetProp recognizes the format that GetSetProp remmms 1 the format af Value i not valid, SetetProp ruses an EPropertyConvertBrror exception, SetstrProp procedure [procedure Sotstetop(matance: Tobject, Prvpiatss Phau: const Value: string); overload; ‘procedure secstrvroplinstance: ‘byect; const Propltane: ating; ‘const Value: string); overload; Sets the value of a sttingtype property The property type can be tkstring, Bastring, or Dastring SatVartantProp procedure Procedure SetvarlantProp(Instance: TUbject; Prepinfo PPrapingo, ‘const vaive: Varuant)? overload; procedure SetVariantProp(Instance: Tbject; const Erosilane: str! ‘const Value: Variant); overload; Sets the value of a vartane-type property. Virtual and Dynamic Methods ‘The YMT stores a lst of pointers for virtual methods and another table n the VMT, ‘which this section refers to as the dynamic method table, lists both dynamic ‘methods and message handlers. ‘The compiler generates a small negative number for each dynamic method. This negative number is just like a message number for a message handler. To avoid ‘86 Chapter 3 Runtime Type Informationconflicts with message handlers, the compiler does not let you compile a message handler whose message number falls into the range of dynamic method numbers, ‘Once the compiler has done its wods, though, any distinction between dynamic ‘methods and message handlers is los. They both sit in the same table and nothing indicates whether one entry is for a dynamic method and another 1 for a message handler ‘The dynamic method table lists only the dynamic methods and message handlers that a class declares; it does not include any methods inherited from ancestor classes. The dynamic method table stars with # 2-byle wut of the number of ‘dynamic methods and message handlers, followed by a list of 2-byte method ‘numbers, followed by a list of ¢-byte method pointers. The dynamic method table ‘is organized an this fashion Gastead of having a let of records, where each record hhas a method number and pointer) to speed up searching for a method number. Example 3-6 shows the logical layout ot a dynamic method table, As with the cther tables, you cannot compile ths record, because it 1s not real Pascal, just 4 descnption Of what a dynamic method table looks like, Example 3-6: The Layout of a Dynamic Method Table ope Wptielareble = packed record Come: Words Inderes: packed exvay{1. Count) of Snallint; ‘Aédresses: packed arrayil. Count] of Pointers end; Dispatching a message or calling a dynamic method requires a lookup of the method or message number in the Indexes array “Ihe table is not sorted and the lookup is linear. Once a match 1s found. the method at the corresponding address is mvoked. If the method number is not found, the search continues with the smmediate base class. when all ofthe following conditions apply: = You are creating a large framework of hundreds of classes — You need to declare many virwal methods in the classes near the root of the inheritance tee. — Those methods will rarely be overridden in derived classes. — Those methods never need to be called when speed is important i ‘The only time your should even consider using dynamic methods is ‘The tradeoff herween viral andl dynamic methods is that virual method tables include all inherited virtual methods, so they are potentially large. Dynamic tnethod tables do noc Ist inherited methods, so they can be smaller. On the other hand, calling a virtual method is a fast index into a table, but calling a dynamic ‘method requires a search through one or mote tables, Virtual and Dynamic Methods 87In the VCL, dynamic methods ate used only for methods that are called in esponse to user interactions. Thus, the slower lookup for dynamic methods will not umpact overall performance Alen, the dynamic methods are uoually declared sn the root classes, such as Tontrol If you do not have a large class hierarchy, you will usually get smaller and faster code by using virual methods instead of dynamic methods, After all, dynamic ‘methods must store the method number in addition to the method address. Unless yyou have enough derived classes that do not override the dynamic method, the dynamic methev!rahle will end up requinng more memory than the virtual method table. Initialization and Finalization When Delph constructs an object, it automatically mitilizes sinngs, dynamic arrays, interfaces, and Variants, When the object 1s destroyed, Delphi must decre- ment the reference counts for strings, interfaces, dynamic arays, and free Variants and wide stings Ta keep track of thie information, Delphi uses initial: tation records as part of a class's RTT. In fact, every record and array that seyuires finalization has an associated initialization record, but the compiler hides these records. The only ones you have access to are thse assacrated with an object's fields. A YMT pomts to an :ntializaion table. The table contains a list of initialization records Recavse arrays and records can be nested, cach initialization sevund contains a pomter to another mitialization table, which can contain initialization ‘econds, and so on. An mitialzation table uses a ‘TIypeKind field to keep track of ‘Whether its initializing @ sting. 2 record, an array, ete An initialization table begins with the type kind (1 byte), followed hy the ype ‘name as a short string, a $-byte size of the data being initialized, a 4byte count for ‘sitslization records, and then an array of zero or sive uitialization records, An initialization record 1s just 2 pointer 10 a nested snitialization table, followed by a “aby olfset for the field that must be initialized, Example 3-7 shows the logical layout of the initialization table ancl record, but the declarations depict the logical layout without being true Pascal code, Example 3-7: The Layout ofthe Initialization Table and Record tape (tntctattzacion/tinalazaticn record} ‘MinitRecord = packed record initrable: “Pinittable: Offset: Longhord, 1/ Offset of field in abject (Anitéalization/finalization table ) ‘Tmnlttable = packed recora (intnmsize 1) // Engure that Typekind takes wp 1 byte. ‘Typetind: Typekind ‘ypetime: packed Shortstring: batasize: tongiord;Example 3-7: The Layout of the Initialization Table and Record (continued) count: tengtora: // TE Typakindstideray, Count 49 the azray size, but Inithacorde 1/ Was only one elenent; if the type kind is tkRecord, Count is the 1/ vosber of record nenbers, and InitRecords{) has a 11 eecoed for each nenber. Bor sll other types, Ceumt-0 InitRocords: array{1..Comt] of TinitRecard ‘The master TmteKecora for the class has an empry type name and zero data size. The type kind is always tkRecord The Count 1s the number of fields that need initialization, and the InitRecords array contains a TInitRacord for each such mombcr. Each initialization record points to an. initialization table that contains the type kind and type name for the associated member. This organiza tion seems a lite strange, but you can soon grow accustomed to it “Most types do not need intualization or linalization, but the I lowing types do: umazay DataSize is the size of each array element, and the Count is the number of elements in the array Every array clement is the same, so the InitRecorde array contains one TinitRecora thet represents all the array elements. The Offset in the TInitRecord has no meaningful value. Upyanstey DataSize and Count are not meaningful. Delphi decreases the refer- fence count of the array and frees the array's memory if the reference ‘count becomes zero, tkinterface DataSize and Count are not meaningful. Delphi calls the Release method, which frees the mieifice ubyect if die reference coun becomes ekistring DataSize and Count are not mesningtul. Delphi decreases the reter- ence count of the string and frees the string's memory if the reference count becomes 2et0, ‘tkRecord Datasize is the size of the record, and the Count is the number of members that need initialization. The TnitRecords array contains a ‘TunstRecord for each member that needs initialization. tkvariant DataSize and Count are not meaningful. Delphi frees any memory asso- ciated with the Variant data erusering DataSize and Count are not meaningful. Delphi frees the sting. Thitialization and Finalization 89Automated Methods ‘The antomated section of a class declaration is now obsolete because i is ease 10 create a COM automation server with Delphi's type library editor, using interfaces "Nonetheless, the compiler currently supports automated declarations for back. ‘ward compatibility A future version of the compiler might drop cupport for automated declarations. The Oleauto unit tells you the details of the automated method table: The table stars with a 2-byte count, followed by a list of automation records. Fach record has a byte dispid (dispatch identifier), a pointer to a short string method name, “bytes of Hlags, a pointer to a list of parameters, and a code pointer. The param. ter list starts with a Lhyte seme type, followed by a I byte count of parameters, and ends with a list of L-byte parameter types. The parameter nantes ate not stored, Exatuple 58 shows the declarations for the automated method table. Example 3-8: The Layout of the Automated Metbod Table Macutorarans = 255; ope ‘Tintautctype = Byte; Outemarion ontry parameter et } PAutoParanbice = “MhitoPareeList; ‘mastotarandst — packed cert ‘Types: array{1..comt] of Iatautorvve: end; [ Rutanation take entry } PhutoBhtry = “Tautomtzy; ‘utomery = packed rewid DispID: Longtaty Flags: Longint; ( Lower byte containg fleas ) Parans: PhutoParentist; berana: Pointers ena) { Autemation table layout } vaucotaple = “TutoTable; ‘TautoTable = packed record Cone: Longines mnteieas array. comnt) of tautomntayy ena; 90 Chapter $= Runtime Type InformationInterfaces ‘Any class can implement any number of interfaces. ‘the compaler stores a table of interfaces as part of the class's RTTL. The VMT points to the table of interfaces, which starts with a 4dyte count, followed by a list of interface records. Bach inter- face record contains the GUID, a pointer to the interface’s VMT, the offset to the anterfice’s hidden field, and a posnter to a property that implements the interface ‘with the implements directive, I the offset is zero, the interface property (called Imploetter) must be non.ntl, and if the offset ss not 2270, InplGetter must be Ril. The interface property can be a reference to a field, a virtual method, of a static method, following the conventions of a property reader (which 1s described earlier in this chapter, under “Published Properties"). When an object is constructed, Delphi automatically checks all the interfaces, and for each interface 1 a nonzero TOLE Set, the fick! at that offset is set tw Ue waerface’s VEable (a pointer to its VMI). Delphi defines the types for the interface table, unlike the Other RTTT tables, inthe System unit. These types are shown in Example 3.9. Example 3-9: Type Declarations for te Interface Table Pintertaccintry ~ “Tintorfscotry ‘Minterfecemtry = record viable: Pointer; offset: Integer; Ieploetter: Integer: ea, PinterfoceTable = “TinterfaceTable; nenytount: Integers 1/ Declare tho type with the largest possible size, 1/ bot the true size of the array is BntryComt clenents. ‘Series: array[0..9999) of Tinterfacemery: ‘TobJect_amplements several methods for accessing the imerface ble. See Chapter 5 for the detals of the Getinterface, GetInterfacemtry, and GetInterfacerable methods. Exploring RTTI This chapter introduces you to a class's viral method table and runtime type information. To better understand how Delphi stores and uses RTT, you should explore dhe Gables on your ow, The code dat accuuipaies dus book on die OReilly web site includes the Vmtexe program. The VatInfo unit defines a collection of interfaces that exposes the structure of all the RTTI tables. The ‘Vmtinpl unit defines classee that implement thece interfaces, You can read the source code for the VmtZmp1 unit or just explore the Vm program. See the ‘VntForn unit to add types that you want to explore, of to change the type declarations, Explonng RTA 91You can also use the meTafo interfaces in your own programs when you nced access to the RIT tables. For example, you might write your own object persise tence linaty whiere you need access (0 a field class table to map class names t0 class references, ‘The interfaces are self-explanatory. Because they use Delphi's automatic reference ‘counting, you don't need to worry about memory management, either. To ereate an interface, call one of the following functions fmetion Gettitinfo(ClassRef: TClass): TatInfo; ewerlond: function Getimtznfo(dbiectRet: TObject): TntIngo; overload: function Gernypetnto(RypeIntos PIypcinge)+ Typetnts, Use the TVmtInfo interface and its related interfaces to examine and explore the sich world of Delphi's runtime type information, For example, take a look at the ‘Bont clas, shown in Example 3-10. ‘example 3-10: Declaration of the TFont Class ‘TRont = class Moraphicsdbject) private Foolor: Toler FPixelaferinch: integer; Rictifys Thangesioes fier, procedure GetData(var Fontata: TFantData) ; procedure setvata(censt FontData: TFontData); protected Drocedure Changed; override; ‘function Getttandle: HFent function GetHeight: Integer function GetPiveh: TFonteiech; function Gecstze: ineeger; function Getstyle: Trontstyles; function Getcharset: TPontcharae procedure SetColor (Value: Talor) Drocedure Setiandle Value: Hfont) ; [procedure Setioight (Valuer Integer) ‘procedure Settiae const Value: Fontan) ; puaceture SetPiccn value: ‘iyontPiten); Drocedure SetSize(Value: Integer) ; Procedure Sotstyle(Value: TFontstyles) ; Procedure Setcharset Value: "Pont Charset) public Gestructor Destroy; override; roveue hislgn(source: Teersistent); override; roperty Fontadapter: IChangelltifier read Mlotity write Miotity: Droperty Handle: Font read Getiiandle write Setiandle: Property PinelsPerinch: Intayer read FPixelabertnch write FPixelePerinch; rehtiched Droperty Charset: 1Fontcharset read Getcharset write Setcharset: veoenty Color: Tolor read HUolor Write SetColor 92 Chapter 3= Runtime Type tnformationExample 3-10: Declaration of the TFont Class (continued) property Height: Integer read Getileight write Setteight: Dropertyy Mane: Trontiane read Cottime write Setlane; ‘property Pitch: TontPitch read GetPitch write setPitch default fpDefaults property Size: Integer read GetSize write Setsize stared False) property Style: TPontstyles read Gatstyle write Setstyle; eat Notice that one fleld is of type ichangenotifier. The changed method Is declared as dynamic in the base class, TGraphicsObject. TFont has no published fields or methods, but has several published properties. Example 3-11 shows the YMT and sype information for the Font clace. You can eee that the dynamic method table has one entry for Changed. The Size property is not stored, but the other published properties are, The Vmitexe program can show you the same kind af information for almost any class or rype Example 5-11. Runstme Type Information ‘yes 40030878 Destroy: 40032820 resinstance: a00us908 Newcinatance: 4000394 Defaulttiandlers 400030K¢ Disoatch: 4000388 BeforeDestruction: 40003¢Bs Safecal ception: 40003Cx4 arent: <0030uR4 (TUraphlestbject) nstanceSize: 32 Clasetine: "ont" manic Mothod Table: 4003052 ‘Counts 1 40002084 (-2) ethod Table: 00000000 ‘typetnfo: 400308F4 nieteble: 40030200 ‘Teaiae: ‘ypeKind: tkRecore ataoffests 6 count: 2 al infemable: 40030844 ‘rwodlane: IChanasiot tier ‘Typekind: tkinterface Dataotfoots 28 autotable: 00000000 type Tontchareet = 0..255; // otuByte ‘type Tolor = 2147483648. .2147483687; // otStong Exploring RTT BExample 3-11. Runtime Type Information (continued) ‘ape Integer = 2147483648. 2147483647; // otstong {type Montane, // tkLotring ‘tape TontPitch = (fpOefault, ‘variable, fpeixed); // otuyte aye Tmuswyle = (285014, retalic, fsthaerline, feSteileost) Uupe tentstyles = set of TRontStyle; // otlByte type Tobject = class // anit ‘syaten! end; ‘type Tersistent = class (TUbject) // init ‘Classes! ‘pe ToaphicsObject = clase(TPersistent) // unit “Graphics* end, ‘type Mont = class Toraphicsdbject) // untt 'Graphics* ‘published Droperty Charset: Tontcharaet read (atatic methd 40032004) write (static method 4003200) nodefault stored ue; // index 0 reperty Color: Toler read (field 20) write (otaLle method 409323A:) odefault stored True; // index 1 Peopetty Height: mnteger read (static method 4003288C) write (static method 40032894) nedefault stored True; // index 2 ‘property Nene: TontHane read (static nethod 400328BC) write (static method 40032804) noefnit ntorad Troe; // index 3 property Pitch: TFonePitch read (static method 40022¢h4) write (static method 40032042) default 0 stored Trucs // Andex 4 property Size: Integer read (static method 4003230) weite (elaLle method 40032c%) nocerault stored False; // index $ property Style: Trenestyles read (static method 40032060) write (static method 40032078) nodefault stored True; // index 6 ea; ‘94 Chapier 3 Runtime Type InformationCHAPTER 4 Concurrent Programming ‘The future of programming is concurrent programming. Not 100 long ago, sequen- tial, command-line programming gave way to graphical, event-daven programming, and now singlethreadeel programming is yielding 1p mulithreaded! programming Whether you are writing a web server that must handle many clients simulta- neously of writing an end-user application such as a word processor, concurrent programming. is for you, Perhaps the word processor checks for spelling errors ‘while the user types. Maybe it can print a file in the background while che user continues to edit. Users expect more today from their applications, and only ‘concurrent programming can deliver the necessary power and flexibility Delphi Pascal includes features to support concurrent programming—not as much support as you find in languages such as Ada, but more than i most traditional programing languages, In addition (0 the hirguage Featutes, you cat use die Windows APL and its semaphores, threads, processes, pipes, shared memory, and so on. This chapter describes the features that are unique to Delphi Pascal and ‘explaine how to use Delphi effectively to write concurrent programe. If you want ‘more information about the Windows API and the deuils of how Windows handles threads, processes, semaphores, and so on, consult a book on Windows programming, such as Inside Windows NT. second edition, by David Solomon (Microsoft Press, 1998) Threads and Processes “This eection provides an overview of multithreaded programming in Windows. If you are already familiar with threads and processes in Windows, you can skip this section and continue with the next section, “The TThread Class A thread 1s @ flow of contol in a program. A program can have many threads, each with its own stack, its own copy of the processor's registers, and related information. On a multiprocessor system, each processor can un a separatethread. On a uniprocessor system, Windows creates the illusion that theeadts are ‘running concurrently, though only one thread at atime gets to run. ‘A process is a collection of threads all running in a single address space. Every process has at least one thread, called the main thread. Throads in the same process can share resources such as open files and can access any valid memory addess ai he process's address space, You can think of a process as an instance of an application (plus any DLLs that the application loads), ‘Threads in a process can communicate easily because they can share variables Critical sections protect threads from stepping on each others’ toes when they access shared variables. (Read the section "Synchronizing Threads" later in te chapter, for details about critical sections.) You can send a Windows message to a particular thread, in which case the receming thread must lave # message loop to handle the message. In most cases, ‘you will find it simpler to let the main thread handle all Windows messages, hut feel free to write your own message loop for any thread that needs it. Separate processes can communicate in a variety of ways, such as messages, ‘mutexes (short for munial exclusions), semaphores, events, memory-mapped files, sockets, pipes, DCOM, CORBA, and so on. Most likely, you will use a combina ‘io of methods. Separate processes do not share ordinary memory, and you ‘cannot cal a function or procedure from one process to annther, although several remote procedure call mechanisms exist, such as DCOM and CORBA. Read more about processes and how they communivate i the section “Processes” later sn this chapter. Delphi has builtan support for multithreaded programming —writing applications {and DLLs that work with multiple threads in a process, Whether you work with threads or processes. you have the full Winlows API at your dispocal. In a multithreaded application or library, you must be sure that the glohsal vanable TotlultiThread 1s Tre. Most applications do this automatically by calling ogintiroad or using the Tread class. f you wate « DLL that ugh be called from a mulithreaded application, though, you might need to set TsttaltiThread 10 Inve manually Scheduling and States Windows schedules threads according to their pnorities. Higher priority threads run before lower prionty threads. At the same parity, Windows schedules threads 0 that each thread gets a fair chance to min Windows can stop a running thread alled preempting the thread) to give another thread a chance to run. Windows defines several dlfferent states for threads, but they fall into one of three categories: Running ‘A thread 1s running when it is active on a processor. A system can have as ‘many running threads as it has processore—one thread per processor. A. thread remains in the running state until it blocks because it must wait for ouue uperauion (Such as the completion of /). Windows then preempts the thread to allow another thread to run, or the thread suspends itself ‘95. Chapter J Concurrent Programming
You might also like
Evo Eng Manual
PDF
No ratings yet
Evo Eng Manual
39 pages
5 Inch "Ultra Light" FSL Antenna: Maximum Am-Dxing Performance From A Minimal Package
PDF
No ratings yet
5 Inch "Ultra Light" FSL Antenna: Maximum Am-Dxing Performance From A Minimal Package
12 pages
Black & Decker Workmate Owners Manual 79-003 Type 2
PDF
0% (1)
Black & Decker Workmate Owners Manual 79-003 Type 2
6 pages
HW4
PDF
No ratings yet
HW4
4 pages
Programming Windows 6th Ed
PDF
No ratings yet
Programming Windows 6th Ed
1 page
Go Programming Language
PDF
100% (1)
Go Programming Language
21 pages
Beamer User Guide
PDF
No ratings yet
Beamer User Guide
130 pages
Qtile
PDF
No ratings yet
Qtile
110 pages
Alpine Linux
PDF
No ratings yet
Alpine Linux
5 pages
EarthCruiser Innovation
PDF
100% (1)
EarthCruiser Innovation
8 pages
MSDN Magazine
PDF
No ratings yet
MSDN Magazine
106 pages
Morse PDF
PDF
No ratings yet
Morse PDF
16 pages
Buckminster Fuller
PDF
No ratings yet
Buckminster Fuller
11 pages
Operating System For Raspberry PI 3 Using Rust
PDF
No ratings yet
Operating System For Raspberry PI 3 Using Rust
8 pages
Basic Tutorials - Batteries For Solar Energy Systems
PDF
No ratings yet
Basic Tutorials - Batteries For Solar Energy Systems
3 pages
CL Prog
PDF
100% (8)
CL Prog
482 pages
Merlin 128 Manual
PDF
100% (1)
Merlin 128 Manual
155 pages
PlantUML Language Reference Guide en PDF
PDF
No ratings yet
PlantUML Language Reference Guide en PDF
175 pages
Solar Sails
PDF
No ratings yet
Solar Sails
13 pages
GCC Cheat Sheet
PDF
No ratings yet
GCC Cheat Sheet
2 pages
Mysql Architecture
PDF
No ratings yet
Mysql Architecture
10 pages
Bluetooth
PDF
No ratings yet
Bluetooth
8 pages
A Simple DIY Spectrophotometer
PDF
100% (1)
A Simple DIY Spectrophotometer
30 pages
Advanced GUI Development Using QT: Paolo Quadrani Andrea Negri
PDF
No ratings yet
Advanced GUI Development Using QT: Paolo Quadrani Andrea Negri
40 pages
Qbasic Programs 1
PDF
No ratings yet
Qbasic Programs 1
16 pages
XDS - Modula 2.IDE - User.guide - en
PDF
No ratings yet
XDS - Modula 2.IDE - User.guide - en
61 pages
Engineer's Notebook
PDF
No ratings yet
Engineer's Notebook
128 pages
Baotian BT49QT 12 Tanco 50 User Manual
PDF
100% (1)
Baotian BT49QT 12 Tanco 50 User Manual
26 pages
DDD
PDF
No ratings yet
DDD
27 pages
LLVM Clang - Advancing Compiler Technology
PDF
No ratings yet
LLVM Clang - Advancing Compiler Technology
28 pages
Using Buildroot For Real Projects: Thomas Petazzoni Free Electrons Thomas - Petazzoni@free
PDF
No ratings yet
Using Buildroot For Real Projects: Thomas Petazzoni Free Electrons Thomas - Petazzoni@free
44 pages
ODROID Magazine 201702
PDF
No ratings yet
ODROID Magazine 201702
31 pages
MDN 0214DG PDF
PDF
No ratings yet
MDN 0214DG PDF
112 pages
DR Dobbs Journal Vol 01
PDF
No ratings yet
DR Dobbs Journal Vol 01
368 pages
The Exokernel Operating System Architecture: Dawson R. Engler
PDF
No ratings yet
The Exokernel Operating System Architecture: Dawson R. Engler
93 pages
A Personal Computer For Children of All Ages: Alan Kay
PDF
No ratings yet
A Personal Computer For Children of All Ages: Alan Kay
12 pages
REGENEDYNE MAGLEV WIND POWER GENERATION Paper
PDF
No ratings yet
REGENEDYNE MAGLEV WIND POWER GENERATION Paper
5 pages
Synthpop CD Inventory
PDF
No ratings yet
Synthpop CD Inventory
4 pages
C Programming Concepts
PDF
No ratings yet
C Programming Concepts
171 pages
Elgg
PDF
No ratings yet
Elgg
265 pages
Swing Human Powered Generator: For The DC House Project
PDF
No ratings yet
Swing Human Powered Generator: For The DC House Project
4 pages
GTK+ GUI Programming: Ori Idan Helicon Technologies
PDF
100% (1)
GTK+ GUI Programming: Ori Idan Helicon Technologies
19 pages
DR Dobbs Journal Vol 02 PDF
PDF
No ratings yet
DR Dobbs Journal Vol 02 PDF
484 pages
Anderson, Anita - Tracy, Martin - Mastering FORTH-Brady (1989)
PDF
No ratings yet
Anderson, Anita - Tracy, Martin - Mastering FORTH-Brady (1989)
260 pages
Learn Rebol
PDF
100% (1)
Learn Rebol
465 pages
Level 9.1: Instruction Manual
PDF
No ratings yet
Level 9.1: Instruction Manual
26 pages
Cedric
PDF
No ratings yet
Cedric
14 pages
KDE Frameworks Cookbook
PDF
No ratings yet
KDE Frameworks Cookbook
52 pages
Threaded Interpretive Languages
PDF
No ratings yet
Threaded Interpretive Languages
276 pages
DrRacket Guide
PDF
No ratings yet
DrRacket Guide
351 pages
DSP Java
PDF
No ratings yet
DSP Java
9 pages
(Ebook - Commodore Computers) Impossible Routines For The c64
PDF
No ratings yet
(Ebook - Commodore Computers) Impossible Routines For The c64
226 pages
DXL Reference Manual
PDF
No ratings yet
DXL Reference Manual
998 pages
Current and Electricity
PDF
No ratings yet
Current and Electricity
10 pages
Kapeel Satish Savant Mobile Email: Career Objective
PDF
No ratings yet
Kapeel Satish Savant Mobile Email: Career Objective
3 pages
Delphi Users Guide For Windows
PDF
No ratings yet
Delphi Users Guide For Windows
466 pages
A Beginner's Guide To Delphi
PDF
100% (2)
A Beginner's Guide To Delphi
33 pages
Delphi XE2 Foundations - Part 1 - Rolliston, Chris
PDF
100% (2)
Delphi XE2 Foundations - Part 1 - Rolliston, Chris
160 pages
Tips - Delphi Xe2 Foundations Part 1 2012 PDF
PDF
No ratings yet
Tips - Delphi Xe2 Foundations Part 1 2012 PDF
159 pages
Delphi XE2 Foundations - Part 2 - Rolliston, Chris PDF
PDF
No ratings yet
Delphi XE2 Foundations - Part 2 - Rolliston, Chris PDF
174 pages
Delphi - 20 Rules For OOP in Delphi
PDF
No ratings yet
Delphi - 20 Rules For OOP in Delphi
4 pages
Telit Easy Script Python 2.7 r5
PDF
No ratings yet
Telit Easy Script Python 2.7 r5
97 pages
Image Processing - Kailath Control Theory
PDF
No ratings yet
Image Processing - Kailath Control Theory
5 pages
YeniBelge 2
PDF
No ratings yet
YeniBelge 2
2 pages
EE430 Digital Signal Processing Project Description
PDF
No ratings yet
EE430 Digital Signal Processing Project Description
3 pages
Info Sheet 2011-2012
PDF
No ratings yet
Info Sheet 2011-2012
5 pages
Pre Rap or
PDF
No ratings yet
Pre Rap or
8 pages
Related titles
Click to expand Related Titles
Carousel Previous
Carousel Next
Evo Eng Manual
PDF
Evo Eng Manual
5 Inch "Ultra Light" FSL Antenna: Maximum Am-Dxing Performance From A Minimal Package
PDF
5 Inch "Ultra Light" FSL Antenna: Maximum Am-Dxing Performance From A Minimal Package
Black & Decker Workmate Owners Manual 79-003 Type 2
PDF
Black & Decker Workmate Owners Manual 79-003 Type 2
HW4
PDF
HW4
Programming Windows 6th Ed
PDF
Programming Windows 6th Ed
Go Programming Language
PDF
Go Programming Language
Beamer User Guide
PDF
Beamer User Guide
Qtile
PDF
Qtile
Alpine Linux
PDF
Alpine Linux
EarthCruiser Innovation
PDF
EarthCruiser Innovation
MSDN Magazine
PDF
MSDN Magazine
Morse PDF
PDF
Morse PDF
Buckminster Fuller
PDF
Buckminster Fuller
Operating System For Raspberry PI 3 Using Rust
PDF
Operating System For Raspberry PI 3 Using Rust
Basic Tutorials - Batteries For Solar Energy Systems
PDF
Basic Tutorials - Batteries For Solar Energy Systems
CL Prog
PDF
CL Prog
Merlin 128 Manual
PDF
Merlin 128 Manual
PlantUML Language Reference Guide en PDF
PDF
PlantUML Language Reference Guide en PDF
Solar Sails
PDF
Solar Sails
GCC Cheat Sheet
PDF
GCC Cheat Sheet
Mysql Architecture
PDF
Mysql Architecture
Bluetooth
PDF
Bluetooth
A Simple DIY Spectrophotometer
PDF
A Simple DIY Spectrophotometer
Advanced GUI Development Using QT: Paolo Quadrani Andrea Negri
PDF
Advanced GUI Development Using QT: Paolo Quadrani Andrea Negri
Qbasic Programs 1
PDF
Qbasic Programs 1
XDS - Modula 2.IDE - User.guide - en
PDF
XDS - Modula 2.IDE - User.guide - en
Engineer's Notebook
PDF
Engineer's Notebook
Baotian BT49QT 12 Tanco 50 User Manual
PDF
Baotian BT49QT 12 Tanco 50 User Manual
DDD
PDF
DDD
LLVM Clang - Advancing Compiler Technology
PDF
LLVM Clang - Advancing Compiler Technology
Using Buildroot For Real Projects: Thomas Petazzoni Free Electrons Thomas - Petazzoni@free
PDF
Using Buildroot For Real Projects: Thomas Petazzoni Free Electrons Thomas - Petazzoni@free
ODROID Magazine 201702
PDF
ODROID Magazine 201702
MDN 0214DG PDF
PDF
MDN 0214DG PDF
DR Dobbs Journal Vol 01
PDF
DR Dobbs Journal Vol 01
The Exokernel Operating System Architecture: Dawson R. Engler
PDF
The Exokernel Operating System Architecture: Dawson R. Engler
A Personal Computer For Children of All Ages: Alan Kay
PDF
A Personal Computer For Children of All Ages: Alan Kay
REGENEDYNE MAGLEV WIND POWER GENERATION Paper
PDF
REGENEDYNE MAGLEV WIND POWER GENERATION Paper
Synthpop CD Inventory
PDF
Synthpop CD Inventory
C Programming Concepts
PDF
C Programming Concepts
Elgg
PDF
Elgg
Swing Human Powered Generator: For The DC House Project
PDF
Swing Human Powered Generator: For The DC House Project
GTK+ GUI Programming: Ori Idan Helicon Technologies
PDF
GTK+ GUI Programming: Ori Idan Helicon Technologies
DR Dobbs Journal Vol 02 PDF
PDF
DR Dobbs Journal Vol 02 PDF
Anderson, Anita - Tracy, Martin - Mastering FORTH-Brady (1989)
PDF
Anderson, Anita - Tracy, Martin - Mastering FORTH-Brady (1989)
Learn Rebol
PDF
Learn Rebol
Level 9.1: Instruction Manual
PDF
Level 9.1: Instruction Manual
Cedric
PDF
Cedric
KDE Frameworks Cookbook
PDF
KDE Frameworks Cookbook
Threaded Interpretive Languages
PDF
Threaded Interpretive Languages
DrRacket Guide
PDF
DrRacket Guide
DSP Java
PDF
DSP Java
(Ebook - Commodore Computers) Impossible Routines For The c64
PDF
(Ebook - Commodore Computers) Impossible Routines For The c64
DXL Reference Manual
PDF
DXL Reference Manual
Current and Electricity
PDF
Current and Electricity
Kapeel Satish Savant Mobile Email: Career Objective
PDF
Kapeel Satish Savant Mobile Email: Career Objective
Delphi Users Guide For Windows
PDF
Delphi Users Guide For Windows
A Beginner's Guide To Delphi
PDF
A Beginner's Guide To Delphi
Delphi XE2 Foundations - Part 1 - Rolliston, Chris
PDF
Delphi XE2 Foundations - Part 1 - Rolliston, Chris
Tips - Delphi Xe2 Foundations Part 1 2012 PDF
PDF
Tips - Delphi Xe2 Foundations Part 1 2012 PDF
Delphi XE2 Foundations - Part 2 - Rolliston, Chris PDF
PDF
Delphi XE2 Foundations - Part 2 - Rolliston, Chris PDF
Delphi - 20 Rules For OOP in Delphi
PDF
Delphi - 20 Rules For OOP in Delphi
Telit Easy Script Python 2.7 r5
PDF
Telit Easy Script Python 2.7 r5
Image Processing - Kailath Control Theory
PDF
Image Processing - Kailath Control Theory
YeniBelge 2
PDF
YeniBelge 2
EE430 Digital Signal Processing Project Description
PDF
EE430 Digital Signal Processing Project Description
Info Sheet 2011-2012
PDF
Info Sheet 2011-2012
Pre Rap or
PDF
Pre Rap or