[Gary entsminger] turbo_pascal_for_windows_bible(book_fi.org)

  • 208 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
208
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
4
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Gary Entsminger TURBO PASCAL FOR WINDOWS B I B L EThe Most ComprehensiveTutorial and Reference for Experienced Programmers Examples, screen illustrations, and practical application samples Essential command reference section describes all features Exclusive coverage of ObjectWindows functions and the Windows API
  • 2. The TPW Command-line Compiler T u r b o Pascal for W i n d o w s c o m m a n d - l i n e o p t i o n s u s e this syntax: TPCW [options] <file name> [options] w h e r e [options] can b e o n e or m o r e o p t i o n s , separated by spaces. Y o u designate the status o f the c o m p i l e r o p t i o n by specifying a plus ( + ) o r a m i n u s (-) after the o p t i o n . • Place a + (or a space) after an o p t i o n to turn it O n . • Place a - after the o p t i o n to turn it Off. C o m p i l e r O p t i o n s Directive options Option Meaning /$A Align data /IB Boolean evaluation /$D Debug information /IF Force FAR calls /|G Generate 286 instructions /II Input/output checking /|L Local symbol information Option Meaning /IN 80x87 code (numeric coprocessor) /|R Range checking /IS Stack-overflow checking /IV String var checking /|W Windows stack frame /IX Extended syntax Mode options Option Meaning /B Build all /F Find error /L Link buffer Option Meaning /M Make /Q Quiet (no IDE equivalent) Conditional defines option Option Meaning /D Conditional defines Option Meaning Debug options Option Meaning /G MAP file Option Meaning /V Debug info in EXE option Directory options Option Meaning /E EXE and TPU directory /I Include directories /O Object Files directories Option Meaning /R Resource directories /T Turbo directory /U Unit directories C o m m a n d - l i n e O p t i o n s a n d T h e i r IDE Equivalents. Option IDE Equivalent /|A Options/Compiler/Align data /IB Options/Compiler/Boolean evaluation /ID Options/Compiler/Debug information /IF Options/Compiler/Force far calls /|G Options/Compiler/286 code /II Options/Compiler/I/O checking /|L Options/Compiler/Local symbols /|M Options/Compiler/Memory sizes /IN Options/Compiler/80x87 code /|R Options/Compiler/Range checking /IS Options/Compiler/Stack checking /IV Options/Compiler/String var checking options /|W Optioni/Compiler/Windows stack frames /IX Options/Compiler/Extended syntax Option IDE Equivalent /B Compile/Build /D Options/Compiler/Conditional defines /E Options/Directories/EXE and TPU directory /F Search/Find error /G Options/Linker/MAP file /I Options/Compiler/Include directories /L Options/Linker/Link buffer /M Compile/Make /O Options/Directories/Object directories /Q (none) • /R Options/Directories/Resource directories /T (none) /U Options/Directories/Unit directories /V Options/Linker/Debug info in EXE
  • 3. Turbo Pascal® for Windows™ Bible
  • 4. Turbo Pascal® for Windows Bible Gary Entsminger SAMS A Division of Macmillan Computer Publishing 11711 North College, Carmel, Indiana 46032 USA
  • 5. For Alison © 1992 by SAMS FIRST EDITION FIRST PRINTING—1991 All rights reserved. No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without written permission from the publisher. No patent liability is assumed with respect to the use of the information contained herein. Although every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omission. Neither is any liability assumed for damages resulting from the use of the information contained herein. For information, address SAMS, 11711 N. College Ave., Carmel, IN 46032. International Standard Book Number: 0-672-30212-8 Library of Congress Catalog No.: 91-66924
  • 6. Publisher Richard K. Swadley Publishing Manager Joseph Wikert Managing Editor Neweleen A. Trebnik Acquisitions Editor Gregory S. Croy Development Editor Paula Northam Grady Editors Kezia Endsley Becky Freeman Jodi Jensen Rebecca Whitney Technical Editor Jeffrey Hsu Production Claudia Bell Sandy Grieshop Denny Hager Audra Hershman Bob LaRoche Laurie Lee Juli Pavey Howard Peirce Tad Ringo Bruce Steed Mary Beth Wakefield Lisa Wilson Phil Worthington Christine Young Book Design Scott Cook Michele Laseau Cover Design Tim Amrhein Indexer Johnna VanHoose Composed in Garamond and MCP Digital by Macmillan Computer Publishing. Printed in the United States of America
  • 7. Overview Parti Working with TPW 1 Getting Started, 3 2 Elements of Application Development, 43 3 Objects for Windows, 77 4 Inheriting an Interface, 111 5 Putting Pictures in Windows, 149 6 Painting, Collecting, and Streaming, 185 Part II Advanced Topics 7 Many Windows: A Multi-Document Interface, 213 8 Resources and Control Objects, 241 9 Memory Matters, 279 10 Display Contexts and Drawing Tools, 301 11 From Program to Program Using D D E (Dynamic Data Exchange), 343 12 Sharing Libraries Using DLL (Dynamic Link Libraries), 369 13 Designing Windows Applications, 383 Part III References A ObjectWindows Objects, 405 B ObjectWindows Constants, 499 C ObjectWindows Procedures and Functions, 505 D ObjectWindows Records, 509 E The WinCrt Unit, 515 F A WinCrt Example, 525 G The Strings Unit, 539 H The Turbo Pascal for Windows System Unit, 553 I The Turbo Pascal for Windows WinDos Unit, 561 J Debugging Turbo Pascal for Windows Applications, 587 K Turbo Pascal for Windows Error Messages, 591 L W i n d o w Manager Interface Procedures and Functions, 635 M System Services Interface Procedures and Functions, 723 N G D I (Graphics Device Interface) Procedures and Functions, 793 O ObjectGraphics (A Whitewater G r o u p Graphics Toolkit), 861 P Notes for Managing a Project, 867 Q Glossary, 869 R References, Resources, and Notes, 881 S ASCII C o d e Character Set, 887 Index, 891
  • 8. Contents I WORKING WITH TPW 1 Getting Started, 3 Creating Windows Applications, 3 System Requirements and Installation, 4 T h e Turbo Pascal for Windows IDE, 4 Turbo Pascal for Windows I D E M e n u C o m m a n d s , 7 T h e Turbo Pascal for Windows Desktop Control M e n u , 7 Restore, 8 Move, 8 Size, 8 Minimize, 8 Maximize, 8 Close, 8 Switch T o , 9 The Edit Window Control M e n u , 9 Restore, 9 Move, 9 Size, 10 Minimize, 10 Maximize, 10 Close, 10 Next, 10 The File M e n u , 10 New, 11 O p e n , 11 Save, 12 Save As, 12 Save All, 12 Print, 12 Printer Setup, 13 Exit, 14 List of Closed Files, 14 vii
  • 9. Turbo Pascal for Windows Bible The Edit M e n u , 14 U n d o , 14 Redo, 15 Cut, 15 Copy, 15 Paste, 15 Clear, 16 The Search M e n u , 16 Find, 16 Replace, 16 Search Again, 16 G o to Line Number, 17 Search/Show Last Compile Error, 18 Search/Find Error, 18 The Run M e n u , 18 Run/Run, 18 Run/Debugger, 18 Run/Parameters, 19 The Compile M e n u , 19 Compile/Compile, 20 Compile/Make, 20 Compile/Build, 21 Compde/Primary File, 21 Compile/Clear Primary File, 21 Compile/Information, 21 Compile Information Box, 21 The Options M e n u , 22 Compiler, 22 Linker, 23 Directories, 23 Guidelines for Entering Directory Names, 24 Preferences, 25 Editor Options, 25 O p e n , 26 Save, 26 Save As, 27 Directories List Box, 28 The W i n d o w M e n u , 28 Tile, 28 Cascade, 28 Arrange Icons, 28 Close All, 29 viii
  • 10. Contents The H e l p M e n u (Alt-H), 29 Index (Shift-Fl), 29 Topic Search (Ctrl-Fl), 29 Help/Using Help, 30 Compiler Directives, 30 ObjectWindows, 30 Procedures and Functions, 30 Reserved Words, 30 Standard Units, 31 Turbo Pascal for Windows Language, 31 Windows API, 31 About Turbo Pascal for Windows, 31 Editor, 31 The Editor C o m m a n d s , 31 The Block C o m m a n d s , 32 C o p y Block, 32 C o p y Text, 32 Cut Text, 32 Delete Block, 32 Move Block, 32 Paste from Clipboard, 33 Read Block from Disk, 33 Write Block to Disk, 33 Editor-Command Tables, 33 Auto Indent, 36 Current Compiler Options, 36 Cursor through Tabs, 36 Find Place Marker, 37 O p e n File, 37 Optimal Fill, 37 Save File, 37 Set Place, 37 S h o w Last Compile Error, 37 Tab M o d e , 37 Unindent, 37 The TPW Command-line Compiler, 38 Onward, Forward, and Upward, 41 2 Elements of Application Development, 43 Units, 44 Data Types and Identifiers, 50 Ordinal Types, 52 Boolean Types, 52 ix
  • 11. Turbo Pascal for Windows Bible Char Type, 53 Enumerated Types, 54 Subrange Types, 54 Reals, 55 Strings, 55 Structured Types, 56 Arrays, 57 Records, 57 Object Types, 58 Sets, 59 Files, 59 Pointer Types, 60 PChar, 61 Procedural Types, 62 Turbo Pascal for Windows Reserved Words, 62 Statements, 63 assignment (:=), 64 begin..end, 64 case..of..else..end, 65 for..to/downto..do, 66 goto, 66 if..then..else, 67 inline(...), 68 procedure call, 69 repeat..until, 70 while..do, 70 with..do, 71 Debugging Turbo Pascal for Windows Applications, 72 Begin.., 75 3 Objects for Windows, 77 Overture, 77 About Turbo Pascal Windows, 78 Why Does the World Make So M u c h Sense?, 81 The Tao of Objects, 81 Inheritance, 84 Polymorphism, 86 Messages, 88 Static and Dynamic Binding, 90 Dynamic Style, 91 Extended Views, 92 X
  • 12. Contents About Microsoft Windows, 93 Windows Structure, 95 Why O O P and Windows, 101 About Object Windows, 102 Events, Messages, and Objects, 106 Windows Messages, 107 About WinCrt, 107 Movin' O n , 109 4 Inheriting an Interface, 111 The Basiclnterface, 113 Application and W i n d o w Objects, 114 The Main Window, 116 Details, 119 W i n d o w Messages, 122 Display Contexts, 126 Using Resources, 127 Pascal and C Strings, 129 A Few Rules, 130 Adding Dialogs, 130 Adding a File Dialog, 134 T w o Kinds of File Dialogs, 135 Constants, 136 Controls, 136 Adding List Boxes, 138 Message Boxes, 141 Closing an Application, 142 Wrapping U p the Basiclnterface, 143 5 Putting Pictures in Windows, 149 Menus, IDs, and Messages, 150 Tasks, 156 Other Windows, Other Tasks, 162 Model Tasks, 162 Modeling, 163 Chaos and Strange Attractors, 166 Mathematic Attraction, 170 Order in Chaos, 171 Grand Finale, 175 xi
  • 13. Turbo Pascal for Windows Bible 6 Painting, Collecting, and Streaming, 185 Polymorphic Collections, 187 Collecting Points, 189 Streams, 194 Putting Points in a Stream, 199 H o w Put Works, 200 Getting Points, 201 T h e S u m of Streams, 203 II ADVANCED TOPICS 7 Many Windows: A Multi-Document Interface, 213 A Basic M D I Interface, 214 Setting U p a Basic M D I Interface, 217 A Model M D I , 219 M D I Message Processing, 221 Editors, 222 A n M D I Editor, 226 M D I Wrap-up, 233 8 Resources and Control Objects, 241 Resources, 242 Resource Editors, 255 Dialog Windows, 256 Details, 260 Control Objects, 267 G r o u p Boxes, 270 Controls in Combination, 274 Bit Maps, 276 Wrap-up, 278 9 Memory Matters, 279 Memory Management, Windows Style, 280 Global and Local Memory, 283 Allocating Local Memory Blocks, 284 Global Memory Blocks, 290 A Few Advanced Memory Matters, 297 Direct Memory Access, 297 xii
  • 14. Contents Data Segments, 297 H e a p Errors, 298 C o d e Segments, 299 w m C o m p a c t i n g , 299 Wrap-up, 300 10 Display Contexts and Drawing Tools, 301 Handling a Display Context, 302 Mapping Modes, 315 Drawing Figures, 322 A Stranger Graphics Function D e m o , 327 Wrap-up, 340 11 From Program to Program Using DDE (Dynamic Data Exchange), 343 The Clipboard, 344 Pasting from the Clipboard, 348 Sharing Data Between Applications, 353 Atoms, and So O n , 354 Wrap-up, 368 12 Sharing libraries: Using DLL (Dynamic Link Libraries), 369 DLL Details, 370 Using DLLs, 371 13 Designing Windows Applications, 383 C o m m o n User Access, 384 Objects and Windows, 386 Designing for Change, 389 Object-Oriented Application Design, 392 A T a o of Windows, 393 Object Discovery, 394 Star Wars and Dances: The Sequel, 395 Begin Discovering Objects, 400 Wrap-up, 401 xiii
  • 15. Turbo Pascal for Windows Bible III REFERENCES A ObjectWindows Objects, 405 TApplication, 406 TBufStream, 411 TButton, 414 TCheckBox, 416 TCollection, 419 T C o m b o B o x , 427 TControl, 430 TDialog, 432 TDlgWindow, 436 TDosStream, 437 TEdit, 440 TEmsStream, 447 T G r o u p B o x , 450 TListBox, 452 TMDIClient, 457 TMDIWindow, 459 TObject, 464 TRadioButton, 465 TScrollBar, 466 TScroller, 471 TSortedCollection, 479 TStatic, 482 TStrCollection, 484 TStream, 486 TWindow, 491 B ObjectWindows Constants, 499 b f _ X X X X Constants, 499 c m X X X X Constants, 499 c o X X X X Constants, 501 e m X X X X Constants, 501 id_XXXX Constants, 502 n f X X X X Constants, 502 s t X X X X Constants, 502 t f _ X X X X Constants, 503 w b _ X X X X Constants, 503 w m _ X X X X Constants, 504 xiv
  • 16. Contents C ObjectWindows Procedures and Functions, 505 Abstract, 506 AllocMultiSel, 506 DisposeStr, 506 FreeMultiSel, 506 GetObjectPtr, 506 LongDiv, 507 LongMul, 507 LowMemory, 507 MemAlloc, 507 NewStr, 508 RegisterType, 508 RegisterWObjects, 508 RestoreMemory, 508 D ObjectWindows Records, 509 LongRec, 509 PtrRec, 510 TDialogAttr, 510 TMessage, 510 TMultiSelRec, 511 TScrollBarTransferRec, 511 TStreamRec, 511 TWindowAttr, 512 WordRec, 513 E The WinCrt Unit, 515 AssignCrt, 516 ClrEol, 517 ClrScr, 517 CursorTo, 518 DoneWinCrt, 518 G o t o X Y , 519 InitWinCrt, 519 KeyPressed, 520 ReadBuf, 520 ReadKey, 521 ScrollTo, 521 TrackCursor, 522 WhereX, ^22 X V
  • 17. Turbo Pascal for Windows Bible WhereY, 523 WriteBuf, 523 WriteChar, 524 F A WinCrt Example, 525 G The Strings Unit, 539 StrCat, 540 StrComp, 541 StrCopy, 542 StrDispose, 542 StrECopy, 543 StrEnd, 543 StrlComp, 544 StrLCat, 544 StrLComp, 545 StrLCopy, 546 StrLen, 546 StrLIComp, 547 StrLower, 547 StrMove, 548 StrNew, 548 StrPas, 549 StrPCopy, 550 StrPos, 550 StrRScan, 551 StrScan, 551 StrUpper, 552 H The Turbo Pascal for Windows System Unit, 553 I The Turbo Pascal for Windows WinDos Unit, 561 Constants, 561 Types, 563 A n Index of W i n D o s Procedures and Functions by Function (or Category), 566 J Debugging Turbo Pascal for Windows Applications, 587 xvi
  • 18. Contents K Turbo Pascal for Windows Error Messages, 591 Compiler Error Messages, 592 Run-time Error Messages, 626 L Window Manager Interface Procedures and Functions, 635 Caret Procedures and Functions, 635 Clipboard Procedures and Functions, 638 Cursor Procedures and Functions, 642 Dialog-Box Procedures and Functions, 645 Display and Movement Procedures and Functions, 658 Error Procedures and Functions, 664 Hardware Procedures and Functions, 665 H o o k Procedures and Functions, 669 Information Procedures and Functions, 671 Input Procedures and Functions, 676 M e n u Procedures and Functions, 681 Message Procedures and Functions, 691 Painting Procedures and Functions, 698 Property Procedures and Functions, 705 Scrolling Procedures and Functions, 706 System Procedures and Functions, 710 Window-Creation Procedures and Functions, 711 M System Services Interface Procedures and Functions, 723 Application-Execution Functions, 723 Atom-Management Procedures and Functions, 725 Communication Procedures and Functions, 729 File I/O Procedures and Functions, 735 Initialization-File Procedures and Functions, 740 Memory-Management Procedures and Functions, 743 Module-Management Procedures and Functions, 757 Operating-System Interrupt Procedures and Functions, 761 Resource-Management Procedures and Functions, 762 Segment Procedures and Functions, 768 S o u n d Procedures and Functions, 773 String-Manipulation Procedures and Functions, 778 Task Procedures and Functions, 786 Utility Macros and Functions, 788 xvii
  • 19. Turbo Pascal for Windows Bible N GDI (Graphics Device Interface) Procedures and Functions, 793 Bitmap Procedures and Functions, 794 Clipping Procedures and Functions, 800 Color Palette Procedures and Functions, 803 Coordinate-Translation Procedures and Functions, 807 Device-Context Procedures and Functions, 809 Device-Independent Bitmap Procedures and Functions, 812 Drawing-Attribute Procedures and Functions, 815 Drawing-Tool Procedures and Functions, 819 Environment Procedures and Functions, 826 Font Procedures and Functions, 827 Line-Drawing Procedures and Functions, 830 Mapping Procedures and Functions, 832 Metafile Procedures and Functions, 837 Printer-Control Procedures and Functions, 841 Rectangle Procedures and Functions, 842 Region Procedures and Functions, 844 Shape-Drawing Procedures and Functions, 851 Text-Drawing Procedures and Functions, 855 O ObjectGraphics (A Whitewater Group Graphics Toolkit), 861 P Notes for Managing a Project, 867 Q Glossary, 869 R References, Resources, and Notes, 881 Quotation Acknowledgments, 884 S ASCII Code Character Set, 887 Index, 891 xviii
  • 20. Introduction Look out of any window, any morning, any evening, any day. Robert Hunter How This Book Is Organized Welcome to Turbo Pascal for Windows Bible, a b o o k that will clear many of the mysteries of Windows programming in Turbo Pascal for Windows style. Windows programming is difficult, but Turbo Pascal for Windows makes the difficulty manageable. In fact, developing Windows applications with Turbo Pascal for Windows is m u c h more fun once you get the hang of it. This bible shows you h o w to get the hang of it. Turbo Pascal for Windows Bible consists of three sections: 1. Working With T P W A n introduction to object-oriented programming and the T u r b o Pascal for W i n d o w s object library, ObjectWindows, plus the language syntax and other details. This section is loaded with practical examples and is intended to bring y o u u p to W i n d o w s application development speed in a hurry. 2. Advanced topics This section discusses s o m e of the m o r e c o m p l e x aspects of Windows application development, such as m e m o r y management,
  • 21. Turbo Pascal for Windows Bible dynamic data exchange ( D D E ) , dynamic link libraries (DLL), design considerations, and so o n . This section is the o n e to read and study after y o u k n o w the basics of object-oriented program- ming, TPW-style. 3. Reference A detailed account of the O b j e c t W i n d o w object-oriented library, including objects, procedures, records, and constants. T h e refer- ence also is a complete description of the W i n d o w s API functions, a glossary, a reading list, and anything else that is important but does not fit in the first two sections. Reader, Who Are You? Although I cannot be sure, I assume that you already k n o w h o w to program using T u r b o Pascal (for D O S ) . T u r b o Pascal for W i n d o w s uses similar syntax and many of the same functions and procedures as Turbo Pascal (for D O S ) . Anything specific to Turbo Pascal for Windows is explained, and any differences between Turbo Pascal for Windows and Turbo Pascal (for D O S ) are discussed. If you have never programmed in Turbo Pascal for Windows, but have programmed in a procedural language such as C, C + + , or M o d u l a 2 , you probably will manage to learn Turbo Pascal for Windows programming. This b o o k makes it easier for you with a general introduction to Turbo Pascal syntax and programming. If you need more details about Turbo Pascal in general (not Windows-specific information), pick u p a g o o d Turbo Pascal (for D O S ) book, such as T o m Swan's Mastering Turbo Pascal 6 (Hayden Books) to use as a general Turbo Pascal reference. If you are already familiar with the Turbo Pascal for Windows integrated development environment (IDE) and editor, you can either glance over or skip the first chapter. Chapter 1 is primarily intended to familiarize you with the preliminar- ies: h o w to install Turbo Pascal for Windows, system requirements, h o w the IDE, compiler, and editor work, and so on. The "real" programming and object- oriented discussions start in Chapter 2. Conventions in This Book These conventions have been used throughout the b o o k to increase its readability: • All program listings; "snippets" of program code; keywords; procedure, function, and method names; types (such as base and d e r i v e d ) ; and objects ( s u c h a s B a s i c I n t e r f a c e , MainWindow, TWindow, T A p p l i c a t i o n , B a s i c A p p l i c a t i o n ) are in monospace type. X X
  • 22. Introduction • B o o k titles, along with terms included in the Glossary (on first occurrence in the text), appear in italics. • Units, program names, and library names (ObjectWindows) appear in regular type. Acknowledgments I'd like to thank a few folks w h o have supported, advised, offered suggestions, read the manuscript, provided software, or just plain been helpful to m e during the writing of Turbo Pascal for Windows Bible: Greg Croy and Paula Northam Grady at Macmillan C o m p u t e r Publishing; N a n Borenson at Borland International; Phil Davis at the Whitewater G r o u p ; Alison Brody; Susan Allen; and Billy Ban* at the Rocky Mountain Biological Laboratory. Trademarks SAMS has made every attempt to supply trademark information about company names, products, and services mentioned in this book. Trademarks indicated below were derived from various sources. SAMS cannot attest to the accuracy of this information. Apple and Macintosh are registered trademarks of Apple Computer, Inc. Borland, Borland C + + , Turbo Debugger, and Turbo Pascal are registered trademarks of Borland International, Inc. Intel is a registered trademark of Intel Corporation. Microsoft C, Microsoft Excel, and Microsoft Word are registered trademarks of Microsoft Corporation. Windows is a trademark of Microsoft Corporation. Smalltalk is a trademark of ParcPlace systems. Whitewater Resource Toolkit is a trademark of The Whitewater G r o u p . Zortech is a trademark of Zortech, Inc. XXI
  • 23. Turbo Pascal for Windows Bible About the Author Gary Entsminger is a writer, programmer, and consultant. H e was an associate editor for Micro Cornucopia, (the technical journal) for five years, and a columnist for Borland's Turbo Technix magazine. H e is the author of The Tao of Objects, a beginner's guide to object-oriented programming, and his articles have appeared in Dr. Dobb's Journal, Computer Language, AI Expert, Midnight Engineering, AI Week, and Neural Network News. Gary lives in the Elk Mountains of Colorado. Gary Entsminger c/o: Rocky Mountain Biological Laboratory B o x 519 Crested Butte, C O 81224 xxii
  • 24. PARTO N E WORKINGWITH TPW
  • 25. 1CHAPTER GETTING STARTED In earlier days, the video display was used solely to echo text that the user typed using the keyboard. In a graphical user interface, the video display itself becomes a source of user input. Charles Petzold Creating Windows Applications Y o u c a n create W i n d o w s applications using T u r b o Pascal for W i n d o w s in three different ways: 1. T h e easiest way is to use the WinCrt unit. This unit enables y o u to write "standard" T u r b o Pascal for W i n d o w s applications that use T u r b o Pascal (for D O S ) functions a n d procedures, such as Readln a n d Writeln in a scrollable w i n d o w . T h e WinCrt unit also lets y o u transfer your existing T u r b o Pascal c o d e to W i n d o w s with the least a m o u n t o f effort. I describe the WinCrt unit in m o r e detail in Chapter 2, "Ele- ments o f Application Development," a n d in the reference section. 2. Y o u also can write W i n d o w s applications in the m o r e or less "tradi- tional" way, by creating your o w n w i n d o w s a n d w i n d o w s classes, a n d setting u p your o w n message l o o p . This is the w a y "C'ers" usually d o it, a n d I briefly describe this m e t h o d in an example in Chapter 2. 3. T h e best way to write full-featured, extendable W i n d o w s applications is to use the ObjectWindows application framework (or object library).
  • 26. 4 Parti—Working with T P W ObjectWindows uses object-oriented techniques to encapsulate c o m p l e x W i n d o w s behavior a n d make connections between W i n d o w s and your application. If y o u use ObjectWindows, W i n d o w s applica- tions are both easier to write a n d m o r e efficient. T h r o u g h o u t this book, I use a n d describe in detail h o w to use ObjectWindows. System Requirements and Installation T o r u n T u r b o Pascal for W i n d o w s , y o u n e e d Microsoft W i n d o w s , a P C with at least 2 M (megabytes) of RAM, a n d an E G A , V G A , or Hercules video adapter. Y o u also have to r u n W i n d o w s in Standard or 386 E n h a n c e d m o d e because T u r b o Pascal for W i n d o w s does not r u n in Real m o d e . In addition, if y o u plan to d e b u g in S V G A (Super V i d e o Graphics Adapter) m o d e , y o u must use dual monitors. T o install T u r b o Pascal for W i n d o w s , use the Install program o n the T u r b o Pascal for W i n d o w s distribution disks. T h e T u r b o Pascal for W i n d o w s system a n d example files o n the distribution disks are archived, so Install de-archives t h e m for y o u , puts them in convenient subdirectories, a n d automatically creates configuration files for both the command-line compiler a n d the inte- grated development environment (IDE). T o r u n the installation program from drive A, enter: C: Win A:Install or, if W i n d o w s is active, select the Program Manager's File/Run c o m m a n d and enter: A: Install Note: If y o u are a hands-on kind o f person, o r have another motive, y o u can use U n p a k . e x e to u n p a c k the archived files manually. After y o u have c o m p l e t e d the installation, a d d the T u r b o Pascal for W i n d o w s directories (for example, C: TPW; C: TPWUTILS) in the D O S path y o u specify in A U T O E X E C . B A T . If y o u d o not k n o w h o w to edit y o u r A U T O E X E C . B A T file, refer to your D O S manuals. The Turbo Pascal for Windows IDE Turbo Pascal for Windows is a complete development environment for Micro- soft W i n d o w s . It consists o f an editor, compiler, linker, a n d debugger in o n e package. Y o u c a n edit many source-code files (as a project), compile them, a n d link t h e m into an executable application without leaving the T u r b o Pascal for W i n d o w s environment. Figure 1.1 shows the T u r b o Pascal for W i n d o w s start- u p screen.
  • 27. 1—Getting Started 5 Most of your visual activity (what y o u see) occurs in a T u r b o Pascal for W i n d o w s Edit w i n d o w . T u r b o Pascal for W i n d o w s lets y o u have as many as 32 w i n d o w s o p e n at a time, provided there is e n o u g h memory. O n l y o n e w i n d o w can be active at a time. T h e active w i n d o w is the o n e in which y o u are working (editing, compiling, and so o n ) . Figure 1.1. The Turbo Pascal for Windows start-up screen. A n Edit w i n d o w consists of • A title bar • T h e W i n d o w C o n t r o l m e n u b o x • Scroll bars • Minimize and Maximize buttons Refer to figure 1.2 for a sample Edit w i n d o w . In addition to Edit w i n d o w s , T u r b o Pascal for W i n d o w s displays various dialog w i n d o w s in response to user m e n u selections, errors, and so o n . A Replace Text dialog box, for example, appears w h e n y o u select S e a r c h / R e p l a c e T e x t from the Main m e n u , as s h o w n in figure 1.3. Dialogs (which y o u will learn m u c h m o r e about in this book) can consist of input boxes, c o m m a n d buttons, and so o n . Typically, y o u check boxes, in- put text, and specify options; then y o u click a c o m m a n d button to close the dialog box.
  • 28. 6 Part I—Working with TPW Figure 1.2. An Edit window. Figure 1.3- A Replace Text dialog box.
  • 29. 1—Getting Started 7 Turbo Pascal for Windows IDE Menu Commands T h e T u r b o Pascal for W i n d o w s I D E M e n u options are c o m p l e x and powerful. For your convenience, the m e n u s are separated into • D e s k t o p control • Edit w i n d o w control • File • Edit • Search • R u n • C o m p i l e • O p t i o n s • W i n d o w • H e l p m e n u s The Turbo Pascal for Windows Desktop Control Menu T h e T u r b o Pascal for W i n d o w s Control M e n u b o x is o n the far left side of the title bar. Click the control m e n u b o x o n c e or press Alt-Spacebar to display the m e n u . T h e c o m m a n d s g r o u p e d in this m e n u manage the T u r b o Pascal for W i n d o w s desktop. Each Edit w i n d o w and dialog b o x also has a (similar) Control m e n u . T h e Desktop Control m e n u c o m m a n d s are • Restore • M o v e • Size • Minimize • Maximize • Close • Switch T o
  • 30. 8 Parti—Working with TPW Restore W h e n y o u select the Restore c o m m a n d from the Desktop Control m e n u , the T u r b o Pascal for W i n d o w s desktop w i n d o w returns to its previous size. Note: Y o u can use this c o m m a n d only if the T u r b o Pascal for W i n d o w s desktop w i n d o w is maximized or minimized. Move T h e M o v e c o m m a n d moves the desktop w i n d o w . Use the arrow keys to m o v e the w i n d o w where y o u want it and then press Enter. Y o u also can m o v e the w i n d o w by dragging its title bar. T h e title bar is the top horizontal bar of a w i n d o w ; it contains the n a m e of the file that is in the w i n d o w . Note: Y o u cannot use this c o m m a n d w h e n the desktop is maximized. Size Y o u can alter the size of the desktop w i n d o w with the Size c o m m a n d . Use the cursor arrow keys to m o v e the w i n d o w borders. T h e n press Enter w h e n y o u are satisfied with the window's size. Note: Size is an available option only w h e n the T u r b o Pascal for W i n d o w s desktop is not maximized. Minimize By selecting the Minimize c o m m a n d , y o u can turn the T u r b o Pascal for W i n d o w s desktop into the T P W icon. (An icon represents a w i n d o w in its minimized state. Applications, such as TPW, can have their o w n u n i q u e icons.) Note: Y o u can select this c o m m a n d only if the desktop w i n d o w hasn't b e e n minimized already. Maximize If y o u select the Maximize c o m m a n d , the desktop w i n d o w fills the entire screen. Note: Y o u can select this c o m m a n d only if the T u r b o Pascal for W i n d o w s desktop w i n d o w has not b e e n maximized already. Close T h e Close c o m m a n d closes the desktop and then unloads T u r b o Pascal for W i n d o w s from memory. T h e c o m m a n d is activated in two different ways, d e p e n d i n g o n the current m o d e :
  • 31. 1—Getting Started 9 • In C U A ( c o m m a n d user access) m o d e , y o u press Alt-F4 to close the desktop. • In Alternate m o d e , y o u press Alt-X to close the desktop. Y o u also can click the close b o x in the upper-left corner to close the w i n d o w . If y o u have modified an Edit w i n d o w but have not saved the file, a dialog b o x appears so that y o u can verify whether y o u want to save the file before closing. Switch To T h e Switch T o c o m m a n d displays the Task List dialog b o x that y o u can use to switch from o n e application to another and to rearrange application w i n d o w s . The Edit Window Control Menu Each Edit w i n d o w has a Control m e n u w h e n the w i n d o w is active. T h e c o m m a n d s o n this m e n u are similar to those of the T u r b o Pascal for W i n d o w s Control m e n u . These c o m m a n d s are available o n the Edit W i n d o w Control m e n u : • Restore • M o v e • Size • Minimize • Maximize • Close • Next Restore T h e Restore c o m m a n d returns the Edit w i n d o w to its default size. If y o u have minimized or maximized the Edit w i n d o w , use Restore to return it to its previous (default) size. If y o u have not minimized or maximized the w i n d o w , the Restore c o m m a n d is disabled. Move Use the M o v e c o m m a n d to m o v e your Edit w i n d o w with keyboard keys or by dragging its title bar.
  • 32. 10 Parti—Working with TPW After y o u select Move, use the arrow keys to m o v e the w i n d o w . W h e n you're satisfied with the window's n e w position, press Enter. Note: Y o u can use M o v e only w h e n your Edit w i n d o w isn't maximized. Size Y o u can change the size of your Edit w i n d o w using the keyboard; or, if a w i n d o w has a Resize corner, y o u can drag the corner to resize the w i n d o w . After selecting Size, use the arrow keys to m o v e the w i n d o w borders. W h e n y o u are satisfied, press Enter. Note: Y o u can use Size only w h e n your Edit w i n d o w isn't maximized or minimized. Minimize Select the Minimize c o m m a n d to shrink your Edit w i n d o w to an icon o n the T u r b o Pascal for W i n d o w s desktop. Note: Y o u can select this c o m m a n d only if the w i n d o w has not b e e n minimized already. Maximize T h e Maximize c o m m a n d enlarges the Edit w i n d o w so that it fills the T u r b o Pascal for W i n d o w s desktop. Note: Y o u can select this c o m m a n d only w h e n the w i n d o w has not b e e n maximized already. Close T h e Close c o m m a n d closes the Edit w i n d o w . Y o u also can double-click the Close b o x in the upper-left corner to close a w i n d o w . If y o u have modified text in the w i n d o w and have not saved the text, a dialog b o x appears that gives y o u the option of saving the file before y o u close. Next T h e Next c o m m a n d activates the next o p e n w i n d o w or icon. The File Menu T h e File m e n u offers y o u choices for creating n e w files, o p e n i n g and loading existing files, saving files, printing files, and exiting T u r b o Pascal for W i n d o w s . T h e File m e n u c o m m a n d s include the following:
  • 33. 1—Getting Started 11 • N e w • O p e n • Save • Save As • Save All • Print • Printer Setup • Exit • List of closed files New N e w o p e n s a n e w Edit w i n d o w with the default n a m e N O N A M E x x . P A S (the x x stands for a n u m b e r from 00 to 99), and makes the n e w Edit w i n d o w active. A N O N A M E file is used as a temporary edit buffer. If y o u try to save a N O N A M E file, Turbo Pascal for Windows prompts y o u to n a m e it before it can be saved. Open T h e O p e n c o m m a n d displays the File O p e n dialog box. In this dialog box, y o u select the file y o u want to o p e n , as illustrated in figure 1.4. Figure 1.4. The File Open dialog box.
  • 34. 12 Part I—Working with TPW Note: In the T u r b o Pascal for W i n d o w s D e s k t o p , y o u can work in either of two edit m o d e s . Y o u specify your choice of m o d e s using the Options/Preferences m e n u . T h e two m o d e s are C U A , the standard W i n d o w s m o d e , and Alternate, which is c o m m a n d - compatible with other Borland editors. In Alternate m o d e , press F3 to o p e n a file. Save T h e Save c o m m a n d saves to a disk the file in the active Edit w i n d o w . If the file has a default n a m e (such as N O N A M E 0 0 . P A S ) , T u r b o Pascal for W i n d o w s o p e n s the File Save As dialog b o x so that y o u can rename the file and save it in a different directory or o n a different drive. If y o u use an existing file n a m e to n a m e the file, T u r b o Pascal for W i n d o w s asks whether y o u want to overwrite the existing file. If y o u want to save all modified files, not just the file in the active Edit w i n d o w , select File/Save All. In Alternate m o d e , press F2 to save a file. Save As Save As o p e n s the File Save As dialog box, which lets y o u save the file in the active Edit w i n d o w u n d e r a different n a m e , in a different directory, or o n a different drive (see figure 1.5). All w i n d o w s that contain this file are u p d a t e d with the n e w n a m e . If y o u select a file n a m e that already exists, T u r b o Pascal for W i n d o w s first asks whether y o u want to overwrite the existing file. Save All This c o m m a n d saves all the files in o p e n Edit w i n d o w s . Print T h e Print c o m m a n d prints the contents of the active Edit w i n d o w . T u r b o Pascal for W i n d o w s expands the Tabs (that is, it replaces any Tab characters with the appropriate n u m b e r of spaces) and then prints the file. Note: T h e Print c o m m a n d is disabled if the active w i n d o w cannot be printed; for example, if n o printer is connected to your system.
  • 35. 1—Getting Started 13 Figure 1.5. The File Save As dialog box. Printer Setup T h e Printer Setup c o m m a n d displays a Select Printer dialog b o x , which lets y o u select a printer type for T u r b o Pascal for W i n d o w s (see figure 1.6). Figure 1.6. The Select Printer dialog box.
  • 36. 14 Parti—Working with TPW Note: If y o u d o not want to alter the way your printer is normally configured, y o u d o not have to use Printer Setup. Exit T h e Exit c o m m a n d exits T u r b o Pascal for W i n d o w s and removes it from memory. If y o u have modified a source file without saving it, T u r b o Pascal for W i n d o w s prompts y o u to save the file before exiting. T h e Exit c o m m a n d is mode-dependent: • In C U A m o d e , press Alt-F4 to exit. • In Alternate m o d e , press Alt-X to exit. list of Closed Files This c o m m a n d lists all the files that have b e e n closed since start-up. Select any closed file from the m e n u to quickly r e o p e n it. The Edit Menu T h e Edit m e n u includes c o m m a n d s to u n d o , redo, cut, copy, paste, and clear text in Edit w i n d o w s . Also, y o u can o p e n a Clipboard w i n d o w to view or edit its contents. T h e Edit m e n u c o m m a n d s are • U n d o • R e d o • C u t • C o p y • Paste • Clear Undo T h e U n d o c o m m a n d restores the most recent edit or cursor movement. U n d o inserts any characters y o u deleted, deletes any characters y o u inserted, replaces any characters y o u overwrote, and moves your cursor back to the previous position.
  • 37. 1—Getting Started 15 If y o u u n d o a block operation, the file reappears as it did before y o u executed the block operation. If y o u press U n d o m o r e than o n c e , it continues to u n d o changes as long as it can. However, the U n d o c o m m a n d does not change an option setting that affects m o r e than o n e w i n d o w . T h e G r o u p - U n d o option in the Options/Preferences dialog b o x specifies U n d o and R e d o behavior. Redo R e d o reverses the effect of the most recent U n d o c o m m a n d . R e d o is effective only immediately after an U n d o or another Redo. A series of R e d o c o m m a n d s reverses the effects of a series of U n d o c o m m a n d s . Cut T h e C u t c o m m a n d removes the selected text from a d o c u m e n t in the Edit w i n d o w and puts the text in the Clipboard. Y o u can then use Edit/Paste to copy the text to another d o c u m e n t or to a different place in the current d o c u m e n t . T h e text remains selected in the Clipboard until y o u replace it with other text, so y o u can paste it many times, in as many files as y o u want. Copy T h e C o p y c o m m a n d does not remove the selected text; it leaves the text intact and places an exact copy of it in the Clipboard. T o paste the copied text into another d o c u m e n t , select Edit/Paste. Y o u also can copy text from a H e l p w i n d o w : • Using the keyboard, press Shift and an arrow key to select the text y o u want to copy. • Use the m o u s e to click and drag the text y o u want to copy. Paste T h e Paste c o m m a n d inserts the selected text from the Clipboard into the active w i n d o w at the current cursor position.
  • 38. 16 Parti—Working with TPW Clear T h e Clear c o m m a n d removes t h e selected text from t h e d o c u m e n t in t h e active w i n d o w , but does not m o v e it to t h e Clipboard. T h u s , y o u cannot paste "cleared" text in a d o c u m e n t as y o u can w h e n y o u use C u t or C o p y . Note: A l t h o u g h y o u cannot paste t h e cleared text, y o u can u n d o t h e Clear c o m m a n d with U n d o . Clear is handy for deleting text without overwriting t h e current text in the Clipboard. The Search Menu T h e Search m e n u includes t h e c o m m a n d s to search for text and error locations in your files. T h e Search m e n u c o m m a n d s are • Find • Replace • Search Again • G o to Line N u m b e r • S h o w Last C o m p i l e Error • Find Error Find T h e Find c o m m a n d displays t h e Find Text dialog box, w h i c h lets y o u type in t h e text y o u want to search for. Several options in this dialog b o x let y o u specify t h e details of t h e search (see figure 1.7). Replace T h e Replace c o m m a n d displays t h e Replace Text dialog box, w h i c h lets y o u type in t h e text y o u want to search for and t h e text y o u want to replace it with (see figure 1.8). Search Again T h e Search Again c o m m a n d repeats t h e previous Find or Replace c o m m a n d . T h e previous settings y o u m a d e in t h e Find Text or Replace Text dialog b o x are in effect w h e n y o u choose Search Again. In C U A m o d e , press F3 to search again.
  • 39. 1—Getting Started 17 Figure 1.7. The Find Text dialog box. Figure 1.8. The Replace Text dialog box. Go to line Number T h e G o to Line N u m b e r c o m m a n d displays the G o to Line N u m b e r dialog box, which prompts y o u for the line n u m b e r y o u want to find.
  • 40. 18 Parti—Working with TPW T u r b o Pascal for W i n d o w s displays the current line n u m b e r and c o l u m n n u m b e r in the lower-left corner of every Edit w i n d o w . Search/Show Last Compile Error T h e Search/Show Last C o m p i l e Error c o m m a n d locates the previous compiler error. T h e cursor moves to the line that caused the error. If the error is not in the active w i n d o w , T u r b o Pascal for W i n d o w s makes active the w i n d o w with the previous compiler error, o p e n i n g a closed file if necessary. T h e error n u m b e r and message then appear o n the status bar. Search/Find Error T h e Search/Find Error c o m m a n d brings u p the Find Error dialog box, which lets y o u specify the address of the most recent run-time error. The Run Menu T h e R u n m e n u includes the c o m m a n d s for running your application, starting T u r b o D e b u g g e r for W i n d o w s , and specifying command-line parameters. It includes the following c o m m a n d s : • R u n • D e b u g g e r • Parameters If y o u want to use the debugger o n a file, check the Options/Linker/Debug Info in E X E check b o x before y o u compile and link your application. T h e D e b u g Info in E X E option puts the necessary information in your executable file. Run/Run T h e Run/Run c o m m a n d runs the application, using any parameters y o u pass to it through the Run/Parameters c o m m a n d . If your source c o d e has b e e n modified since the previous compilation, the compiler automatically "does a m a k e " and links your application. Run/Debugger T h e Run/Debugger c o m m a n d starts T u r b o D e b u g g e r for W i n d o w s , and allows y o u to d e b u g the application.
  • 41. 1—Getting Started 19 Turbo Pascal for Windows tells Turbo D e b u g g e r for Windows which application to debug. C h e c k the Options/Linker/Debug Info in the E X E check b o x before y o u compile and link your application if y o u want to use Turbo D e b u g g e r to de- b u g it. T h e Options/Linker/Debug Info in E X E check b o x puts the necessary d e b u g information in the executable file. T o get the most from Turbo Debugger's symbolic debugging capabilities, y o u also should check the Options/Compiler/Debug Information b o x and the Options/Compiler/Local Symbols b o x before compiling your application. Run/Parameters T h e Run/Parameters c o m m a n d passes parameters to your application program w h e n y o u run it as though y o u were running the application from the Program Manager's File/Run m e n u . When y o u select this c o m m a n d , the Parameters dialog b o x appears. Y o u r job is to specify the command-line arguments (see figure 1.9). Figure 1.9. The Parameters dialog box. The Compile Menu Y o u use the c o m m a n d s o n the C o m p i l e m e n u to compile, make, or build your application program.
  • 42. 20 Parti—Working with TPW T o u s e the Compile c o m m a n d , y o u must have a file o p e n in an active window. T o use Make a n d Build, y o u must have a primary file defined. Select from these c o m m a n d s : • C o m p i l e • Make • Build • Primary File • Clear Primary File • Information Compile/Compile T h e Compile/Compile c o m m a n d compiles the file in the active Edit window. A C o m p i l e Status information b o x displays the compilation progress a n d results. If a n error occurred, the status bar displays the error line a n d highlights the error. Click your m o u s e or press a key to clear the message so that y o u c a n correct the error. Compile/Make T h e Compile/Make c o m m a n d creates a . E X E file according to these rules: • If a primary file has b e e n n a m e d in the Primary File dialog b o x , that file is compiled. Otherwise, the file in the active Edit w i n d o w is compiled. Turbo Pascal for Windows checks all files affecting the compiled file's performance to verify that they exist a n d that they are current. • If the source file for a unit has b e e n modified since the . T P U (object code) file was created, the modified unit is recompiled. • If the interface for a unit has changed, any unit that d e p e n d s o n it is recompiled. • If a unit links in a . O B J file (external routines), a n d the . O B J file is newer than the unit's . T P U file, the unit is recompiled. • If a unit contains an Include file a n d the Include file is newer than that unit's . T P U file, the unit is recompiled. • If the source to a unit (.TPU file) cannot b e located, the unit is not compiled. This option is identical to Compile/Build, except it is conditional. Build rebuilds all files, whether or not they are current.
  • 43. 1—Getting Started 21 Compile/Build T h e Compile/Build c o m m a n d rebuilds all the c o m p o n e n t s of your application, whether or not they are current. This option is identical to Compile/Make, except it is unconditional. M a k e rebuilds only those files that are not current. T h e Compile/Build c o m m a n d recompiles all the files included in the primary file. If y o u abort a Compile/Build c o m m a n d by pressing Ctrl-Break or receive errors that terminate the build, y o u can restart the build where it was termi- nated by selecting Compile/Make. Compfle/Primary File T h e Compile/Primary File c o m m a n d displays the Primary File dialog box, which lets y o u specify which .PAS file will be compiled w h e n y o u choose Compile/ Make or Compile/Build. Use Compile/Primary File w h e n y o u are working o n an application that uses several unit (.TPU) or Include files. Regardless of the file y o u are editing, Compile/Make and Compile/Build always operate o n your primary file. If y o u specify another file as a primary file, but want to compile only the file in the active Edit window, choose C o m p i l e . Compile/Clear Primary File T h e Compile/Clear Primary File c o m m a n d removes the n a m e of the primary file y o u specified with the Compile/Primary File c o m m a n d . If a primary file has not b e e n specified, however, the c o m m a n d is disabled. Compile/Information T h e Compile/Information c o m m a n d displays the C o m p i l e Information box, the n a m e of your primary file (if y o u are using o n e ) , a n d the n a m e of the previous file compiled. Compile Information Box T h e C o m p i l e Information b o x lists: • T h e n a m e of the primary file (if y o u are using one) • T h e n a m e of the previous file c o m p i l e d • T h e source compiled • C o d e size • Data size
  • 44. 22 Parti—Working with TPW • Stack size • Local heap size The Options Menu T h e Options m e n u contains c o m m a n d s for viewing and changing various default settings in Turbo Pascal for Windows. Most of the c o m m a n d s in this m e n u initiate a dialog b o x . T h e c o m m a n d s are • Compiler • Linker • Directories • Preferences • O p e n • Save • Save As Compiler T h e Options/Compiler c o m m a n d displays the Compiler O p t i o n s dialog b o x , which lets y o u select the options that determine howyour c o d e is compiled (see figure 1.10). Figure 1.10. The Compiler Options dialog box.
  • 45. 1—Getting Started 23 Linker T h e Options/Linker c o m m a n d displays the Linker O p t i o n s dialog box, which lets y o u select the options that determine h o w your application files are linked, as s h o w n in figure 1.11. Figure 1.11. The Linker Options dialog box. Map File options T h e M a p File options (Off, Segments, Publics, and Detailed) determine the type of m a p file produced. Link Buffer File options T h e Link Buffer File options (Memory or Disk) specify the location of the link buffer. Debug Info in E X E option T h e D e b u g Info in E X E option puts d e b u g information in your program's executable file. Directories T h e Directories c o m m a n d o p e n s the Directories dialog box, where y o u specify the directories y o u want Turbo Pascal for Windows to use w h e n running and storing your application programs, as illustrated in figure 1.12.
  • 46. 24 Part I—Working with TPW Figure 1.12. The Directories dialog box. With the options in this dialog box, y o u decide where T u r b o Pascal for W i n d o w s finds the files it needs to compile, link, and output executable files. T h e E X E and T P U Directory input b o x specifies the directory that stores your .EXE and .TPU (object code) files. T h e Include Directories input b o x specifies the directories that contain your standard Include files. T h e Unit Directories input b o x specifies the directories that contain your T u r b o Pascal for W i n d o w s unit files. The Object Directories input b o x specifies the directories that contain your . O B J files (assembly language routines). The Resource Directories input b o x specifies the directories in which your resource files are kept. Guidelines for Entering Directory Names Use the following guidelines w h e n y o u enter directories in the Options/ Directories input boxes: • Separate multiple directory path names (if allowed) with a semicolon (;). • Use a m a x i m u m of 127 characters (including white space). White space before and after the semicolon is allowed but not required. • Relative and absolute path names are allowed, including path names relative to the logged position in drives other than the current o n e .
  • 47. 1—Getting Started 25 For example: C: ; D:TPW D:;C:TPW;D:TPW Preferences T h e Options/Preferences m e n u c o m m a n d o p e n s the Preferences dialog box, which lets y o u decide the behavior and physical appearance of the T u r b o Pascal for W i n d o w s environment (see figure 1.13). Figure 1.13. The Preferences dialog box. Editor Options T h e Editor O p t i o n s g r o u p has several check boxes that control text handling in Edit w i n d o w s . They are • Create B a c k u p File • A u t o Indent M o d e • Use Tab Character • O p t i m a l Fill • Backspace Unindents
  • 48. 26 Part I—Working with TPW • Cursor through Tabs • G r o u p U n d o • Block Overwrite T h e A u t o Save options define w h e n and h o w often T u r b o Pascal for W i n d o w s saves your o p e n files, settings, and options. They are • Editor Files • D e s k t o p • Configuration W h e n y o u select a n e w font displayed in the list box, the Font list b o x changes the size and appearance of the text. T h e Tab Size input b o x controls the n u m b e r of c o l u m n s the cursor moves for each tab stop. T h e Right M o u s e Button options (Nothing and Topic Search) determine whether T u r b o Pascal for W i n d o w s uses the right button to initiate a topic search in H e l p . The C o m m a n d Set options ( C U A or Alternate) determine whether the editor uses C o m m o n User Access (CUA) c o m m a n d s or Alternate c o m m a n d s . Open T h e Options/Open c o m m a n d displays the O p e n Configuration File dialog box, where y o u can retrieve n e w configuration-file settings. T h e File N a m e input b o x lets y o u enter the n a m e of the configuration file containing the settings y o u want; y o u choose O K or press Enter to load that file. T h e default configuration file n a m e is T P W . C F G . T h e Files list b o x lists the names of files in the current directory that match the file-name mask in the File-Name input box. The Directories list b o x lets y o u select a different directory to view. Press Alt-D to place the cursor in this list box. Save T h e Options/Save c o m m a n d saves in the current configuration file the primary file n a m e , the settings you selected with the O p t i o n s m e n u , and the desktop setup. Use Options/Save As to save options to a different configuration file. T h e n a m e of the current configuration file appears next to the Options/Save c o m m a n d . • All options and the editor c o m m a n d table are stored in T P W . C F G , the default saved-options file.
  • 49. 1—Getting Started 27 • History lists, the desktop state, and breakpoint locations are stored in TPW.INI. Save As T h e Options/Save As c o m m a n d o p e n s t h e Configuration Save As dialog box, where y o u enter a n e w n a m e for your configuration file (see figure 1.14). Figure 1.14. The Configuration Save As dialog box. Y o u can create a n e w configuration file by setting options a n d then selecting Options/Save As and entering a n e w configuration file n a m e . T h e newly created configuration file is n o w in effect. In the File N a m e input box, enter a n e w n a m e for the configuration file. C h o o s e O K or press Enter to create a . C F G file with the n e w n a m e . If y o u d o not specify a file extension, T u r b o Pascal for W i n d o w s adds a . C F G extension for y o u . For example: YOUR becomes YOUR.CFG. A history list is attached to the File N a m e input box. If the Configuration option is o n , settings m a d e to the current configuration file are saved w h e n y o u exit.
  • 50. 28 Parti—Working with TPW Directories List Box Use the Directories list b o x to change to another directory. Press Alt-D to place the cursor in the Directories list box. The Window Menu T h e Window m e n u has c o m m a n d s for manipulating and o p e n i n g windows. Most of the windows y o u o p e n from this m e n u have the standard w i n d o w elements such as scroll bars, Minimize and Maximize buttons, and a Control m e n u box. O p e n windows with the File/Open or File/New c o m m a n d s . At the bottom o f the Window m e n u is a list of o p e n windows. If more than o n e w i n d o w is o p e n , y o u can switch to another w i n d o w and make it active by selecting it from the list. These are the Window m e n u c o m m a n d s : • Tile • Cascade • Arrange Icons • Close All Tile C h o o s e Window/Tile to tile your o p e n windows. Using this c o m m a n d arranges the windows so that they cover the entire desktop without overlapping o n e another. Cascade C h o o s e Window/Cascade to stack all o p e n Edit windows. Cascade overlaps o p e n windows so that each w i n d o w is the same size, but part of each underlying w i n d o w is visible. Arrange Icons Select Window/Arrange Icons to rearrange the icons. Rearranged icons are evenly spaced, beginning at the lower-left corner o n the desktop. T h e o p e n files must be Minimized or this c o m m a n d is disabled.
  • 51. 1—Getting Started 29 Close All C h o o s e Window/Close All to close all o p e n w i n d o w s o n the desktop. If the text was changed since the previous time y o u saved it, a dialog b o x warns y o u to save the file before closing the window. C h o o s e Yes, N o , or Cancel. The Help Menu (Alt-H) T h e H e l p m e n u provides access to on-line H e l p , which appears in a special H e l p w i n d o w . T h e H e l p system provides information about most aspects o f the integrated environment and Turbo Pascal for Windows. T h e following list shows the H e l p m e n u c o m m a n d s : • I n d e x • Topic Search • Using H e l p • Compiler Directives • ObjectWindows • Procedures and Functions • Reserved Words • Standard Units • Turbo Pascal for Windows Language • Windows API • About Turbo Pascal for Windows Index (Shift-Fl) Turbo Pascal for Windows' on-line H e l p c o m e s with a comprehensive index that summarizes the organization and contents of the H e l p system. T o get into the H e l p system from the index, select o n e of the highlighted words or phrases in the index, click it or Tab to it, and then press Enter. If y o u don't k n o w how to use a H e l p system u n d e r Windows, choose the Help/Using H e l p M e n u c o m m a n d . Topic Search (Ctrl-Fl) If y o u place your cursor o n a word (a "token") in the active Edit w i n d o w and choose Help/Topic Search, a H e l p w i n d o w o p e n s with information about that token.
  • 52. 30 Parti—Working with TPW Y o u can set u p the Right m o u s e button (in the Options/Preferences dialog box) to initiate a topic search. H e l p provides on-line reference for many elements of the T u r b o Pascal for W i n d o w s language, including functions and procedures, reserved words, global variables, ObjectWindows, the W i n d o w s API, and so o n . Help/Using Help T h e Help/Using H e l p c o m m a n d displays information o n h o w to use T u r b o Pascal for W i n d o w s ' H e l p system (or any other H e l p system u n d e r W i n d o w s ) . Compiler Directives W h e n y o u choose this m e n u c o m m a n d , y o u see an index of compiler directives. C o m p i l e r directives control s o m e of T u r b o Pascal for W i n d o w s ' features. • S o m e turn compiler features o n or off. • S o m e specify parameters that affect h o w your application program is compiled. • Others control the conditional compilation of your application. A compiler directive is a c o m m e n t with a special syntax that y o u can put anywhere a c o m m e n t is allowed. ObjectWindows W h e n y o u select this m e n u c o m m a n d , y o u see a hierarchy of ObjectWindows types. Procedures and Functions W h e n y o u choose this m e n u c o m m a n d , y o u see an index of the T u r b o Pascal for W i n d o w s library procedures and functions that y o u can use to develop applications. Reserved Words W h e n y o u select this m e n u c o m m a n d , y o u see an index of all the reserved words in the T u r b o Pascal for W i n d o w s language. Reserved words have special m e a n i n g to the compiler. D o not use a reserved w o r d to n a m e your variables, procedures, functions, objects, and so o n .
  • 53. 1—Getting Started 31 Standard Units W h e n y o u select this m e n u c o m m a n d , y o u see a n index o f T u r b o Pascal for W i n d o w s ' standard units. A standard unit is a collection o f predefined con- stants, data types, variables, procedures, a n d functions. Y o u tell your applica- tion program to u s e only the units it needs. Turbo Pascal for Windows Language W h e n y o u select this m e n u c o m m a n d , y o u see a list o f the elements that comprise the T u r b o Pascal for W i n d o w s language. Windows API W h e n y o u select this m e n u c o m m a n d , y o u see an index of the constants, styles, messages, types, functions, a n d procedures that comprise the W i n d o w s Appli- cation Programming Interface (API). T u r b o Pascal for W i n d o w s declares all the W i n d o w s styles, constants, a n d types in the WinTypes unit. T h e WinProcs unit has all the API procedures a n d functions. About Turbo Pascal for Windows W h e n y o u select this c o m m a n d , a dialog b o x appears with copyright a n d version information. Press Esc o r click O K or Cancel to close the b o x . Editor T h e T u r b o Pascal for W i n d o w s editor is a complete programming editor. In almost all cases, y o u use it to develop all facets of your applications. In addition to being a full-screen, command-rich editor, it is based o n W i n d o w s ' multi- d o c u m e n t interface, which y o u learn h o w to use in Chapter 7, "Many Windows: A Multi-Document Interface." T h e multi-document interface enables many files to b e o p e n simultaneously. Thus, y o u c a n o p e n files for several units a n d switch between them easily without closing any files—a great feature w h e n y o u develop large projects. The Editor Commands T u r b o Pascal for W i n d o w s ' editor c o m m a n d s are summarized in the following groups o f c o m m a n d s :
  • 54. 32 Part I—Working with TPW • Block c o m m a n d s • Block c o m m a n d s ( C U A and Alternate) • Block c o m m a n d s (Borland style) • Extending selected blocks • O t h e r c o m m a n d s • Cursor-movement c o m m a n d s • Insert and Delete c o m m a n d s • M o r e about editor c o m m a n d s • Miscellaneous keyboard c o m m a n d s The Block Commands T h e following sections describe the block c o m m a n d s . Copy Block This c o m m a n d copies a previously selected block to the Clipboard and pastes it to the current cursor position. T h e original block is u n c h a n g e d . If n o block is selected, nothing h a p p e n s . Copy Text This c o m m a n d copies selected text to the Clipboard. Press Ctrl-Ins to use the c o m m a n d . Cut Text This c o m m a n d s cuts selected text to the Clipboard. Press Shift-Del to use the c o m m a n d . Delete Block This c o m m a n d deletes a selected block. Y o u can "undelete" a block with U n d o . Press Ctrl-Del or Ctrl-KY to use this c o m m a n d . Move Block This c o m m a n d moves a previously selected block from its original position to the Clipboard and then pastes it to the cursor position. T h e block disappears from its original position. If n o block is marked, nothing h a p p e n s . Press Shift- D e l to m o v e text to Clipboard and Shift-Ins to paste text in current d o c u m e n t .
  • 55. 1—Getting Started 33 PastefromClipboard This c o m m a n d pastes t h e contents of t h e Clipboard to cursor location. Press Shift-Ins to use t h e c o m m a n d . Read BlockfromDisk This c o m m a n d reads a disk file into t h e current text at t h e cursor position exactly as t h o u g h it was a block. Press Shift-Ctrl-R or Ctrl-KR to use this c o m m a n d . T h e text read is then selected as a block. When this c o m m a n d is initiated, y o u are p r o m p t e d for t h e n a m e of t h e file to read. Y o u can use wildcards to select a file to read, and a directory is displayed. T h e file specified can be any legal file n a m e . WWte Block to Disk This c o m m a n d writes a selected block to a file. Press Shift-Ctrl-W or Ctrl-KW to use this c o m m a n d . When y o u specify this c o m m a n d , T u r b o Pascal for Windows prompts y o u for t h e n a m e of t h e file to write to. T h e file can be given any legal n a m e (the default extension is .PAS). If y o u prefer to use a file n a m e without an extension, a p p e n d a period to t h e e n d of its n a m e . Note: If the file specified already exists, a warning is issued before t h e existing file is overwritten. If n o block is selected, nothing happens. Editor-Command Tables T h e tables throughout this section list t h e editor c o m m a n d s and their function or meaning. Table 1.1. The Block commands (CUA and Alternate). Movement CUA Both Alternate Delete block Ctrl-Del Ctrl-Del C o p y to Clipboard Ctrl-Ins Ctrl-Ins C u t to Clipboard Shift-Del Shift-Del Paste from Clipboard Shift-Ins Shift-Ins Read block from disk Shift-Ctrl-R Ctrl-KR Write block to disk Shift-Ctrl-W Ctrl-KW Indent block Shift-Ctrl-I Ctrl-KI Unindent block Shift-Ctrl-U Ctrl-KU
  • 56. 34 Parti—Working with TPW Table 1.2. The Block commands (Borland style). Command Keys Function Text selection O n Ctrl-KB Begins the selection of text; text selection ends with copying (Ctrl-KK) or cutting (Ctrl-KV) to the Clipboard, or turning text selection off with Ctrl-KH Text selection Off Ctrl-KH Stops the selection of text, and the selected text b e c o m e s unselected C o p y text to Clipboard Ctrl-KK C o p i e s the selected text to the Clipboard C u t text to Clipboard Ctrl-KV Cuts the selected text to the Clipboard Paste from Clipboard Ctrl-KC Pastes the contents of the Clipboard into your active Edit w i n d o w Extending selected blocks Movement CUA Both Alternate Left 1 character Shift-Left Shift-Left Right 1 character Shift-Right Shift-Right End of line Shift-End Shift-End Beginning of line Shift-Home Shift-Home Same column, Shift-Down Shift-Down next line Same column, Shift-Up Shift-Up previous line O n e page d o w n Shift-PgDn Shift-PgDn O n e page u p Shift-PgUp Shift-PgUp Left o n e word Shift-Ctrl-Left Shift-Ctrl-Left Right o n e word Shift-Ctrl-Right Shift-Ctrl-Right End of file Shift-Ctrl-End Shift-Ctrl-End Shift-Ctrl-PgDn Beginning of file Shift-Ctrl-Home Shift-Ctrl-Home Shift-Ctrl-PgUp
  • 57. 1—Getting Started 35 N o t e : T u r b o Pascal for Windows' Borland-style block c o m - m a n d s work only with t h e Alternate c o m m a n d set. Table 1.3- Commands that extend selected blocks. Movement CUA Both Alternate Left 1 character Shift-Left Shift-Left Right 1 character Shift-Right Shift-Right E n d o f line Shift-End Shift-End Beginning o f line Shift-Home Shift-Home Same c o l u m n , Shift-Down Shift-Down next line Same c o l u m n , Shift-Up Shift-Up previous line O n e page d o w n Shift-PgDn Shift-PgDn O n e page u p Shift-PgUp Shift-PgUp Left o n e w o r d Shift-Ctrl-Left Shift-Ctrl-Left Right o n e w o r d Shift-Ctrl-Right Shift-Ctrl-Right E n d o f file Shift-Ctrl-End Shift-Ctrl-End Shift-Ctrl-PgDn Beginning o f file Shift-Ctrl-Home Shift-Ctrl-Home Shift-Ctrl-PgUp Table 1.4. The cursor-movement commands (CUA and Alternate). Movement CUA Both Alternate Character left Left Left Ctrl-S Character right Ctrl-Right Right Ctrl-D W o r d left Ctrl-Left Ctrl-Left Ctrl-A Scroll d o w n 1 line Ctrl-Z Ctrl-Z Ctrl-Z Line u p U p U p Ctrl-E Line d o w n D o w n D o w n Ctrl-X Scroll u p 1 line Ctrl-W Ctrl-W Ctrl-W Scroll d o w n 1 line Ctrl-Z Ctrl-Z Ctrl-Z Page u p P g U p P g U p Ctrl-R continues
  • 58. 36 Parti—Working with TPW Table 1.4. continued Movement CUA Both Alternate Page d o w n P g D n P g D n Ctrl-C Last cursor position Ctrl-QP Beginning of line H o m e H o m e Ctrl-QS E n d of line E n d E n d C t r l - Q D T o p of w i n d o w Ctrl-E Ctrl-QE B o t t o m of w i n d o w Ctrl-X Ctrl-QX T o p of file Ctrl-Home Ctrl-Home Ctrl-QR, Ctrl-PgUp B o t t o m of file Ctrl-End Ctrl-End C t r l - Q C , Ctrl-PgDn Table 1.5- The Insert and Delete commands (CUA and Alternate). Movement CUA Both Alternate Delete char D e l Ctrl-G Delete char to left Backspace Backspace Delete line Ctrl-Y Ctrl-Y Delete line e n d Shift-Ctrl-Y Ctrl-QY Delete w o r d Ctrl-T Insert line Ctrl-N Ctrl-N Insert m o d e On/Off Ins Ins Ctrl-V Auto Indent This c o m m a n d toggles the automatic indenting of successive lines. Y o u also can use Options/Preferences/Autolndent in the I D E to turn automatic indenting o n and off. Current Compiler Options Inserts the current compiler-option settings at the head of your active Edit w i n d o w . Cursor through Tabs T h e arrow keys m o v e the cursor to the middle of tabs w h e n this option is o n ; otherwise the cursor w o u l d j u m p several c o l u m n s w h e n it moves over multiple tabs. Ctrl-OR is a toggle.
  • 59. 1—Getting Started 37 Find Place Marker This c o m m a n d finds a m a x i m u m of ten place markers (N can be any n u m b e r in the range zero to nine) in text. M o v e the cursor to any previously set marker by pressing Ctrl-Q and the marker number. Open File O p e n s an existing file in an Edit w i n d o w . Optimal Fill O p t i m a l Fill begins every line with the m i n i m u m n u m b e r of characters possible, using Tabs and spaces as necessary. This option produces lines with fewer characters. Save File This c o m m a n d saves the file and returns to the editor. Set Place This c o m m a n d marks a m a x i m u m of ten places in text w h e n y o u press Ctrl-K, followed by a single-marker digit (zero to nine). After marking your location, y o u can w o r k elsewhere in the file and then return to a marked location by using the Find Place Marker c o m m a n d (be sure to use the same marker n u m b e r ) . Y o u can have as many as ten places marked in each w i n d o w . Show last Compile Error This c o m m a n d highlights the last syntax error that the compiler f o u n d during the previous compile. T h e error message appears o n the status bar. If y o u have already closed that file, T u r b o Pascal for W i n d o w s reopens it and highlights the error. Tab Mode Y o u can specify the use of true Tab characters in the I D E with the Options/ Preferences/Use Tab Character option. Unindent Y o u can turn Unindent o n and off from the I D E with the Options/Preferences/ Backspace Unindents option.
  • 60. 38 Parti—Working with TPW Table 1.6. Miscellaneous keyboard commands. Movement CUA Both Alternate Autoindent on/off Ctrl-OI C o m p i l e r options C t r l - O O Cursor through Tabs Ctrl-OR on/off Find place marker N Ctrl-N* Ctrl-Q-N* H e l p F l F l H e l p index Shift-Fl Shift-Fl Maximize w i n d o w F5 O p e n file F3 Optimal fill m o d e Ctrl-OF on/off Pair matching Alt-[, Alt-] Ctrl-Q [, Ctrl-Q ] Save file F2, Ctrl-KJ Search Ctrl-QF Search again F3 F3 Search and replace Ctrl-QA S h o w last compile Ctrl-QW error Set marker Shift-Ctrl-N* Ctrl-K-N* Tabs m o d e on/off Ctrl-OT Topic H e l p Ctrl-Fl Ctrl-Fl Exit Alt-F4 Alt-X U n d o Alt-Backspace Alt-Backspace Unindent m o d e Ctrl-OU on/off Insert control Ctrl-P ** Ctrl-P ** character * TV indicates a number from zero to nine. r * To enter a control character, first enter Ctrl-P, and then enter the control character. The TPW Command-line Compiler The T u r b o Pascal for W i n d o w s command-line compiler (TPCW.EXE) lets y o u invoke all the functions of the I D E compiler (TPW.EXE) from the D O S c o m m a n d line.
  • 61. 1—Getting Started 39 T u r b o Pascal for W i n d o w s command-line options use this syntax: TPCW [ o p t i o n s ] < f i l e name> [ o p t i o n s ] where [ o p t i o n s ] can be o n e or m o r e options, separated by spaces. Y o u designate the status of the compiler option by specifying a plus ( + ) or a minus (-) after the option. • Place a + (or a space) after an option to turn it O n . • Place a - after the option to turn it Off. Table 1.7. Compiler options. Option Meaning Directive options /$A Align data /$B B o o l e a n evaluation /$D D e b u g information /$F Force FAR calls /$G Generate 286 instructions /$! Input/Output checking /$L Local Symbol information /$N 80x87 C o d e (numeric coprocessor) /$R Range checking /$S Stack-overflow checking /$V String variable checking /$W Windows stack frame /$X Extended syntax Mode options /B Build all /F Find error /L Link buffer /M Make /Q Quiet (no I D E equivalent) Conditional defines option /D Conditional defines continues
  • 62. 40 Parti—Working with TPW Table 1.7. continued Option Meaning Debug options /G .MAP file /V D e b u g information in E X E option Directory options /E E X E and T P U directory /I Include directories /O Object Files directories /R Resource directories /T T u r b o directory /U Unit directories Most of the command-line options have equivalent m e n u c o m m a n d s . Table 1.8. Command-line options and their IDE equivalents. Option IDE Equivalent /$A Options/Compiler/Align data /$B Options/Compiler/Boolean evaluation /$D Options/Compiler/Debug information /$¥ Options/Compiler/Force far calls /$G Options/Compiler/286 c o d e /$! Options/Compiler/I/O checking /$L Options/Compiler/local symbols /$M Options/Compiler/Memory sizes /$N Options/Compiler/80x87 code /$R Options/Compiler/Range checking /$S Options/Compiler/Stack checking /$V Options/Compiler/String Variable C h e c k i n g O p t i o n s /$W Options/Compiler/Windows Stack Frames /$X Options/Compiler/Extended Syntax /B Compile/Build
  • 63. 1—Getting Started 41 Option IDE Equivalent ID Options/Compiler/Conditional Defines IE Options/Directories/EXE and T P U Directory /F Search/Find Error /G Options/Linker/Map File /I Options/Compiler/lnclude Directories IL Options/Linker/Link Buffer /M Compile/Make /O Options/Directories/Object Directories /Q (none) /R Options/Directories/Resource Directories IT (none) /U Options/Directories/Unit Directories /V Options/Linker/Debug Information in E X E Onward, Forward, and Upward T u r b o Pascal for W i n d o w s is a flexible, powerful application development environment for Microsoft Windows, complete with editor, compiler, debugger, linker, and a powerful library of objects and tools. Y o u don't have to be a W i n d o w s or T u r b o Pascal expert to use T u r b o Pascal for W i n d o w s ; instead it helps y o u b e c o m e the W i n d o w s expert. A T u r b o Pascal for W i n d o w s application is limited only by your imagina- tion. Y o u can use units and libraries to create large and powerful W i n d o w s applications using either the I D E or the command-line compiler. In the next few h u n d r e d pages, I'll s h o w y o u just h o w easy and fun it can be to create W i n d o w s applications T u r b o Pascal style, using the p o w e r and flexibility of object-oriented programming techniques. S o u n d easy? It is. In the next chapter, y o u will g o to it!
  • 64. 2 CHAPTER ELEMENTS OF APPLICATION DEVELOPMENT Your Windows program doesn't interact directly with the screen, keyboard, printer, or any other device. Windows does all that, and places the results in an application message queue (in a device-independent fashion). Lee and Mark Atkinson If y o u have p r o g r a m m e d in any language, y o u undoubtedly have your o w n ideas about h o w to develop an application, whether it is for W i n d o w s or otherwise. T o develop an application for W i n d o w s , y o u have to learn h o w W i n d o w s works, but only at an easy level. Y o u also have to prepare your application to run in a W i n d o w s w i n d o w and y o u have to think (at least somewhat) in terms of events. T h e beans and rice of a W i n d o w s application is what y o u are used to: c o d e for solving p r o b l e m s — c o d e that manipulates information (or data). T h e biggest difference between developing a D O S application and a W i n d o w s application is that, with D O S , y o u are required to create your o w n user interface (unless y o u are writing a primitive application or o n e that does not require an interface). If y o u are writing a W i n d o w s application, y o u must "connect" to the W i n d o w s G U I (graphical user interface), but y o u d o not have to create it. Y o u use the W i n d o w s Interface, and y o u continue to use most of what y o u already k n o w about programming.
  • 65. 44 Part I—Working with TPW T o use a W i n d o w s application to solve a problem, y o u have to 1. Interact with W i n d o w s (mostly using ObjectWindows). 2. G e t information into the application (the input c o m p o n e n t ) . 3. Store information (the data c o m p o n e n t ) . 4. Manipulate the information, using procedures, functions, or object m e t h o d s (the operations c o m p o n e n t ) . 5. G e t the results (the output c o m p o n e n t ) . These steps are straightforward and probably familiar to y o u , except for the W i n d o w s connection. T o connect with W i n d o w s , use ObjectWindows, the T u r b o Pascal for W i n d o w s O O P library. ObjectWindows is an object-oriented library, packaged with T u r b o Pascal for W i n d o w s , that greatly simplifies W i n d o w s applications development by encapsulating (packaging) c o m p l e x W i n d o w s information in a simpler, m o r e easily accessible form. T o handle actions 2 through 5, y o u structure your application along traditional "structured" programming lines. Y o u use conditional statements ( I t s ) and loops ( w h i l e s , r e p e a t s , and so o n ) . Y o u divide groups of instructions into sections that can be referenced by n a m e (procedures, functions, objects). This again is programming as y o u probably already k n o w it (whether y o u program in Pascal or another similarly structured language such as C or C + + ). T u r b o Pascal for W i n d o w s , like T u r b o Pascal for D O S , supplies a rich set of data types and built-in operators, controls, procedures, and functions for manipulating information. T u r b o Pascal for W i n d o w s lets y o u create large applications by dividing any program (or application) into pieces (units) that can be compiled separately. T h e remainder of this chapter briefly covers s o m e of the basic aspects of T u r b o Pascal for W i n d o w s and its development capabilities. If y o u already k n o w T u r b o Pascal, feel free to skip this section and m o v e o n to the next chapter, where y o u learn h o w to develop W i n d o w s applications using the object- oriented techniques of ObjectWindows. (You will not see any Windows-specific c o d e until the next chapter.) If y o u want m o r e information about the standard (or built-in) T u r b o Pascal for W i n d o w s procedures and functions, check out the reference section. Units T o develop any T u r b o Pascal for W i n d o w s application, y o u must use at least o n e T u r b o Pascal for W i n d o w s standard unit, but y o u can use many m o r e units if y o u have to (either standard ones or units y o u create). A unit is a collection of constants, data types, variables, procedures, and functions. In a nutshell, a unit is the basis of m o d u l a r programming in T u r b o Pascal for D O S and T u r b o Pascal for W i n d o w s . Y o u use units to create libraries and to divide large applications into logically related m o d u l e s .
  • 66. 2—Elements of Application Development 45 T u r b o Pascal for W i n d o w s supplies the following standard units: Strings System WinCrt WinDOS WinProcs WinTypes These standard units (which are stored in TPW.TPL) support your T u r b o Pascal for W i n d o w s applications in m a n y ways, taking m u c h o f the work o u t o f developing applications. T h e Strings unit supports a type o f character strings called null- terminated strings. Null-terminated strings are the type o f strings required by the W i n d o w s Application Programming Interface (API). (Previously, T u r b o Pascal did not support null-terminated strings.) T h e System unit (SYSTEM.TPU) is the T u r b o Pascal for W i n d o w s run-time library. It implements low-level, run-time support routines (procedures a n d functions) for all the built-in T u r b o Pascal for W i n d o w s "features," such as file Input/Output, floating point operations, string-handling, and dynamic m e m o r y allocation. All units a n d programs automatically u s e the System unit, so y o u d o not have to specify it in a uses declaration. (You learn m o r e about the uses declaration in this section). T h e WinCrt unit implements a terminal-like text screen in a w i n d o w . Y o u d o not have to write "Windows-specific" c o d e if your application uses WinCrt. In many cases, y o u c a n start with T u r b o Pascal for W i n d o w s quickly by translating existing T u r b o Pascal (for D O S ) c o d e a n d using the WinCrt screen to "run" it. Y o u will learn h o w to use WinCrt in the next chapter. T h e WinDos unit implements operating system a n d file-handling proce- dures a n d functions. These procedures a n d functions are specific to T u r b o Pascal a n d are not defined by standard Pascal. T h e WinProcs unit defines function a n d procedure headers for the W i n d o w s API. Y o u c a n access every function in the standard W i n d o w s libraries through WinProcs. T h e WinProcs a n d WinTypes units both define the T u r b o Pascal for W i n d o w s implementation o f the W i n d o w s API. T h e WinTypes unit defines T u r b o Pascal versions o f all the types used by the W i n d o w s API functions, including simple types and data structures (records, a n d so o n ) a n d all the standard W i n d o w s constants, including flags, messages, a n d styles. Units are both conceptually a n d pragmatically important because • They are precompiled s o y o u c a n u s e the functions, procedures, a n d so o n in a unit without recompiling the unit each time y o u compile another part o f your application. T h u s , units save time.
  • 67. 4 6 Part I—Working with TPW • Units also let y o u break u p functionality for separate development, modification, a n d use. Projects thus can b e large a n d their develop- ment a n d management simplified. Units are nifty, useful structures that change the way your T u r b o Pascal for Windows application code is stored in memory. Consider first h o w a compiled T u r b o Pascal for W i n d o w s application (without units) stores itself in memory. It divides itself into four main sections: 1. Code segment 2. D a t a segment 3. S t a c k segment 4. H e a p The code segment contains the application's procedures, functions, a n d the main program b o d y o f the application. T h e d a t a segment contains the application's global variables a n d constants. T h e s t a c k segment contains return addresses for the applications' functions a n d procedures a n d most of the local variables declared inside functions a n d procedures. T h e heap contains any variables y o u create dynamically using the T u r b o Pascal for W i n d o w s keyword, New. Each section (code, d a t a , a n d s t a c k segments) can use as m u c h as 64K (kilobytes) of memory, a n d the heap can grow as large as available m e m o r y allows. Figure 2.1 shows a m e m o r y m a p of this scheme. High Memory Heap ?K Stack Segment 64K Data Segment 64K Code Segment 64K Memory Map Without units Low Memory Figure 2.1. A memory map of three segments, plus the heap.
  • 68. 2—Elements of Application Development 47 Without units, a compiled T u r b o Pascal for Windows application can be about 192K plus the h e a p (whose size d e p e n d s o n the n u m b e r of dynamically allocated variables). In contrast, the procedures and functions in a unit are stored in separate segments apart from the m a i n m o d u l e . Each unit can use as m u c h as 64K of memory. T h u s , an application that uses units can consist of as m a n y of these 64K units as m e m o r y (the system's, not yours) allows. O f course, applications that use units can be large. Figure 2.2 shows a m e m o r y m a p of an application segmented into units. High memory Heap ?K Stack Segment 64K Data Segment 64K Unit 64K Unit 64K Code Segment 64K Low memory M e m o r y Map with units Figure 2.2. A memory map of units. T o use a standard (or precompiled) unit, add a u s e s declaration at the beginning of the main m o d u l e of your application: Program M a i n ; u s e s W i n C r t ; { . . . . body h e r e . . . } T o use m o r e than o n e unit, separate the units by c o m m a s : Program M a i n ; u s e s W i n T y p e s , S t r i n g s ,
  • 69. 48 Parti—Working with T P W WinProcs, WObjects; { ... body here ... } Y o u use the standard T u r b o Pascal for W i n d o w s units throughout this b o o k , a n d they are discussed in m o r e detail as y o u m o v e along. Creating your o w n units is similar to creating the main m o d u l e o f a n application, with a couple o f exceptions: 1. Rather than designate the m o d u l e as a program, y o u designate it as a unit: Unit YourUnit; 2. Y o u also divide the unit into parts: Unit heading Interface part Implementation part Initialization part T h e unit heading specifies the unit's n a m e (the n a m e y o u u s e w h e n y o u refer to this unit in another module's Uses declaration). T h e interface part declares constants, types, variables, procedures, a n d functions that are public (available to any m o d u l e that uses the unit). List the procedures a n d functions as headings only in the interface part. T h e implementation part defines the bodies o f all public procedures a n d functions. I n addition, it declares constants, types, variables, procedures, a n d functions that are private a n d , thus, are not available to users o f the unit. T h e initialization part is the last part o f a unit. It consists o f either: • T h e reserved w o r d end ( n o initialization code) or • A statement part to b e executed to initialize the unit Listing 2.1 shows the layout o f a unit. Listing 2.1. The general layout of a unit. Unit YourUnit; Interface { Use something here }
  • 70. 2—Elements of Application Development 49 { CONST, TYPE, VAR declarations here } { PROCEDURE and FUNCTION declarations here } Implementation { Another Use here, if you want it } { Any Private LABEL, CONST, TYPE, VAR declarations here } { Procedure and function bodies here } Begin { Initialization statements } End.
  • 71. 50 Part I—Working with TPW T u r b o Pascal for W i n d o w s handles units intelligently. For example, if several m o d u l e s (or units) in an application refer to the same unit, only o n e copy of that unit—not several—is loaded into memory. Data Types and Identifiers Application development begins and ends with variables. Whenever y o u declare a variable, y o u must specify its type. T h e variable type indicates • T h e range of values the variable can take • T h e operations that can be performed o n it W h e n y o u specify a type (in a t y p e declaration) y o u specify an identifier that denotes a type. Y o u use identifiers throughout your application, and a T u r b o Pascal for W i n d o w s identifier can denote any of the following: • Constants • Fields in records • Functions • Labels • Procedures • Programs • Types • Units • Variables Identifiers can be any length, but only the first 63 characters are significant (recognized by T u r b o Pascal for W i n d o w s ) . Y o u have to follow a few rules w h e n y o u use identifiers: • T h e first character of an identifier must be a letter. • T h e characters that follow the first character must be letters, digits, or underscores (no spaces). • Identifiers are not case-sensitive. As this chapter states, applications development begins and ends with variables. Variables must be t y p e d in T u r b o Pascal. It is helpful to divide these types into six major classes, which are covered next. For m o r e in-depth information about T u r b o Pascal for W i n d o w s types, consult the T u r b o Pascal for W i n d o w s manuals.
  • 72. 2—Elements ofApplication Development 51 Qualified Identifiers W h e n your application declares several instances of the same identi- fier, you might have to qualify the identifier by specifying a unit identifier to select the correct instance of the identifier. The combined Unit. Identifier specification is called a qualified identifier. For example, the following are qualified identifiers: System. Exit (unit = System, identifier = Exit) Dos. Exec (unit = Dos, identifier = Exec ) Crt .Window ( unit = Crt, identifier = Window) Y o u c a n divide types as follows: 1. Simple types that define ordered sets o f values: A. Ordinal types, which include: Integer types B o o l e a n types Char type Enumerated types Subrange types B. Real types 2. String types that represent a sequence o f characters with a dynamic length attribute a n d a constant size attribute. 3. Structured types that hold more than o n e value. These include: Array types Record types Object types Set types File types 4. Pointer types that define a set o f values that point to dynamic variables of s o m e type. A dynamic variable is o n e that is allocated o n the heap and manipulated using pointers. Because the heap c a n b e quite large (much larger than a stack allocated in the data segment, which is limited to 64K), dynamic variables also c a n b e quite large. 5. Procedural types that allow procedures a n d functions to b e treated as objects. A n object, which y o u learn m u c h more about throughout this
  • 73. 52 Part I—Working with TPW b o o k , consists of data and the procedures and functions that y o u use to manipulate that data. For example: AWindow = object x1, x2, y1, y2 :Integer; procedure minimize; procedure maximize; end; 6. Object types are structures that consist of a fixed n u m b e r of c o m - ponents. Ordinal Types T u r b o Pascal has nine predefined ordinal types. Five of these integer types denote a specific subset of the w h o l e numbers: Type Range Size Shortint 128.. 127 8-bit Integer - 3 2 7 6 8 . 3 2 7 6 7 16-bit Longint -2147483648. .2147483647 32-bit Byte 0.255 8-bit Word 0.65535 16-bit T h e other four predefined ordinal types are the Booleans ( B o o l e a n , WordBool, L o n g B o o l ) , a n d C h a r . T w o other classes of user-defined ordinal types are enumerated types and subrange types. Three standard functions can b e u s e d with all ordinal types: 1. Ord (which returns the ordinality of the value). For example: O r d ( F a l s e ) = 0; 2. Pred (which returns the predecessor of the value). For example: P r e d ( T r u e ) = F a l s e ; 3. S u c c (which returns the successor of the value). For example: S u c c ( T r u e ) = F a l s e ; Boolean Types T u r b o Pascal for W i n d o w s has three predefined B o o l e a n types: B o o l e a n , WordBool, and L o n g B o o l , which are defined as follows:
  • 74. 2—Elements of Application Development 5 3 type Boolean = (False, True); WordBool = (False, True); LongBool = (False, True); These types have the following sizes: • Boolean is byte-sized (8 bits). • WordBool is word-sized (16 bits). • LongBool is longint-sized (32 bits). Because Booleans are enumerated ordinal types, the following relation- ships exist a m o n g B o o l e a n types: True > False Ord(False) = 0 Ord(True) = 1 Succ(False) = True Pred(True) = False A m o n g the "Booleans," Boolean is the preferred type a n d uses the least memory. WordBool a n d LongBool exist primarily for compatibility with your applications in the W i n d o w s environment. In a n expression, the following relational operators produce results o f type Boolean: <> > < > = < = IN For W i n d o w s compatibility, Booleans c a n assume ordinal values other than zero a n d o n e . A B o o l e a n expression is considered false w h e n its ordinal value is zero, a n d true w h e n its ordinal value is nonzero. Char Type Use variables of the ordinal type Ch a r to store A S C I I characters. Write character constants between single quotations, as in the following:
  • 75. 54 Part I—Working with T P W ' 9 ' 'A' 'L' 'i' '&' T h e single quotation character is written as t w o single quotations within single quotations, like this: i i i i T h e Chr function converts a n integer value into a character with the corresponding A S C I I value. T h e Ord function returns a character's A S C I I value. Enumerated Types Enumerated types define ordered sets of values by enumerating the identifiers that denote the values. Their ordering is determined by the sequence in which the identifiers are enumerated. For example: type Food = (Apple, Kiwi, Peach, Date); In this declaration, Kiwi is a constant o f type Food. T h e Ord standard function returns the ordinality o f an enumerated constant. In this example: Ord (Apple) = 0 Ord(Kiwi) = 1 Ord(Peach) = 2 Ord(Date) = 3 T h e identifiers in the type definition b e c o m e constants of the enumerated type. T h e first constant has an ordinality o f zero, the second has a n ordinality of o n e , the third a n ordinality o f two, a n d so o n . Subrange Types A subrange type is a range of values from a n ordinal type sometimes called the host type. For example: LittleConstant .. BiggerConstant
  • 76. 2—Elements of Application Development 5 5 specifies the smallest and largest value in the subrange. In this case, the subrange is from L i t t l e C o n s t a n t to B i g g e r C o n s t a n t . Both constants must be of the same ordinal type, and the first constant must be less than or equal to the second constant. T h e $R compiler directive controls range-checking of subrange types. T h e following are subrange examples: 0. .49 -128..127 Reals A real type has a set of values that is a subset of the real numbers, which can be represented in floating-point notation with a fixed n u m b e r of digits. A value's floating-point notation normally consists of three values: M, B, and E, such that M x B E = N where B is always 10, M is a rational number, and E is an integer in the real type's range. Turbo Pascal for Windows supplies four predefined real types. Each type has a specific range and precision: Type Range Digits Bytes Real 2.9e-39..1.7e38 11-12 6 Single 1.5e-45..3.4e38 7-8 4 D o u b l e 5.0e-324..1.7e308 15-16 8 Extended 3.4e-4932..1.1e4932 19-20 10 N o t e : T u r b o Pascal for W i n d o w s supports two models of floating-point c o d e generation: 1. Software floating point 2. 80x87 floating point Use the $N compiler directive to switch between the two models. Strings A T u r b o Pascal string type variable (not a null-terminated string type) is a sequence of characters with a dynamic length, and a constant m a x i m u m size between 1 and 255.
  • 77. 56 Parti—Working with T P W If y o u declare a string without a m a x i m u m size, it automatically b e c o m e s a size o f 255. String constants are written in quotations; for example: 'Windows1 'Bible' Notice that two consecutive single quotations are used to indicate a single quotation in a string. T h e following operators c a n b e used with string type values: + < > < = > = Operators compare strings by using the A S C I I codes for letters a n d numbers. For example, the A S C I I c o d e for Af is 77 a n d 7* is 84. Thus, a string beginning with an M is less than o n e beginning with a T. T h e A S C I I c o d e for a lowercase ra, however, is 109. Thus, an uppercase 7*is less than a lowercase m. K e e p this in m i n d w h e n y o u compare strings. Structured Types A structured type can hold more than o n e value. Structured types are • Array (types) • File (types) • Object (types) • Record (types) • Set (types) If a c o m p o n e n t type is structured, the resulting structured type has m o r e than o n e level of structuring a n d can, in fact, have unlimited levels of structur- ing (memory permitting). In other words, a structured type can contain other types that are themselves structured. These other types can, in turn, contain m o r e types that also are structured. The m a x i m u m size of any structured type in T u r b o Pascal is 65,520 bytes (about 64K). T h e reserved w o r d packed in a structured type's declaration tells the compiler to compress data w h e n it stores the type. Note: T u r b o Pascal for W i n d o w s accepts the reserved w o r d packed, but ignores it.
  • 78. 2—Elements of Application Development 5 7 Arrays A n array is a collection of values of the same type. Arrays make data m u c h m o r e manageable. Y o u declare a n array as follows: array [index-type] of element-type T h e element type c a n b e any type, but the index type must b e a n ordinal type. Y o u c a n use several index types if y o u separate t h e m by c o m m a s . Each index type separated by a c o m m a represents a dimension o f the array. For example: type CharData = array[1 A'..1 Z1 ] of Byte; { 1 Dimension } NumList = array[1..600] of Integer; { 1 Dimension } Matrix = array[0..21, 0..21] of real; { 2 Dimensions } Records A record contains a n u m b e r o f c o m p o n e n t s , or fields, that c a n b e o f different types. A record declaration begins with the keyword record a n d ends with an end. For example: ThisRecord = Record Month: 0 .. 12; Day : 1 .. 31; Year : Integer; end; A record also can b e variant. I n other words, a g r o u p o f records c a n have different structures d e p e n d e n t o n a condition. For example: type ClassType = (Num, Dat, Str); Date = record D, M, Y: Integer; end; Facts = record Name: string[10];
  • 79. 58 Parti—Working with T P W case Kind: ClassType of Num: (N: real); Dat: (D: Date); Str: (S: string); end; D e p e n d i n g o n whether Kind is a Num, Dat, or Str, the Facts record contains an N, D, o r S data field. Object Types A n object type is a data structure similar to a record, also containing a fixed n u m b e r o f c o m p o n e n t s . Each c o m p o n e n t is either a field (which contains data of a particular type) or a m e t h o d (procedure or function), which "operates" o n an object's data. For example: GenericObject = object Fieldl : integer; { Object data } Field2 : real; procedure Methodl; { Object behavior } procedure Method2; end; W h e n y o u declare a field, y o u specify an identifier that names the fields and their data types. W h e n y o u declare a m e t h o d , y o u specify a procedure, function, constructor, or destructor heading. Here's the scenario in somewhat formal form: Field = FieldName(s): type; M e t h o d = procedure MethodName(<parameter(s)>type); or = function MethodName(<parameter(s)>:type):type; or = constructor MethodName(<parameter(s)>:type [;<parameter(s)>: type]); /"virtual/; or = destructor MethodName[(<parameters> type)/;/virtual/; A n object type c a n inherit the data a n d behavior (its c o m p o n e n t s ) from another object type. T h e inheriting object is a descendant, a n d the object that supplies the data a n d behavior for inheritance is an ancestor.
  • 80. 2—Elements of Application Development 59 The d o m a i n o f an object type consists o f itself a n d all its descendants. Sets Sets define collections o f elements o f a specific scalar o r subrange type. F o r example, the following are set types: type Day = (Sun, Mon, Tue, Wed, Thu, Fri, Sat); CharSet = set of Char; Digits = set of 0..4; Days = set of Day; Months = (January, February, March, April, May, June, July, August, September, October, November, December); T h e base type o f a set must b e an ordinal type with not m o r e than 256 possible values. Thus, the ordinal values of the u p p e r a n d lower b o u n d s of the base type must b e in the range 0..255. A set constructor, which denotes a set type value, is formed by writing expressions in brackets. Each expression denotes a value o f the set. T h e bracket notation [ ] denotes the empty set—compatible with all set types. For example, the following are set constructors: [Mon..Sat] [1, 3, I + 1 .. J - 1] ['0'..'5', 'A'..'Q', 'd'..'z', '_'] Files A file type consists o f a linear sequence o f c o m p o n e n t s o f s o m e c o m p o n e n t type, which can b e any type except a file type. If y o u omit the c o m p o n e n t type, the type denotes an untyped file. T h e predefined file type Text signifies a file containing characters orga- nized into lines. For example, the following are File type declarations: type Employee = record ID : Integer; FirstName: string[10]; LastName : string[20]; Address : string[40]; end;
  • 81. 60 Parti—Working with T P W EmployeeFile = file of Employee; NumberFile = file of Real; SwapFile = file; Pointer Types A pointer type variable contains the m e m o r y address o f a dynamic variable o f s o m e "specified" base type. In other words, a pointer does not contain a data value; it contains a m e m o r y address. A pointer "points t o " a u n i q u e location in memory. Pointers can point to locations that contain byte values, integers, reals, records, strings, or any other data type. Pointers are extremely important in object-oriented p r o g r a m m i n g a n d are used throughout this book. Although y o u might think that pointers are complicated creatures (rumor has it), they are not. K e e p in m i n d that a pointer holds a m e m o r y address, not a data value. Y o u assign data values to the addresses held in the pointer by using the pointer. T h e pointer is the only way y o u c a n get at the data. This procedure sounds a little indirect, but it is important in both object-oriented a n d W i n d o w s programming, a n d it is discussed in detail throughout the book. Y o u c a n assign a value to a pointer variable with: • T h e NeworGetMem procedures • T h e @ operator • T h e Ptr function T h e reserved w o r d nil denotes a pointer constant that points nowhere. T h e predefined type Pointer denotes an untyped pointer (a pointer that does not point to any specific type). For an application to use a pointer, it must first request m e m o r y for the type of data the pointer points to. It requests m e m o r y by initializing the pointer with New: var APointer : "Integer; begin New(APointer); end; In this case, New reserves space for an integer value.
  • 82. 2—Elements of Application Development 61 Y o u c a n then store a value at the address pointed to by APointer, using a caret after t h e pointer n a m e : APointer" := 28; T h e caret indicates that y o u d o not want the pointer itself (as an address), but the value at the address pointed to by the pointer. This is called dereferencing the pointer. T h e following are pointer type declarations: type BytePtr = "Byte; WordPtr = "Word; IdentPtr = "IdentRec; IdentRec = record Ident: string[24]; RefCount: Word; Next: IdentPtr; end; If y o u are not used to using pointers, y o u might w o n d e r w h y it is worth going to the extra trouble o f using them, because pointers are, by their nature, indirect. O n e g o o d reason to use pointers is that variables pointed to by pointers use memory that is in the heap, not in t h e data segment. T h e heap is dynamic a n d c a n grow as large as it has to (memory permitting). T h e data segment is a fixed size, a n d variables in the data segment are o f a fixed size as well. If y o u are designing applications such as a database, which has to b e flexible about how m u c h memory it eventually uses, pointers a d d the flexibility. Databases, spreadsheets, a n d anything else that d e p e n d s o n linked lists, trees, and other dynamic structures rest o n pointers. A n array must have precise dimensions, a n d thus must specify in advance (at compile time) how m u c h memory it uses. Variables addressed through pointers d o not have to specify their exact size at compile time. Decisions c a n be delayed until run-time—a definite plus in many applications. For example, if o n e computer system has 8 M (megabytes) of memory a n d another 640K, a database or spreadsheet that uses pointers to allocate memory can utilize t h e extra memory to create larger data sets o n the larger system. PChar T h e predefined type PChar denotes a pointer to a null-terminated string. Declare PChar as follows: type PChar = "Char;
  • 83. 62 Part I—Working with T P W T u r b o Pascal for W i n d o w s supports a set of extended syntax rules (controlled by the $X compiler directive) to facilitate handling o f strings using the PChar type. Procedural Types Standard Pascal regards procedures a n d functions strictly as program parts that can b e executed through procedure o r function calls. T u r b o Pascal a n d T u r b o Pascal for W i n d o w s have m u c h broader views o f procedures a n d functions. T h r o u g h procedural types, T u r b o Pascal allows y o u to treat procedures a n d functions as objects that c a n b e assigned to variables and passed as parameters. A procedural type declaration specifies the parameters and, for a function, the result type. T h e key difference between a procedure a n d a function is that a procedure does not return a value for the procedure itself. A function always returns a value o f s o m e type: integer, real, a n d so o n . T h e syntax for a procedural type declaration is exactly the same as that for a procedure or function header, except y o u omit the identifier after the procedure o r function keyword. For example: type AProc = procedure; ASwapProc = procedure(var A, B: Integer); AStrProc = procedure(S: String); AMathFunc = function(A: Real): Real; ADeviceFunc = function(var F: Text): Integer; AMinFunc = function(A,B: Real; F: AMathFunc): Real; T h e parameter names in a procedural type declaration have n o effect o n the meaning o f the declaration. T u r b o Pascal for W i n d o w s does not let y o u declare functions that return procedural type values. A function result value must b e a String, Real, Integer, Char, Boolean, Poinfer, o r a user-defined enumeration. Turbo Pascal for Windows Reserved Words Reserved words are words that have fixed meanings in the T u r b o Pascal for W i n d o w s language. In other words, y o u cannot redefine reserved words. Y o u must use t h e m as they are. T u r b o Pascal for W i n d o w s is not case-sensitive, so y o u c a n use upper- or lowercase letters to specify reserved words.
  • 84. 2—Elements of Application Development 63 T h e T u r b o Pascal for W i n d o w s reserved words are as follows: and asm array begin case const constructor destructor div do downto else end exports file for function goto if implementation in inline interface label library mod nil not object of or packed pointer procedure program record repeat set shl shr string then to type unit until uses var while with xor Statements A statement is o n e of the following: • assignment (: =) • begin..end • case..of ..else..end • for..to/downto..do • goto • if ..then..else • inline(...) • procedure call • repeat..until • while..do • with..do
  • 85. 64 Part I—Working with T P W Table 2.1 shows the operator precedence for the mathematical, relational, and logical operators in T u r b o Pascal for W i n d o w s . Table 2.1. Operator precedence from high to low. Operators Precedence @ , not First (high) *, /, div, m o d , a n d , shl, shr S e c o n d + , - , or, x o r Third = , < > , < , > , < = , > = , in Fourth (low) assignment (:=) A n assignment operator (: =) assigns the value o f an expression to a variable. T h e variable must b e assignment-compatible with the result type o f the expression. T h e variable that is assigned the n e w value is o n the left o f the assignment operator. T h e value its assigned to is o n the right. For example: A := B; { A is assigned the value B. } C[I] := C[I] + 1 ; { C[I] is assigned the value C{I} + 1 } LoopR := (I > 0) and (I < 30) { LoopR is assigned the value that } { results from the evaluation of } { the expression on the right. } begin..end T h e begin...end constructs serve as statement brackets. For example: begin Statementl; Statement2; StatementX; end;
  • 86. 2—Elements of Application Development 6 5 W h e n they are bracketed in this way, any n u m b e r o f consecutive state- ments can b e treated as a single statement. For example: {Compound statement used in an 'if statement } if First < Last then begin Temp := First; First := Last; Last := Temp; end; case..of..else..end T h e case statement consists o f an expression (the selector) a n d a list o f statements, each prefixed with a case. F o r example, a simple case: case AnExpression of case: Statementl; case: Statement2; end; or a case-else: case AnExpression of case: Statementl; case: Statement2; else Statement3; end; A c a s e consists of o n e o r m o r e constants o r ranges, separated by c o m m a s . T h e else part is optional. For example: case Ch of 'A'..'Z', 'a'-.'z1 : WriteLn('Letter'); '0'..'9': WriteLn('Digit'); '+', '-', '*', '/': WriteLn('Operator'); else WriteLn('A Special character'); end;
  • 87. 66 Part I—Working with T P W for..to/downto..do T h e for statement causes the statement after do to b e executed o n c e for each value in the range first to last. For example, a f or-to: for Var1 := First to Last do Statementl; or for Var1 := First to last do begin Statementl; Statement2: end; or a f or-downto: for Var1 := First downto Last do Statementl; T h e control variable a n d initial a n d final values must b e ordinal types. If y o u u s e a Downto, the value o f the control variable falls in increments of o n e for each l o o p . With downto, the value o f the control variable falls in decrements by o n e for each l o o p . For example: { for ... to, for ... downto } for I := 1 to ParamCount do WriteLn(ParamStr(I); for I := 1 to 15 do for J := 1 to 15 do begin X := 0; for K := 1 to 15 do X := X + Matrix1[I,K] * Matrix2[K,J]; Matrix[I,J] := X; end; goto A goto statement transfers program execution to the statement prefixed by the label referenced in the statement.
  • 88. 2—Elements of Application Development 67 For example: goto ALabel T h e label must b e in the same block as the goto statement; y o u cannot transfer execution o u t o f a procedure o r a function. For example: label 1, 2; goto 1 1: WriteLn ('Something can happen here'); 2: WriteLn ('Something different here'); i£.then..else I f, t h e n, a n d else specify the conditions u n d e r w h i c h a statement is executed. For example, a simple if-then: if AnExpression then Statementl; or if AnExpression then begin Statementl; Statement2; end; O r an if-then-else: if AnExpression then Statementl else Statement2; If the B o o l e a n expression after the if is true, the statement after then is executed. Otherwise, if there is a n else part, the statement after else is executed. For example: { 'if statements } if (X < Min) or (X > Max) then X := 0;
  • 89. 68 Parti—Working with T P W if ParamCount <> 2 then begin WriteLn('Can not execute the command line1 ); Halt(1); end else begin ReadFile(ParamStr(1)); WriteFile(ParamStr(2)); end; inline(...) Inline statements a n d directives allow y o u to insert machine-code instruc- tions directly into the c o d e o f a main program m o d u l e or a unit. For example: inline (data/data/...data) If y o u u s e inline as a statement, the inline data elements are inserted directly in the code. If y o u u s e inline as a directive in a procedure or a function declaration, the inline data elements are inserted in the c o d e each time the procedure or function is called. A n inline data element consists o f a constant or a variable identifier, optionally prefixed by a size specifier: < or > . A variable identifier can b e followed by a + or a - a n d a constant that specifies a n offset from the variable's address. A n inline element generates o n e byte o f c o d e if it is a constant in the range 0..255. Otherwise, it generates o n e word. Y o u use the < a n d > operators to override the automatic size selection: < means "always generate a byte." > means "always generate a w o r d . " For example: { 'inline' statement } procedure FillWord(var Dest; Count: Word; Data: Word); begin inline( $C4/$7E/<Dest/ (* LES DI,Dest[BP] *)
  • 90. 2—Elements of Application Development 69 $8B/$4E/<Count/ (* MOV CX,Count[BP]*) $8B/$46/<Data/ (* MOV AX,Data[BP] *) $FC/ (* CLD *) $F3/$AB); (* REP STOSW *) end; procedure call A procedure is a program c o m p o n e n t that defines a specific action or operation o n a variable or g r o u p o f variables. For example: procedure identifier; Or, a procedure c a n have parameters: procedure identifier ( parameters ); T h e procedure heading specifies t h e identifier for the procedure a n d the formal parameters, if there are any. A procedure is activated by a procedure statement. T h e procedure heading is followed by: • A declaration part that declares local objects • T h e statements between begin a n d end, which specify what action occurs w h e n t h e procedure is called Rather than specify the declaration a n d statement parts, a procedure declaration c a n specify a forward, external, or inline directive. A forward declaration indicates that a procedure will b e defined later (that is, forward) in the c o d e : procedure GetNum (X: Integer); forward A n external declaration refers to separately c o m p i l e d procedures a n d functions written in assembly language: procedure Copyword (var Source, Dest,Count: Word);external; A n inline directive allows y o u to p u t machine-code instructions directly into your c o d e : procedure Disablelnterrupts; inline ($FA);
  • 91. 70 Parti—Working with T P W For example: { A Procedure Declaration } procedure WrStr(X, Y: integer; S: string); var SaveX, SaveY: Integer; begin SaveX := X; SaveY := Y; Writeln(S); end; repeat.until T h e statements between repeat a n d until are executed in sequence until the B o o l e a n expression is true at the end o f the sequence. For example: repeat Statementl; Statement2; StatementN until AnExpression A repeat-until sequence is executed at least o n c e . For example: { Repeat Statements } repeat Ch := GetChar until Ch <> ' '; repeat Write('Enter a value: '); ReadLn(V); until (V >= 0) and (V <= '99'); whilc.do Awhile statement contains a n expression that controls the repeated execution of a statement (which c a n b e a c o m p o u n d statement). For example: while AnExpression do Statementl
  • 92. 2—Elements of Application Development 71 T h e statement after do is executed repeatedly as long as the B o o l e a n expression is true. T h e expression is evaluated before the statement is executed, so if the expression is false at the beginning, the statement is not executed. I n other words, there is n o certainty that a while-do executes even o n c e . For example: { 'while' statements } while Ch = ' ' d o Ch := GetChar; while not Eof(InputFile) do { Eof means End of file } begin ReadLn(InputFile, Line); WriteLn(OutputFile, Line); Inc(LineCount); end; with„do T h e wit h statement is an alternate m e t h o d for referencing the fields of a record. For example: with ARecord do Statementl; In the statement after do, the fields o f o n e o r m o r e record variables c a n be accessed using only their field identifiers. For example: { 'with' statement } with Date[C] do begin Month := 1; Year := Year + 1; end; This is equivalent to Date[C].Month := 1; Date[C].Year := Date[C].Year + 1;
  • 93. 72 Part I—Working with T P W Debugging Turbo Pascal for Windows Applications Although y o u probably never make mistakes (ha, ha), y o u might want to k n o w that if y o u d o , T u r b o Pascal for W i n d o w s can help. Its help c o m e s in the form of the T u r b o Pascal for W i n d o w s Debugger. T h e T u r b o Pascal for W i n d o w s D e b u g g e r is a powerful tool for d e b u g g i n g W i n d o w s applications. It goes a major step or two further than the built-in d e b u g g i n g capabilities of the T u r b o Pascal for W i n d o w s compiler. T h e T u r b o Pascal for W i n d o w s compiler's bug-detecting p o w e r focuses o n your applica- tion c o d e syntax. If y o u have an u n k n o w n identifier or have omitted a necessary semicolon, the compiler finds it. It cannot guarantee m o r e than correct syntax. Y o u r c o d e can survive compiler bug-detection and still crash miserably at run- time. Run-time errors are the d o m a i n of another class of b u g detectors: "debuggers." Debuggers help y o u isolate and correct mistakes that usually are not d u e to errors in syntax. This is a broad a n d c o m p l e x g r o u p of errors y o u can make in the logic of your c o d e , by not accounting for the full range of possible actions of your c o d e , and so o n . D e b u g g i n g , in this realm, is an imperfect "art" at best, and debugging W i n d o w s applications is even m o r e imperfect. T h e key to d e b u g g i n g W i n d o w s applications lies in isolating the m o r e likely error-prone areas of your c o d e . A few simple development tactics help: 1. C o d e in small fragments. Use object-oriented techniques to k e e p data and the behavior for manipulating data in objects. 2. D e v e l o p objects, units, or other structural blocks o n e at a time. Make sure that an object or a block works before moving o n to other objects or blocks, particularly if these objects a n d blocks are interrelated. 3. Reduce the n u m b e r of procedures, functions, and so o n , that can manipulate data. If y o u d o not use objects, then use local variables. These tactics help, but they probably will not eliminate all your bugs. W h e n y o u discover a b u g in your W i n d o w s application, call o n T u r b o D e b u g g e r for W i n d o w s . In effect, it slows d o w n the execution of an application and lets y o u examine its specific aspects. Y o u can examine the stack, variable values, C P U registers, W i n d o w s messages, and so o n . T u r b o D e b u g g e r gives y o u seven main ways to explore your c o d e : 1. Tracing (executing an application o n e line at a time). 2. Back tracing (stepping backward through the application c o d e o n e line at a time, and reversing the execution).
  • 94. 2—Elements of Application Development 73 3. Stepping (executing the application c o d e o n e line at a time but "stepping over" any calls to procedures or functions). This way the procedure or function is executed as a block and any values are returned, but y o u d o not "trace" through the procedure or function o n e line at a time. 4. Viewing (opening a w i n d o w for viewing the states of various c o m p o - nents of the application). These c o m p o n e n t s are the application's variables, break points y o u set, the stack, a T u r b o D e b u g g e r log, a data file, a source file, C P U c o d e , memory, registers, numeric processor information, object hierarchies, the application's execution history, and the application's output. 5. Inspecting data structures (such as arrays). 6. C h a n g i n g (manipulating the application by replacing the current value of a variable with a n e w value that y o u specify). 7. Watching application variables (tracking the changing values of vari- ables y o u specify). All the T u r b o D e b u g g e r for W i n d o w s features are available in pull-down m e n u s . T h e simplest way to use T u r b o D e b u g g e r for W i n d o w s is to load the application y o u want to d e b u g into a T u r b o Pascal for W i n d o w s edit w i n d o w , and then select D e b u g g e r from the T u r b o Pascal for W i n d o w s Run/Debugger m e n u . Make sure, t h o u g h , that y o u select Options/Linker/Debug info into an executable file (.EXE) before y o u run T u r b o D e b u g g e r . T h e specifics of h o w y o u d e b u g your application d e p e n d o n the kind of application and possible error. In general, y o u d o not want to trace through an entire W i n d o w s application. Instead, try to isolate the error as best y o u can and set break points in likely troubled areas. (You probably are thinking that if y o u k n e w where the error was, y o u w o u l d not n e e d the debugger—Yes and N o . ) If y o u are developing the application object-by-object or block-by-block, y o u can at least reduce the b u g to that area. Set a break point, and then trace through the application from the break point. In many situations, making sure that a procedure, function, or m e t h o d is called, or monitoring a variable's values can locate the bug. Most d e b u g sessions are started by setting break points and adding the variables in those break points using A d d Watch. T h e n y o u step or trace through the code. If y o u get a run-time error that typically looks like this: Runtime error 204 at 0001:004 Notice the address (you probably want to write it d o w n ) , and use the Find Error c o m m a n d o n the T u r b o Pascal for W i n d o w s Search m e n u to locate the error in your source c o d e (see figure 2.3).
  • 95. 74 Parti—Working with TPW Figure 2.3- The Find error... command in the Search menu. The Find Error dialog box appears (see figure 2.4). Figure 2.4, Result of selecting the Find error... command.
  • 96. 2—Elements of Application Development 75 Enter the address of the error in the Error Address box. T u r b o Pascal for W i n d o w s then recompiles your c o d e and stops w h e n it reaches the address y o u specify, highlighting the statement that caused the error. T h e n , fix the error (in the edit w i n d o w ) and recompile. Repeat the process if y o u have to. Begin.. A W i n d o w s application is c o m p l e x and impressive. In fact, a g o o d way to impress your friends is to tell t h e m h o w c o m p l e x a W i n d o w s application is and then s h o w t h e m a W i n d o w s application y o u created. If y o u use T u r b o Pascal for W i n d o w s , y o u can impress your friends and develop applications that were b e y o n d the scope of most " g o o d " programmers only o n e year ago. Progress, at least of a kind, o n e has to admit. Sometimes, w h e n I find myself peering through o n e w i n d o w or another, I'm not sure whether I should be surprised by the progress.
  • 97. 3CHAPTER OBJECTS FORWINDOWS So if Windows is the future, how do programmers get there? The answer is, of course, by using object-oriented programming. Zack Urlocker Overture T u r b o Pascal for W i n d o w s makes developing a Microsoft W i n d o w s (called W i n d o w s from n o w on) application affordable (mentally, I m e a n ) . Because T u r b o Pascal for W i n d o w s is a W i n d o w s application (that is, it runs in a Microsoft W i n d o w s w i n d o w ) , y o u can write, test, and d e b u g source code in W i n d o w s without having to shift between text and graphic m o d e s . This process makes developing W i n d o w s applications convenient, efficient, and (believe it or not) enjoyable. If you're a T u r b o Pascal programmer, y o u already k n o w that y o u have the niftiest compiler in personal computing. It's fast, has a terrific user interface (IDE), and, starting with version 5.5, has included object-oriented extensions. These extensions are your ticket into the W i n d o w s development arena. In short, T u r b o Pascal for W i n d o w s is mostly T u r b o Pascal plus ObjectWindows, an object-oriented library that encapsulates the c o m p l e x behaviors of W i n d o w s applications in objects. These inheritable, extendable
  • 98. 78 Parti—Working with TPW objects handle most of the tedious initialization required before an application can c o m m u n i c a t e with W i n d o w s . If y o u already k n o w T u r b o Pascal, you'll be running W i n d o w s applications in minutes by using T u r b o Pascal for W i n d o w s . Y o u build them out of objects derived from ObjectWindows. About Turbo Pascal Windows Until recently, a developer creating a Microsoft W i n d o w s application c o u l d expect to learn at least 550 functions at a l o w level and write an application in either assembly language or Microsoft C — a difficult, time-consuming task at best. T h e latest version of Borland International's world-class compiler, T u r b o Pascal, called T u r b o Pascal for W i n d o w s , makes Microsoft W i n d o w s develop- ment m u c h , m u c h easier. T h e advantages of this compiler/programming environment are several: 1. Because its core and I D E (integrated development environment) are similar to previous versions of T u r b o Pascal, only a short learning investment is required by the million-plus current T u r b o Pascal programmers. 2. It abstracts the 550 W i n d o w s API (Application Programming Interface) functions to a high level through the use of object-oriented techniques, and thus lets a programmer "inherit" existing W i n d o w s functionality (buttons, dialogue w i n d o w s , m e n u s , and so on) rather than create each w i n d o w from scratch. Programmers call low-level W i n d o w s API functions through a high-level object-oriented unit called "ObjectWindows." 3. It lets a programmer write, compile, run, and d e b u g applications in the W i n d o w s environment, without exiting to D O S . N o other popular compiler (including Microsoft C and Borland C + + ) can d o this. 4. It includes the Whitewater Resource Compiler, which significantly simplifies the writing of m e n u s , dialogues, controls, and so o n . Figure 3.1 shows W i n d o w s , the T u r b o Pascal for W i n d o w s I D E , and the Whitewater Resource C o m p i l e r running together.
  • 99. 3 — O b j e c t s for Windows 79 Figure 3.1. Windows, the IDE, and the compiler running together. Because T u r b o Pascal programmers can learn object-oriented program- m i n g ( O O P , for short) without giving u p a language they already know, they get the best of both c o m p u t i n g worlds—structured programming and objects. M o r e important, because T u r b o Pascal is general-purpose and fast, it's practical for commercial applications. T u r b o Pascal for W i n d o w s compiles c o d e at the same blazing speed as T u r b o Pascal 6.0—on my modestly paced 386SX, running at l 6 M h z : 4 0 , 0 0 0 + lines per minute. T h e addition of ObjectWindows to the T u r b o Pascal core is the best thing that has h a p p e n e d to T u r b o Pascal since units, and T u r b o Pascal for W i n d o w s is the best thing that has h a p p e n e d to W i n d o w s since, well, W i n d o w s . In this book, I guide y o u through two passes of the W i n d o w s development process: 1) a quick and clean pass and 2) a detailed and dirty pass. O n the first o n e , I s h o w y o u h o w to build a B a s i c l n t e r f a c e (object) that handles many of your applications. I g o quickly, sparing y o u the details I think y o u can live without. If you're not a programming whiz, don't worry; y o u won't have to be. T u r b o Pascal for W i n d o w s does most of the work. Y o u don't n e e d to k n o w most of the details to create a major application. O n the second pass, I fill in many of the blanks for y o u aficionados and hackers. This pass includes the fun stuff. W i n d o w s , even for a command-line kind of guy like myself, is undeniably a pleasant, fun environment to work in, especially if y o u think in pictures. Many folks d o , so a deeper understanding of optimization techniques, m e m o r y management, and other juicy topics can be profitable.
  • 100. 80 Parti—Working with TPW W i n d o w s is an event-driven interface. W i n d o w s intercepts events, such as a m o u s e click, a keypress, and so o n , and dispatches t h e m as messages to the appropriate application w i n d o w s . A W i n d o w s application makes the appropri- ate response to these messages to perform the following actions: • Carry out s o m e task • S e n d a message back to W i n d o w s • S e n d a message to another application T h e objects in ObjectWindows encapsulate this c o m p l e x message ex- change in objects, which y o u use as stock items or extend b y w a y of inheritance. Y o u should understand generally h o w objects work and h o w event and message processing occurs, so I both explain and s h o w y o u pictures as y o u m o v e along. Y o u don't have to understand the specific details of W i n d o w s event and message processing, thanks to ObjectWindows. T o develop a W i n d o w s application with T u r b o Pascal for W i n d o w s , y o u use a few objects in the ObjectWindows library and extend them however y o u n e e d to. T h e B a s i c I nt e r f a c e I develop in Chapter 4, "Inheriting an Interface," is derived from ObjectWindows and can be easily extended for your specific needs. I'll s h o w y o u how. As o u r interfaces, p r o g r a m m i n g languages, and c o m p u t i n g tools b e c o m e m o r e powerful, they b e c o m e m o r e c o m p l e x as well. O n e path through the complexity is the repackaging of applications in an event-driven architecture like W i n d o w s . Not that event-driven architectures aren't c o m p l e x — t h e y are, but they can be m a n a g e d easily with O O P techniques. Objects inherently c o m m u n i c a t e through messages. W h e n y o u want an object to d o something, y o u send o n e of its m e t h o d s (functions or procedures) a message. T h e object performs a task (which c o u l d entail sending a message to another object). Objects y o u derive from ObjectWindows also can send and receive messages from W i n d o w s . If you're thinking that objects and W i n d o w s d o things quite alike, you're right, and well o n your way to understanding h o w to write W i n d o w s applications with T u r b o Pascal for W i n d o w s . W i n d o w s is a graphics environment; that's the exceptional reason for using it. Sure, the multitasking and standardized interface and device drivers are wonderful, but y o u can get those features elsewhere. It's graphics, plus those attributes, that make W i n d o w s special. T h e applications y o u develop with T u r b o Pascal for W i n d o w s pay special attention to graphics. In this b o o k , I pay the same special attention and use many graphics to illustrate what might otherwise be tough to conceptualize. You're g o o d at visualizing, manipulating, learning from images—a big reason y o u use graphics interfaces. So, "Nuff said," s o m e hurried hero said. Let's get to it.
  • 101. 3 — O b j e c t s for Windows 81 Why Does the World Make So Much Sense? Actually, this question is more than a little debatable. Why does T u r b o Pascal for Windows make so m u c h sense? That question I tackle in the next hundred or so pages, beginning with general concepts s u c h as events, messages, and objects. I begin with O O P , working toward Windows and the ObjectWindows connection. T u r b o Pascal for Windows is another amazing development in t h e evolution of T u r b o Pascal. It is the dynamite solution to what was almost an overwhelming p r o g r a m m i n g problem: how to make sense of Microsoft Windows' development. The Tao ofObjects C h i n e s e philosophers in ancient times expressed a belief in a unifying reality that they called the T a o . T o these philosophers, the T a o was a way of understanding that the world was not a static entity, but a dynamic, ever- changing process. T h e objects that m a k e u p the world reflect the dynamic process, because they are ever-changing. I use the phrase "the T a o of objects" to express the dynamic nature of p r o g r a m m i n g problems and the m o d e l i n g of systems based o n "the real world." Because the world is evolving, your p r o g r a m m i n g models of the world must evolve as well. In his introduction to my book, The Tao of Objects, Bruce Eckel wrote: O n e difficulty p e o p l e have w h e n learning object-oriented program- m i n g is finding a way to think about it. Often y o u hear s u c h unhelpful things as "It's easier for s o m e o n e w h o doesn't k n o w how to program to learn O O P than for an experienced programmer" or "You n e e d to unlearn what y o u k n o w . " M y personal experience hasn't supported this. A l t h o u g h thinking about objects is different from thinking about procedural programming, it's different because you're stepping into a larger world, not because everything y o u k n o w is w r o n g . This is especially true with hybrid languages like C + + and T u r b o Pascal; you'll see that t h e ability to create user- defined [object] types isn't s u c h a radical idea, since y o u use data types so m u c h that y o u usually don't even think about t h e m . However, it does tend to highlight t h e limitations of t h e built-in types and (to my mind) t h e relative primitiveness of what we've b e e n using as p r o g r a m m i n g languages so far. O n c e y o u begin using an object-oriented language, it's hard to g o back. I couldn't agree more with Bruce. If y o u start with what y o u k n o w (I assume T u r b o Pascal), and add k n o w l e d g e of O O P and k n o w l e d g e of Windows, you'll have Windows programming, T u r b o Pascal style, d o w n . Y o u can start with O O P .
  • 102. 82 Part I—Working with TPW Objects and actions c o m p o s e our world. Objects (the n o u n s of the grammatical world) have attributes or characteristics. Actions (the verbs of the grammatical world) express behaviors. A spruce sways. S n o w falls. H e r eyes o p e n . T h e application w i n d o w sends or receives a message. A user responds to a m e n u . Y o u click a m o u s e , and so o n . In a program, data are the characteristics of an object. Operations are its behaviors. A n object-oriented programming language like Turbo Pascal encap- sulates an object's characteristics and its behaviors within a single block of source c o d e . Operations and behaviors are in o n e place, which makes g o o d sense. It's convenient and safer than having them spread about. Putting together data and the operations to manipulate data is encapsulation. Using O O P techniques, programmers can create their o w n object types, which the compiler treats just as it does built-in types. Y o u build u p c o m p l e x types from simpler types that share characteristics and behaviors. This description shouldn't s o u n d all that n e w to you. Turbo Pascal programmers have b e e n creating n e w types all along—by collecting variables into records. Objects simply add the functions and procedures to manipulate the data to the package. So, not unexpectedly, an object type looks m u c h like its data-only counterpart—a record in Pascal. It's just a little more; a record plus the functions and procedures (which O O P calls methods) to manipulate the data fields. Recall that y o u declare a record like this: type recordl = aRecord; aRecord = record ID : integer; Name: string; X,Y : integer; end; Define an object like this: type anObject = object ID : integer; X,Y : integer; procedure ManipulateX; procedure ManipulateY; end; A variable of type anObj ect looks like this: var ov: anObject;
  • 103. 3 — O b j e c t s for Windows 83 A pointer looks like this: var op: "anObject; op = @ov; X a n d Y are data fields. ManipulateX a n d ManipulateY are m e t h o d s for manipulating the data fields, X a n d Y. T o access members o f a n instance (a variable) o f a n object type, y o u use the same selection operators y o u use with r e c o r d s — o r a With statement: ov.X := 256; op"ManipulateX; { procedure call! } With ov do begin X:= 256; Y:= 128; ManipulateX; ManipulateY; end; A n object type consists o f everything that describes it. Its characteristics and behaviors are together in o n e block o f c o d e . Notice that y o u don't have to pass X a n d Y to the m e t h o d s ManipulateX and ManipulateY. ManipulateX a n d ManipulateY already have access to X a n d Y because they both are packaged in the same type. In other words, they share a local scope. Everything in a n object type (data fields a n d methods) is shared a n d thus k n o w n to everything else. F r o m another perspective, combining data a n d c o d e in an object is a neat extension of Pascal units. Programs consist of collections of units. Units contain definitions of object types, functions, and variables. S o , at o n e level, object types suggest a way to organize c o d e . There's m u c h m o r e to it than that: it's a m o r e powerful w a y o f thinking about c o d e . Different objects c a n share s o m e characteristics a n d behaviors, while not sharing others. Shared characteristics a n d behaviors c a n b e collected in a c o m m o n type called a base type. For example: mandolins, guitars, drums, banjos, fiddles, a n d flutes are all types o f musical instruments. They have different specific characteristics, but each has a way o f making s o u n d a n d c a n be played. T h e base type, the musical instrument, encapsulates these c o m m o n characteristics: it creates s o u n d a n d it c a n b e played. T h e act o f playing the instrument a n d the way the instrument sounds differ from instrument to instrument. Y o u pluck the strings of a banjo with your fingers; y o u b l o w air into a flute. T h e vibrations of strings c o m b i n e d with w o o d creates a guitar s o u n d . T h e pressure a n d v o l u m e o f air p r o d u c e d by your lips and lungs c o m b i n e with w o o d or metal to create a flute s o u n d .
  • 104. 8 4 Part I—Working with T P W In the everyday world, y o u classify objects into types a n d extend your knowledge by assigning the attributes y o u k n o w (from previous object types) to n e w ones. Using O O P techniques, y o u create applications in a similar manner, by creating base object types and deriving n e w object types from them. Inheritance Encapsulation is the beginning, a n d there's m u c h more to O O P than that. H o w d o y o u modify or extend a n object's functionality? If y o u c a n help it, y o u don't g o in a n d m u c k around the c o d e . This c a n easily lead to n e w bugs, a n d y o u t o o often will mess u p something that already works. A better path, after you've defined a n e w base type, is to build o n the base type using inheritance. When a n e w type (called a derived type) inherits from a base type, the n e w type automatically receives all the characteristics a n d behaviors o f the base type, without "lifting a finger." Y o u also c a n assemble a n e w type o f object from a group o f existing objects. This process is called composition. A w o o d l a n d community, for example, is c o m p o s e d o f trees, herbaceous plants, animals, a n d the micro- organisms that sustain them. Derivation a n d composition enable y o u to reuse existing c o d e without introducing n e w bugs. Y o u c a n develop applications faster, more efficiently, a n d more clearly. In an important sense, object-oriented programming is a w a y to build family trees (or hierarchies) for data structures. In Turbo Pascal (unlike in s o m e O O P languages) an object c a n have only o n e immediate ancestor, or a single inheritance (see figure 3.2). (An object c a n have any n u m b e r o f ancestors, but only o n e immediate ancestor.) Let's say that you've created a base type: base = object X,Y: integer; procedure ManipulateX; procedure ManipulateY; end; N o w y o u want to a d d s o m e specialized functionality to it. Therefore, y o u create a n e w type from this base type. Y o u want the derived type to b e identical to the base type except to extend the base by adding a m e t h o d called RecalculateXandY. Y o u create the derived type's characteristics by simply inheriting t h e characteristics from the base type. derived = object (base) procedure RecalculateXandY; end;
  • 105. 3 — O b j e c t s for Windows 8 5 I nheritance O b j e c t _ 1 ( B a s e ) O b j e c t _ 2 ( d e r i v e d f r o m O b j _ 1 ) O b j e c t _ 3 ( d e r i v e d f r o m O b j _ 2 ) O b j e c t _ 3 ( d e r i v e d f r o m O b j _ 1 ) O b j e c t _ 4 ( d e r i v e d f r o m O b j _ 1 ) Figure 3.2. Single inheritance. Because d e r i v e d (the n e w object type) inherits all the data fields and m e t h o d s of b a s e (its ancestor object type), y o u don't n e e d to redefine base's data fields and m e t h o d s . Y o u just tell the compiler y o u want to derive a n e w type from a base type—the line d e r i v e d = o b j e c t ( b a s e ) does the trick—and add the n e w m e t h o d . N o w y o u can use M a n i p u l a t e X , M a n i p u l a t e Y , and R e c a l c u l a t e X a n d Y with any instance (variable) of type d e r i v e d , just as t h o u g h all three m e t h o d s had b e e n defined in d e r i v e d : v a r d: d e r i v e d ; With d do b e g i n X : = 4 0 ; Y : = 3 2 ; M a n i p u l a t e X ; R e c a l c u l a t e X a n d Y ; M a n i p u l a t e Y ; e n d ; Notice that y o u don't have to pass the variables X and Y to any of d e r i ved's m e t h o d s ; it inherited access to X and Y along with base's methods.
  • 106. 86 Parti—Working with T P W Inheritance lets y o u build c o m p l e x data types w h e n y o u n e e d to, without repeating any code. A n e w object type simply inherits whatever it needs from an ancestor a n d ignores or revises what it doesn't. T h e derived type can use as m u c h or as little o f its ancestors' c o d e as it wants. T h e derived type can reimplement (or override) any m e t h o d it decides to. This reimplementation o f base type methods in derived types is fundamental to another o f O O P ' s key concepts, polymorphism, which I get to in a m o m e n t . Inheritance is useful for two important reasons. T h e first is a simple o n e : w h e n you're given a working object type that doesn't d o exactly what y o u want (let's say that your neighbor in the next cubicle handed it to y o u ) , y o u can create a n e w object type from the o l d o n e with inheritance, adding characteristics or behaviors to suit yourself. This capability enables y o u to program quickly, while isolating the existing c o d e (which works—your neighbor is trustworthy, right?) from your n e w , experimental c o d e (which m a y not). T h e second use o f inheritance involves the behavior o f derived object types that descend from the same base. When y o u learn to handle a kayak, y o u learn something that can b e applied to a bicycle or pickup truck as well. When y o u steer any o f these vehicles, y o u don't have to think about which type o f vehicle it is—you steer a n d the vehicle moves. Because this is true in the world, w h y shouldn't it b e true with programming as well? Polymorphism Using polymorphism, y o u can represent this vehicular system with a base object type called vehicle a n d derived object types called kayak, bicycle, a n d pickup. T h e base type contains a generic steer m e t h o d : vehicle = object Afield : integer; procedure Steer; virtual; end; and each derived type contains a reimplemented Steer method: bicycle = object Afield : integer; procedure Steer; virtual; end; Any vehicle can b e steered (because vehicle contains a steer m e t h o d ) , but each vehicle can steer itself differently (by overriding the vehicle steer m e t h o d ) . Because vehicle can respond to a message called steer, any type derived from vehicle also can accept that message.
  • 107. 3 — O b j e c t s for Windows 87 Thus, bicycles, kayaks, a n d pickups can b e steered because they're vehicles, but the m e t h o d each specific type uses w h e n vehicle gets the steer message c a n differ. In a nutshell this is polymorphism. Y o u tell the vehicle to steer itself (send it a steer message), a n d the vehicle figures out h o w to carry out the message. W h y is polymorphism so useful? Because this system (which uses poly- morphism) won't have to relearn everything each time it encounters a n e w type of vehicle. This system applies existing k n o w l e d g e to n e w situations. A n object- oriented program that steers vehicles doesn't n e e d to b e rewritten just because it needs to handle a n e w type o f vehicle. It already k n o w s that any vehicle c a n respond to the steer message a n d act accordingly (see figure 3 3 ) . P o l y m o r p h i s m S t e e r m e s s a g e V e h i c l e ( o b j e c t ) B i c y c l e ( d e r i v e d f r o m V e h i c l e ) P i c k u p t r u c k ( d e r i v e d f r o m V e h i c l e ) K a y a k ( d e r i v e d f r o m V e h i c l e ) O n e s t e e r m e s s a g e p r o d u c e s s p e c i f i c s t e e r b e h a v i o r i n e a c h v e h i c l e . Figure 33. Polymorphism. Polymorphism is important because programmers can't k n o w everything about a program or the p r o b l e m a program needs to solve while developing the program. Programs should b e able to change their behaviors in response to n e w information. Text editors (or w o r d processors) didn't k n o w about fonts a n d styles w h e n they were first created; n e w features h a d to b e added as users b e c a m e m o r e sophisticated a n d their needs evolved. T h e n e e d for programs to change and evolve has b e e n a nemesis o f software development since the early days. C h a n g e is both expensive a n d necessary, a n d the inability to change quickly often leads to programming obsolescence.
  • 108. 88 Parti—Working with T P W Evolution a n d change must b e an integral part o f a program. N e w information might c o m e from understanding a system in a n e w way or because the problem changes in t h e real world. Either way, change is inevitable. Polymorphism lets y o u create extensible programs. Behaviors such as steering a vehicle or making musical sounds c a n b e c o m m o n to a group of types but implemented differently for each. T h e concept is the same, but t h e implementation details might differ. Using polymorphism, y o u c a n create a system which knows that musical instruments can b e played, but not how a particular instrument is played. Specific playing details can c o m e later. T h e system is extensible because y o u c a n add n e w types o f instruments (or vehicles, or whatever) a n d n e w ways o f playing without redesigning the program. T h e capability to create object types is a powerful o n e indeed, o n e that fits in well with how p e o p l e view t h e world. If y o u think in terms o f types, representing a real-world system as an application (or program) c o m p o s e d o f base a n d derived types is a natural process. Ideally, the m o d e l o f a system in a program is a direct m a p p i n g o f a system from t h e world. Therefore, as the system in the world changes, it is easier to change the m o d e l in the computer. Messages Conventional programming systems typically view a program as a collection o f functions a n d procedures. These functions a n d procedures are the active c o m p o n e n t s o f the program; data are passive. When y o u declare data globally, any function or procedure c a n access them, thus placing the data at any function's or procedure's mercy. T h e likelihood o f incorrect data manipula- tion is high. When y o u declare data locally (in a procedure), only that procedure c a n get at the data. T h e data are safer, but a little t o o restricted for most tastes. S o m e flexibility usually is n e e d e d , an in-between solution, in which data c a n b e accessed by s o m e restricted n u m b e r o f defined functions a n d procedures. In object-oriented programming, a m e t h o d (an object's functions a n d proce- dures) is programmed to manipulate only certain data, a n d data accept manipulation by only certain methods. Manipulation is handled through the sending a n d receiving o f messages (see figure 3.4). In a procedural program, a program's flow of control is determined by the ordering o f procedures a n d control mechanisms such as if, w h i l e , s w i t c h , and so o n . This ordering implies that y o u k n o w how to structure t h e entire program w h e n y o u create the program. In programs designed to "capture" the essence o f a dynamic world, this assumption is unrealistic a n d c u m b e r s o m e . T h e world is evolving, a n d our ideas a n d models o f the world must adapt to survive. A better alternative captures the design flow in terms o f the logical relationships a m o n g objects.
  • 109. 3 — O b j e c t s for Windows 89 O b j e c t s e n c a p s u l a t e d a t a a n d m e t h o d s Object D a t a _ f i e l d 1 D a t a _ f i e l d 3 D a t a _ f i e l d 2 M e t h o d i m e s s a g e s s e n t t o O b j e c t m e t h o d s M e t h o d 2 D a t a _ f i e l d 4 M e t h o d s a c c e s s d a t a f i e l d s . Figure 3 A. Messages. O O P captures these logical relationships in objects, a n d t h e flow o f control in a n object-oriented application is determined by the messages sent to and received from objects. When y o u send a message, y o u clarify the c o m m u - nication a m o n g the c o m p o n e n t s of a program. Objects respond to the messages sent t o them a n d send messages to other objects. Messages, not data, m o v e through t h e system. Rather than "invoke a function o n s o m e data" (the procedural approach), y o u "send a message to a n object" (the object-oriented approach). T o send a message to a n object, y o u specify the object and the m e t h o d y o u want to invoke. S u p p o s e that you've declared the following point type: Point = object X : integer; Y : integer; constructor Init(InitX, InitY : integer); function IsVisible: integer; { is the point on or off? Return State. } end; P o i n t ' s characteristics are its location on-screen ( X and Y coordinates). Its behaviors are to construct itself and to report (if it receives a message requesting this information) whether it's visible.
  • 110. 90 Part I—Working with T P W Y o u declare a n d initialize a n instance o f t h e object in a two-step process like this: var SomePoint : Point; begin SomePoint.Init(23,28); end; T h e n y o u c a n ask SomePoint w h e t h e r it's visible by sending it a message: var Visible : integer; begin Visible := SomePoint.IsVisible; end; Sending a message means calling an object's m e t h o d , w h i c h manipulates or interprets t h e type's characteristics. Static and Dynamic Binding E a c h object talked about so far uses statically b o u n d m e t h o d s . When a m e t h o d is statically b o u n d (also referred to as early binding) t h e compiler allocates a n d resolves all references to t h e m e t h o d at compile-time. When y o u call a statically b o u n d m e t h o d , t h e compiler determines exactly w h i c h m e t h o d to send a message to at compile-time—an efficient way to search for m e t h o d s unless y o u want to use polymorphism. With polymorphism, y o u want to send a message to an object a n d let t h e object determine w h i c h m e t h o d to u s e . S o , you're asking t h e compiler to resolve s o m e references at run-time; this process is called late, o r dynamic, binding. T o resolve references to m e t h o d s at run-time, y o u create virtual m e t h o d s . T o create a virtual m e t h o d , a d d t h e keyword virtual to t h e m e t h o d in t h e base object type a n d include a special procedure called a const ructor in t h e object. After a m e t h o d is declared virtual in a base type, this m e t h o d must b e declared virtual in all inherited types. T o make AddXandY a virtual m e t h o d , for example, y o u declare it as virtual at its earliest a n d in all subsequent declarations:
  • 111. 3 — O b j e c t s for Windows 91 derived = object(base) constructor Init; procedure AddXandY; virtual; end; an0bject2 = object(derived) constructor Init; procedure AddXandY; virtual; end; Virtual methods enable derived types to have their o w n distinct versions of a base type m e t h o d . Y o u use this thorny (but quite powerful) aspect of object- oriented programming again a n d again. Dynamic Style Most folks w h o discuss object-oriented programming emphasize only three o f its aspects: encapsulation, inheritance, a n d polymorphism. T h e T a o of objects, as I've explored it, must also incorporate another important concept: dynamic style or the u s e o f dynamic objects. Although y o u c a n create an instance o f a polymorphic object o n the stack (without using pointers), it's convenient a n d helpful to create a n instance at run-time by allocating it o n the heap, using a pointer. Turbo Pascal manipulates dynamic variables easily a n d efficiently through the New a n d Dispose proce- dures in Turbo Pascal. T o create an instance o f an object type, pass New a pointer to the instance of the type to b e created: var ShapePointer : "Shape; New(ShapePointer); As with records, New allocates e n o u g h space o n the heap for an instance of the pointer's base type, and stores that space's address (in the pointer). When the dynamic variable contains any virtual methods, y o u must use a construc- tor to initialize the type before sending any messages to the object. Y o u c a n use New to allocate space a n d initialize the instance of the type in o n e step, because New c a n take the constructor (Init) as a parameter: var EllipsePtr : "Ellipse; New(EllipsePtr,Init(140,75,50)); { points and radius }
  • 112. 92 Part I—Working with TPW Dynamic variables are useful because y o u can add any n u m b e r of in- stances of them at run-time without k n o w i n g the exact n u m b e r o f instances at compile-time. By delaying system-determining decisions until run-time, y o u allow c o d e to be disconnected from a type's specific details, and the system b e c o m e s more flexible. A working system can be modified, adjusted, a n d so o n , l o n g after it's "finished." Instances of n e w types can be a d d e d to the system easily without disrupting it. Many languages can easily handle small- to medium-size programs, but the real problems begin w h e n the programs get big. Windows applications are big by default. Turbo Pascal (with extensions for separate compilation) enables y o u to program "in the large." Turbo Pascal for Windows allows y o u to encapsulate into an object the data and operations n e e d e d to handle a window. Extended Views It's helpful to think of an object as a little program. A n object has its o w n data (like a program) and an interface for sending and receiving messages. Y o u use programs such as a text editor (an object), which manages its o w n data (characters and words). Using a keyboard or a m o u s e , y o u send the text editor messages such as " a p p e n d a specific character" or "move back to the previous word." Each object of your program handles a task. S o , an object-oriented program is similar to a multitasking environment. Y o u might use a c o m m u n i - cation program to send and receive files (data), a database to store it, a spreadsheet to analyze it, and a desktop publishing system to format it. Although y o u can (in theory at least) write spreadsheets and database systems yourself, y o u don't have to (nor d o y o u usually want to!); y o u save time and effort by using programs s o m e o n e else has written. When y o u request s o m e data or action (a report or a recalculation by a spreadsheet, for example) y o u probably don't want to k n o w the specifics of how the spreadsheet handled the math. Y o u want the results. Creating programs out of objects works similarly. In effect, y o u "run" objects (just as y o u "run" programs) that manipulate their data. Y o u may write the c o d e for these objects or y o u may derive your objects from s o m e o n e else's. A n object-oriented program saves time and effort by enabling y o u to reuse existing objects. ObjectWindows is the library of existing objects y o u use to get to Windows programming. All the objects y o u n e e d to get started are c o d e d for y o u . T h e B a s i c l n t e r f a c e in Chapter 4, "Inheriting an Interface," uses (and extends) these objects. Y o u , in turn, use as m u c h o f t h e B a s i c l n t e r f a c e as y o u want and extend it for your o w n purposes. Y o u communicate with objects by sending them messages. A program, then, consists of objects and the messages you send them (see figure 3 5 ) .
  • 113. 3 — Objects for Windows 93 This view is consistent with h o w y o u should think about a Windows program. Each application (or program) running in a Windows w i n d o w is an object that sends and receives messages. When y o u want a task d o n e , y o u send a message to an application w i n d o w (an object), and it completes the task. Keyboard Mouse e v e n t s W i n d o w s Message Dispatcher ( U S E R . E X E ) Windows message application message A p p l i c a t i o n w i n d o w application message Windows message A p p l i c a t i o n w i n d o w Figure 3-5. Objects and messages. About Microsoft Windows Microsoft Windows has b e c o m e the graphical user interface (or GUI) of choice for a majority of P C users. Certainly, in the next few years, y o u should expect an explosion of Windows users and programmers. Windows is wonderful, powerful, and c o m p l e x , but it doesn't have everything yet. Its application lineup still has many positions to fill. Any programmer can benefit by adding Windows skills to her tool kit. Windows runs in graphics m o d e o n IBM PCs and compatibles. Windows is an interface, not an operating system, so it doesn't replace D O S ; instead it works with it. For example, Windows utilizes D O S for file I/O (see figure 3.6).
  • 114. 94 Parti—Working with TPW D O S + W i n d o w s I A p p l i c a t i o n " ! | A p p l i c a t i o n || A p p l i c a t i o n ! Win dows D O S M e m o r y F i l e s D O S h a n d l e s f i l e I/O; W i n d o w s , t h e r e s t . Figure 3-6. DOS plus Windows. There are m a n y excellent reasons for using Windows: • Because W i n d o w s offers a standard, consistent user interface, users d o not have to learn n e w cues and keystrokes to get u p to speed with n e w applications. T h u s , they can run many otherwise dissimilar applica- tions easier because there's less to learn. • W i n d o w s enables y o u to write device-independent applications. Y o u write generic c o d e that solves the p r o b l e m , and W i n d o w s takes care of running the application with various displays, printing to different kinds of printers, and so o n . • W i n d o w s allows applications to talk to each other. Not only can your applications send and receive messages to objects in themselves, but they also can send messages to and receive t h e m from other applica- tions you didn't even write. Y o u r application can tap into programs it didn't even k n o w about w h e n the programs were written. • W i n d o w s allows m o r e than o n e application and m o r e than o n e instance of an application to run simultaneously. Note: M o r e than o n e application is not using the C P U at the same time although they appear to be running simultaneously; it's a beautiful W i n d o w s illusion. • W i n d o w s enables applications to share m e m o r y (at least in appear- ance) by sharing c o d e .
  • 115. 3 — Objects for Windows 95 O n the d o w n side: • W i n d o w s requires a m o r e powerful computer, m o r e memory, a faster C P U , and a better graphics adapter. • Y o u , the programmer, must learn your way around an event-driven architecture and learn h o w to c o m m u n i c a t e with the W i n d o w s man- agement facilities. Y o u have access to a beautiful and powerful inter- face, but to really use it, y o u must understand its language. C and C + + programmers generally still must learn hundreds and hundreds of n e w function calls to make their W i n d o w s programs shine. T u r b o Pascal for W i n d o w s folks can use ObjectWindows and take hundreds of shortcuts. Windows Structure T h e functionality of W i n d o w s resides in W i n d o w s ' Application Programming Interface (or API), contained in three external library m o d u l e s . These m o d u l e s are part of the retail version of W i n d o w s . Thus, your applications d o not create W i n d o w s functionality, they simply tap into it. W h e n y o u write a W i n d o w s application using T u r b o Pascal for W i n d o w s , your application interacts with (and uses) the m o d u l e s • K E R N E L . E X E • G D I . E X E • U S E R . E X E behind the scenes. K E R N E L . E X E handles m e m o r y and resource management, scheduling, and interaction with D O S . G D I . E X E displays graphics o n the screen and printer. U S E R . E X E handles w i n d o w management, user input, and communications. Y o u don't n e e d to think of these m o d u l e s as separate entities w h e n y o u write your applications. F r o m your application's perspective, they're together—just W i n d o w s . Although a complete W i n d o w s application has the .EXE extension (TPW.EXE, for example), the .EXE isn't a typical D O S .EXE file. Because a Windows-compatible compiler attaches s o m e special information to the .EXE file, W i n d o w s can recognize and run it. A n application designed to run in W i n d o w s won't run in D O S without W i n d o w s ' support, but a D O S application might run in W i n d o w s . In addition to the c o d e the compiler attached to your .EXE (remember: you don't have to worry about it), even the simplest application y o u write for Windows must meet s o m e other minimal requirements. T h e application must at least
  • 116. 96 Parti—Working with T P W 1. Create a main w i n d o w . 2. B e able to c o m m u n i c a t e with Windows. 3. Close the w i n d o w . 4. Remove the w i n d o w w h e n it's n o longer n e e d e d . Because T u r b o Pascal for Windows is Windows-compatible, even without the ObjectWindows library, y o u c a n write a Windows-compatible application without ObjectWindows' support. T o write the application, y o u must handle many details that ObjectWindows usually handles for y o u . In general, y o u d o not want to bypass ObjectWindows, but because y o u might, y o u should take a quick look at the process. If y o u never bypass ObjectWindows, it helps to appreciate the work ObjectWindows is d o i n g f o r y o u "under the table." T h e c o d e is about 100 lines long (the equivalent C c o d e is about 80). See the complete c o d e in listing 3.1. If y o u are unfamiliar with the T u r b o Pascal for Windows I D E a n d are not sure h o w to run a program, review the discussion o f the I D E in Chapter 1, "Getting Started." Listing 3.1. Creating a window without ObjectWindows. { Basic Windows application written in Turbo Pascal without ObjectWindows } program Basics; { $R BASICS } uses WinTypes, { to use Windows API types } WinProcs; { to use API processes } const AppName = 1 Basics'; const { function About is a frill } idm_About = 1 0 0 ; { but shows basic wm_processing function About(Dialog: HWnd; Message, WParam: Word; LParam: Longint): Bool; export; begin About := True; case Message of { basic wm_ processing } wm_InitDialog: Exit;
  • 117. 3 — O b j e c t s for Windows 97 wm_Command: if (WParam = id_0k) or (WParam = id_Cancel) then begin EndDialog(Dialog, 1); Exit; end; end; About := False; end; function WindowProc(Window: HWnd; Message, WParam: Word; LParam: Longint): Longint; export; var AboutProc: TFarProc; begin WindowProc := 0 ; { intercept messages } case Message of { message responses } wm_Command: if WParam = idm_About then begin AboutProc := MakeProcInstance(@About, HInstance); DialogBox(HInstance, 'AboutBox', Window, AboutProc); FreeProcInstance(AboutProc); Exit; end; wm_Destroy: { destroy window } begin PostQuitMessage(0); Exit; end; end; WindowProc := DefWindowProc(Window, Message, WParam, LParam); end; { create a main window } procedure WinMain; var Window: HWnd; { HWnd is a handle for a window } Message: TMsg; { TMsg is in WinTypes } const WindowClass: TWndClass = ( { register window class } style: 0 ; lpfnWndProc: @WindowProc; { default window info } cbClsExtra: 0 ; cbWndExtra: 0; continues
  • 118. 98 Parti—Working with TPW Listing 3.1 continued hlnstance: 0; hlcon: 0; hCursor: 0; hbrBackground: 0; IpszMenuName: AppName; IpszClassName: AppName); begin { handle multiple instances } if HPrevInst = 0 then begin WindowClass.hlnstance := Hlnstance; { specify icon, cursor, and so on } WindowClass.hlcon := Loadlcon(0, idi_Application); WindowClass.hCursor := LoadCursor(0, idc_Arrow); WindowClass.hbrBackground :=GetStockObject(white_Brush); if not RegisterClass(WindowClass) then Halt(255); end; Window := CreateWindow( { create main window } AppName, 'Basic Windows w/o ObjectWindows', ws_OverlappedWindow, { default window } cwJJseDefault, cwJJseDefault, cw_UseDefault, cwJJseDefault, 0, 0, Hlnstance, { note the instance } nil); ShowWindow(Window, CmdShow); { show the window } UpdateWindow(Window); { update when necessary } while GetMessage(Message, 0, 0, 0) do { run the message loop } begin TranslateMessage(Message); DispatchMessage(Message); end; Halt(Message.wParam); end; begin WinMain; { create a main window } end.
  • 119. 3 — Objects for Windows 99 Figure 3 7 shows the window created by this code. Figure 3.7. The created window. Several "general" things happen to the application in this code: • It registers the window class, in the code beginning WindowClass: TWndClass = ( • It creates a main window in the code beginning Window := CreateWindow(....)) using stock or default attributes. • It shows the window ShowWindow(Window, CmdShow);. • It sets up a message loop to process Windows messages: while GetMessage(Message, 0, 0, 0) do begin TranslateMessage(Message); DispatchMessage(Message); end;. • The application halts ( Halt (Message .wParam);. • In the beginning it used a $R (resource) file uses $R BASICS. This directive makes the compiler link into a resource file. I discuss resources in Chapter 8. For now, if you do not have the Turbo Pascal for Windows Bible disk, just link in the GENERIC.RESfilethat came with your Turbo Pascal for Windows. The file worksfinefor this example. Note: Ifyou are using the IDE, Turbo Pascal for Windows automatically links in any resources specified with $R.
  • 120. 100 Parti—Working with T P W It might surprise y o u that the code in listing 3 1 (despite its many lines) is hiding most of W i n d o w s ' complexity. What's h a p p e n i n g in CreateWindow, for example? ( H o w d o y o u s h o w a window?) T h e equivalent ObjectWindows application, with ObjectWindows d o i n g most o f the work, requires 16 lines (see listing 3.2). Listing 3-2. Creating a window with Ob j ectWindows. program BasicObjectWindowsAppl; { derive an application window using Object windows } uses WObjects, WinTypes, WinProcs; { All Object Windows programs use these units; actually, this program compiles using WObjects alone } type { Derive an application object from TApplication } { you must initialize a new main window or you get a nil window } App1 = object(TApplication) procedure InitMainWindow; virtual; end; { Construct Appl's MainWindow object } procedure App1.InitMainWindow; begin { window name here } { new gets a pointer to a TWindow } MainWindow := New(PWindow, Init(nil, 'Application 1')); end; { Declare an instance of type App1 } var Instancel: App1; { Run Instancel } begin
  • 121. 3—Objects for Windows 101 Instancel.Init('App1'); { init application instance } Instancel.Run; { message loop } Instancel.Done; { clean up } end. ObjectWindows gains many lines for you, but more important, it is encapsulating information in objects you do not need to understand in detail. Face it, you can retain only so much information in your brain for quick recall, so why not be spared a few details? Save yourself for the beans and potatoes of your applications. Why OOP and Windows Object-oriented programming (OOP) techniques hide program complexity in objects. Object-oriented libraries such as ObjectWindows package these objects. Specifically, ObjectWindows conceals the complexity of the Windows Application Programming Interface (API). With ObjectWindows, you don't need to understand the Windows API from the bottom up. You don't need to learn and place dozens offunction calls to create a window. Instead, you just need to know that predefined object types in ObjectWindows handle it for you. You then use inheritance to extend these objects to make your application special. I mentioned that another more subtle link between Windows and O O P is that Windows is message based. Figure 3 8 illustrates this concept. A M e s s a g e - D r i v e n Architecture u s e r m e s s a g e s Windows application p r o g r a m m e r m e s s a g e s B o t h u s e r a n d p r o g r a m m e r s e n d m e s s a g e s t o a p p l i c a t i o n s . Figure 3-8. A message-driven architecture.
  • 122. 102 Parti—Working with T P W W i n d o w s treats user events (clicking the m o u s e , pressing a key) as messages that must b e dispatched to the correct application. T h e objects y o u derive using ObjectWindows c o m m u n i c a t e by responding to the messages they receive from W i n d o w s . Y o u r W i n d o w s application is c o m p o s e d o f objects that represent the c o m p l e x user-interface elements o f a W i n d o w s application. A w i n d o w is an object. A dialog is an object. A n application is a n object that sets u p the interface to W i n d o w s , a n d so o n (see figure 3 9 ) . A Window is an object that contains objects. | Y o u r W i n d o w Y o u r M e n u Y o u r D i a l o g Y o u r L i s t B o x Y o u r F i l e E d i t o r Figure 3-9- Several objects in one object. Because ObjectWindows is so conceptually compatible with W i n d o w s , it simplifies the learning o f the W i n d o w s event-driven operation. About Object Windows T h e p o w e r o f Windows lies in the 550 or so functions that comprise the Windows API. Recall a few functions from B A S I C S . PAS, required to set u p a basic w i n d o w : LoadIcon LoadCursor GetStockObj ect RegisterClass CreateWindow ShowWindow UpdateWindow GetMessage TranslateMessage DispatchMessage DefWindowProc
  • 123. 3 — Objects for Windows 103 W h e n a W i n d o w s application wants to change its appearance, or respond to user input, it sends a message to a W i n d o w s function. Typically, w h e n y o u write a W i n d o w s application without ObjectWindows (in C , for example), y o u send messages to these W i n d o w s functions directly. These messages specify the n u m e r o u s parameters required o f a W i n d o w s function, a n d they handle any other protocol required o f the function. T h e following fragment, for example, sends W i n d o w s an API CreateWindow message directly: Window := CreateWindow( AppName, 'Your Window Application Name', ws_OverlappedWindow, cwJJseDefault, cwJJseDefault, cwJJseDefault, cwJJseDefault, 0, 0, HInstance, nil); Notice the complexity o f the CreateWindow message, which requires 11 parameters (see figure 3.10). These parameters are, in order, the ClassName, the W i n d o w N a m e , the WindowStyle, the Window's initial height a n d width (specified here by cwJJseDef ault), the window's parent (0 here because the w i n d o w has n o parent), a m e n u (0 here for n o n e ) , the Instance, a n d a pointer (nil here) for M D I w i n d o w s . Simple? N o ; this is o n e of the many reasons that y o u don't create W i n d o w s a n d applications without the help o f ObjectWindows. T h e equivalent ObjectWindows call looks something like this: MainWindow := New(PtrWindow, Init(nil, 'Your Window Application Name')); O t h e r ObjectWindows object types manage the message-processing a n d other behaviors required o f a W i n d o w s program. ObjectWindows simplifies the calling of W i n d o w s functions by repackag- ing the API in an object-oriented library. ObjectWindows encapsulates all the W i n d o w s information contained in the API. ObjectWindows abstracts the W i n d o w s API functions a n d automates message response. ObjectWindows handles any messages y o u don't want to handle directly, as s h o w n in figure 3.11.
  • 124. 1 0 4 Part I—Working with T P W C o n v e n t i o n a l W i n d o w s D e v e l o p m e n t c a l l A P I d i r e c t l y Windows API L o a d I c o n L o a d C u r s o r R e g i s t e r C l a s s C r e a t e W i n d o w S h o w W i n d o w Figure 3.10. Conventional Windows development. O b j e c t W i n d o w s W i n d o w s D e v e l o p m e n t Windows API L o a d I c o n L o a d C u r s o r R e g i s t e r C l a s s C r e a t e W i n d o w S h o w W i n d o w O b j e c t W i n d o w s ( o p t i o n a l ) O b j e c t W i n d o w s m a k e s it e a s i e r t o a c c e s s t h e W i n d o w s A P I . Figure 3-11- ObjectWindows Windows development. By encapsulating the details o f W i n d o w s in objects, ObjectWindows insulates y o u from m u c h o f W i n d o w s ' complexity. Most o f the parameter passing, setup, a n d so o n occurs u n d e r cover in ObjectWindows. Y o u create an
  • 125. 3 — O b j e c t s for Windows 1 0 5 instance o f an object y o u n e e d in order to handle a job; the object handles it without your worrying about the details. Y o u also can think o f the ObjectWindows approach as a n indirect o n e . I n ObjectWindows are the objects y o u u s e t o create w i n d o w s , dialogs, controls, and s o o n . Y o u should keep in m i n d that in many cases, ObjectWindows is not actually implementing many o f its behaviors itself. Whenever it c a n , it has W i n d o w s d o the work. S o W i n d o w s handles many o f the details, another level away from the objects y o u create. I n fact, W i n d o w s is responsible for every physical element y o u see o n your c o m p u t e r screen. Let m e explain. ObjectWindows, for example, defines w i n d o w , dialog, a n d control objects y o u can utilize to create applications. ObjectWindows itself does n o t actually implement w i n d o w s , dialogs, a n d s o o n . It only represents them. ObjectWindows requests W i n d o w s to actually create t h e m o r remove t h e m from the screen. It supplies only the specific behavior and attributes of the objects. This distinction might seem confusing, b u t it's a n important o n e that helps y o u understand the ObjectWindows approach. T h e term used by Borland to define ObjectWindows objects is interface objects, and the visual elements (what y o u see o n your screen) are called interface elements. These t w o c o m p o n e n t s are connected by way o f a W i n d o w s handle (see figure 3.12). Object Windows defines object behavior. Interface objects Interface elements Windows implements the physical elements. Figure 3-12. Interface objects versus interface elements. W h e n y o u construct an interface object, ObjectWindows asks W i n d o w s to create the corresponding element. W i n d o w s creates the element and returns a handle that identifies the element throughout its life. This handle is used
  • 126. 106 Part I—Working with T P W any time a W i n d o w s function needs t o send a message t o the element. ObjectWindows stores this handle in a TWindows object field called HWindow, which y o u read m u c h m o r e about in the next chapter. Events, Messages, and Objects W i n d o w s is based o n a n event-driven architecture. W i n d o w s handles all user input (keyboard a n d mouse) as events, and generates a message corresponding to the event (see figure 3.13). Windows Messages generates a Windows mouse button message. wm_LButtonDown Windows routes messages to applications. Application Figure 3-13- Windows messages. For example, w h e n y o u click the left m o u s e button, W i n d o w s generates a left-button-down message (wmLButtonDown), where wm is a w i n d o w s message. W h e n y o u press a key, W i n d o w s generates a wmKeyDown message. T h e user's selection o f a m e n u item is also a n event. I n Chapter 4, "Inheriting an Interface," y o u learn h o w to define command-message response m e t h o d s for responding t o m e n u s . Events trigger W i n d o w s messages t o objects. W h e n these objects are derived from ObjectWindows, they can easily b e taught to respond to W i n d o w s messages. T h e user also can use the m o u s e to click various control buttons and select items from a list b o x (called C o n t r o l events). ObjectWindows makes it easy for your objects t o respond t o these events as well (again, m o r e o n this i n Chapter 4, "Inheriting a n Interface").
  • 127. 3 — O b j e c t s for Windows 107 Windows Messages There are m o r e than 100 standard W i n d o w s messages. W i n d o w s sends mes- sages t o applications i n response t o events. T h e application responds t o these messages a n d acts accordingly. W i n d o w s objects respond t o i n c o m i n g Win- d o w s messages (see figure 3.14). Windows objects respond to incoming messages. generates a Windows mouse button message. w m _ L B u t t o n D o w n Windows routes messages to windovxs objects send message baok to Windows A p p l i c a t i o n send message to other objeots. Figure 3.14. Windows objects respond to incoming messages. About WinCrt Before y o u get t o the heart of W i n d o w s p r o g r a m m i n g ObjectWindows-style, I should point o u t a quick a n d clean way t o get a T u r b o Pascal for W i n d o w s application u p and running in n o time at all. Because W i n d o w s doesn't support traditional text-oriented file I/O, w h e n y o u try to use your existing T u r b o Pascal programs t o read and write files, y o u receive a fatal error message. T h e way to utilize your existing c o d e and the simplest way to get a simple application running with T u r b o Pascal for W i n d o w s is t o use the WinCrt unit. WinCrt contains the control logic t o emulate a text screen i n a w i n d o w .
  • 128. 108 Part I—Working with T P W T h e WinCrt unit enables y o u to r u n standard T u r b o Pascal programs in W i n d o w s by adding o n e line o f code: uses WinCrt;. Y o u can't take advantage of c o m p l e x W i n d o w s features, but y o u can still use o l d c o d e that's text-based. This feature makes the transition to W i n d o w s programming easier. T h e following c o d e fragment demonstrates standard T u r b o Pascal input and output, using Writeln, Readln. Notice the repeat/until loops that the input a n d output e c h o until Input = 1 quit1 . 1 Quit' does not close the W i n d o w . T h e w i n d o w remains on-screen a n d is closed just as any W i n d o w is by way of the FileMenu (see listing 3.3). Listing 33- Using standard Turbo Pascal I/O. program WindCRTex; uses WinCrt; { Allows Writeln, Readln, cursor movement, and so on. } { This program demonstrates how to use the WinCrt unit to perform "traditional" screen I/O. This is the easiest way to build text mode programs that run in a window. } var Input : string[80]; F : text; begin Assign(F,'wincrtex.pas'); { Basic FILE I/O } Reset(F); { Note: no error checking } repeat Readln(F,Input); { Read a line of the file } Write(Input); { Write it to the screen } Writeln; Writeln('What do you say?'); { Interact with user } Readln(Input); Writeln('Got it... You said ', Input); until (Input = 'quit') or EOF(F); Close(F); { Close the file. } DoneWinCrt; { Destroys the CRT window } end. { so that the user doesn't } { have to close it manually } W h e n your application doesn't n e e d to use anything m o r e than a single "frill-less" w i n d o w a n d is text-based, the WinCrt route is definitely the easiest route to get a W i n d o w s application going.
  • 129. 3 — Objects for Windows 109 Using WinCrt eliminates the n e e d to write specific W i n d o w s c o d e — a plus in the short term, but limiting in the long term. T o use the many features provided by W i n d o w s to their fullest extent, y o u should g o b e y o n d the text- based w i n d o w i n g provided by WinCrt to the ObjectWindows library. That's where T u r b o Pascal for W i n d o w s shines. Movin' On That's e n o u g h information for an introduction. T h e next chapter develops a basic application a n d w i n d o w interface that I continue to u s e throughout the book. This Basiclnterface creates a main w i n d o w (through inheritance) a n d attaches dialogs, m e n u s , a n d controls to it. Use it as the starting point for all your W i n d o w s applications (I d o ) . W i n d o w s a n d objects are a great match: an interface a n d the tools for easily manipulating that interface. Putting the t w o together requires a little initial effort (and perhaps) a n e w programming point o f view, but the payoff for a little effort is m o r e than e n o u g h compensation. O O P is a powerful programming technique in the P C arena, and W i n d o w s is the most powerful p r o g r a m m i n g environment. T u r b o Pascal for W i n d o w s (with its ObjectWindows library) links the t w o in a pleasant, powerful I D E , fit for the princes a n d princesses o f programming like y o u a n d m e .
  • 130. 4CHAPTER INHERITING AN INTERFACE What the user and applications developer want today is a graphics-oriented user interface, multitasking capability, and hardware independence. Windows has come of age. William H . Murray, III and Chris H . Pappas Object-oriented programming languages (such as T u r b o Pascal for Windows) encourage y o u to change the way y o u think about developing applications. Using O O P techniques, y o u can design general (or base) object types, and your applications can inherit characteristics and behaviors from these base types. This inheritance results in your saving significant programming time and effort, because y o u write only the code that differs from the base type. ObjectWindows contains e n o u g h base types for y o u to create a complete W i n d o w s interface. Objects that create m e n u s for user responses, list boxes for user selections, file dialogs for opening and saving files, and editors for modi- fying files are a few ObjectWindows base object types that are ready to g o right out of the box. Eventually y o u will use most of the objects in ObjectWindows, so it's worth taking a look at h o w the objects fit together hierarchically. Figure 4.1 shows the ObjectWindows object hierarchy.
  • 131. 112 Parti—Working with T P W TObject (Base) TApplloation TScroller TWi ndowsOb iect TDialog TDlgWindow TFileDialog Tin putDialoq TWindow TMDIWIndOW TEditWindow TFileWindow TControl TButton TMDICIient T St at ic TEdit TScrollBar TLIStBox TComboHox TQroupBox TCheckBox TRadioButton O b j e c t W i n d o w s H i e r a r c h y Figure 4.1. The ObjectWindows hierarchy. ObjectWindows is a terrific library: easy to use and well thought out. You do have to specify the behaviors of menus, dialogs, boxes, and so on, but you don't have to specify what they look like or h o w they operate. Those details all are ready to be inherited by the objects you create using ObjectWindows. In addition, these behaviors can be defined outside your Turbo Pascal source code as resources (using the Whitewater Resource Toolkit packaged with Turbo Pascal for Windows, which is discussed in Chapter 8, "Resources and Control Objects," and in Reference O, "Object Graphics." You can modify them without necessarily modifying your source code—a definite plus when you develop large or generic applications. To include a menu, for example, your application 1. Loads a m e n u from a compiled resource file. 2. Specifies h o w the application should respond to a user's m e n u selections. To include a list box, your application 1. Loads a list box from a resource file. 2. Specifies what should go in the list and h o w the application should respond to list selections. To include other resources in your application, you follow a similar procedure.
  • 132. 4 —Inheriting an Interface 113 Any application you create using ObjectWindows starts from two basic objects in the library (TApplication and TWindow). You derive new applica- tions and windows from these base application and window objects. You don't have to reinvent the application or the window. You expend virtually no energy designing the look and feel ofyour application's interface. It already looks and feels like any other Windows application. You concentrate, instead, on the details of your specific application, making you, your boss, and your family happy. Because each application you create using TApplication and TWindow shares the c o m m o n attributes and behaviors of other Windows applications, both you and your users benefit. A user learns h o w to use a general interface (in this case, the Windows GUI), and comes up to speed in new applications much more quickly. You concentrate on the specific aspects of the application, not on h o w to use the interface. You don't have to rewrite an interface for each application. You reuse an existing one, adding the bells and whistles you need. Everybody wins, especially marketing. The Basiclnterfece It's worth repeating: Windows is a graphical user interface (a GUI). Every- thing—text, dots, fills, and pictures—are treated by Windows not as ASCII characters (DOS-style), but as pixels turned on and off in a display context (the Windows name for a painting surface). Dealing with pixels rather than characters empowers GUIs, but it also makes them difficult for application programmers. Every aspect of the applications you develop using Turbo Pascal for Windows and ObjectWindows must deal with pixels. You can use the WinCrt unit (described in Chapter 3, "Objects for Windows,") for simple text-oriented Windows applications, but for anything complex, your application must trans- late to pixels. Fortunately, using pixels is only slightly more difficult than using text. Amazing! In this chapter, you use the O O P concepts discussed in Chapter 2 to create a useful and powerful interface. After you have this Basiclnterface in your toolbox, you use it as a starting point each time you write a Windows application. It is general enough to use as is and simultaneously customizable. Each time you write a new application you concentrate on its details, and the Basiclnterface handles communications with Windows. The Basiclnterface consists of two big objects derived from TApplication and TWindow: 1. A n application 2. Its main window and the objects that are attached to it
  • 133. 114 Parti—Working with TPW T h e B a s i c I n t e r f a c e object (I call itWIF, for W i n d o w s InterFace) handles your application's low-level interactions with W i n d o w s , channeling messages back and forth between W i n d o w s and the application's main w i n d o w . T h e main w i n d o w , in turn, controls other w i n d o w objects (such as buttons, m e n u s , scroll bars, and boxes). For convenience, y o u k e e p the B a s i c l n t e r f a c e in a unit (WIF.PAS), which y o u include in each of your applications. This unit also manages the loading of other basic units and resources required by O b j e c t W i n d o w s — another detail y o u don't have to be concerned about. I build the B a s i c l n t e r f ace a c o m p o n e n t at a time, and s h o w the c o d e to y o u in pieces. T h e complete B a s i c l n t e r f a c e c o d e , ready to plug into your applications, is in listing 4.7, at the e n d of this chapter. Y o u r applications inherit all the behaviors and characteristics of the B a s i c l n t e r f a c e : communicating with W i n d o w s , creating and managing main and child w i n d o w s , interacting with the user, and so o n . Y o u sometimes n e e d to modify the B a s i c l n t e r f a c e abit (to specify responses to dialogs and m e n u selections, for example), but for many generic purposes, it works fine as is. Modifying the B a s i c l n t e r f a c e is easy, thanks to O O P techniques. Chapters 5 through 13 s h o w y o u h o w to extend the B a s i c l n t e r f a c e to handle m a n y different kinds of problems. Application and Window Objects Any W i n d o w s application must initiate and maintain a c o m m u n i c a t i o n link between itself and W i n d o w s . Recall from Chapter 3, "Objects for W i n d o w s , " that to set u p the basic machinery required to initialize a main w i n d o w in W i n d o w s and to set u p communications between your application and Win- d o w s requires about 100 lines of T u r b o Pascal for W i n d o w s c o d e , if your application sends messages to the W i n d o w s API directly. Although y o u can call the API (Application Programming Interface) directly each time y o u create an application, y o u usually don't want to because y o u can often achieve the same results in far fewer lines using ObjectWindows. Three units packaged with Turbo Pascal for Windows (WObjects, WinTy pes, and W i n P r o c s ) establish the interface between your applications and W i n d o w s . WObjects is the ObjectWindows object library. WinTypes and W i n P r o c s define the T u r b o Pascal for W i n d o w s function types and processes for sending messages to the W i n d o w s API directly. If your application sends messages to the W i n d o w s API only through ObjectWindows, it doesn't n e e d to include the WinTypes and W i n P r o c s units. T h e B a s i c l n t e r f a c e sometimes sends messages to the API directly, so it includes all three units. {Note: Including these units doesn't incur any extra overhead for the B a s i c l n t e r f a c e . T h e T u r b o Pascal for W i n d o w s compiler is smart and compiles only the c o d e actually used by your application.)
  • 134. 4 —Inheriting an Interface 1 1 5 The Basiclnterf ace consists o f t w o objects (BasicApplication a n d MainWindow). T h e BasicApplicat ion "owns" the MainWindow, but the two are distinct objects; they're not related hierarchically. Ownership o f this type is called an instance linkage. The BasicApplication is derived from the TApplication object (in ObjectWindows). T h e MainWindow is derived from the TWindow object (in ObjectWindows). The TApplication object in ObjectWindows already knows h o w to handle all of Windows' initialization f o r y o u . T h e only specific initialization the BasicApplication has to handle itself is to create a n e w MainWindow using inheritance (see figure 4.2). Inheriting an application T A p p l i c a t i o n Y o u r A p p l i c a t i o n Y o u r A p p l i c a t i o n a u t o m a t i c a l l y k n o w s e v e r y t h i n g T A p p l i c a t i o n k n o w s . Figure 4.2. Inheriting an application. Your first order of business in creating the Basiclnterfaceisto derive a BasicApplication object type from a TApplication object: type BasicApplication = object(TApplication) procedure InitMainWindow; virtual; end; The procedure InitMainWindow is virtual (thus, its behavior c a n b e overridden), defined originally as a TApplication m e t h o d . Each application derived from TApplication should override this m e t h o d :
  • 135. 116 Part I—Working with T P W procedure BasicApplication. InitMainWindow; begin MainWindow := New(PMainWindow, Init(nil, 'Basiclnterface')); end; InitMainWindow "connects" the BasicApplication to its MainWindow, b y w a y o f a pointer (PMainWinsdow). T h e T u r b o Pascal for W i n d o w s extended syntax for the New procedure enables y o u to specify the object type y o u want to create (a MainWindow) a n d construct it (using I nit) in o n e step. T h e MainWindow's default constructor (defined in TWindow) requires t w o parameters: nil (required for initialization purposes), a n d a n a m e for the application w i n d o w . This n a m e appears in the t o p border of the main window. T h e default Basiclnterface n a m e is simply Basiclnterface, but y o u c a n (obviously) change this n a m e easily. The Main Window The following c o d e shows h o w to derive a n e w main w i n d o w object from TWindow: type PMainWindow = "MainWindow; MainWindow = object(TWindow) end; This MainWindow object doesn't a d d any n e w behavior (yet!) to its ancestor, TWindow. T h e main w i n d o w simply appears with its n a m e — h i d i n g a m e n u with close, resize, move, and other options w h e n y o u run the application (see figure 4.3). This main w i n d o w (byway o f its connection to the BasicApplication) responds automatically to W i n d o w s messages (the keyboard, the m o u s e , a n d so o n ) a n d to user events (menu selections, check boxes, dialogs, a n d so o n ) . In almost all cases, your application wants to implement s o m e o f its o w n responses to specific W i n d o w s messages. N o problem. By beginning with a general main w i n d o w that can handle any W i n d o w s message automatically, y o u have to implement only the responses y o u want to specify. Y o u a d d only the behaviors y o u want to override by adding response methods to the basic main window. M o r e o n this in a m o m e n t .
  • 136. 4 —Inheriting an Interface 1 1 7 Figure 4.3. The default window of Window. Init. You can derive most ofyour applications from the Basiclnterface devel- oped in this chapter. Your applications that need to have more than one document open at a time can use a variation ofthe Basiclnterface set up for you in Chapter 5, "Putting Pictures in Windows." The variation uses a main window as well but calls it a parent window and attaches otherwindows (called children) to it. This many-window system is defined by the multi-document interface (or MDI). In sum, the Basiclnterface at its simplest is an application and a main window object, as illustrated byfigure4.4. To use these two objects: 1. Declare an instance (for example, a variable) of object type BasicApplication (but you don't create an instance of MainWindow!): var Applicationl : BasicApplication; 2. Construct it: Applicationl.Init('Applicationl1 ); 3. Set it in motion: Applicationl.Run; 4. Arrange for it to be destroyed when you finish with it: Applicationl.Done;
  • 137. 1 1 8 Parti—Working with TPW TApplication + T W i n d o w objects = W i n d o w application Your application (object) your window (object) Windows applic ation control, dialog, etc. objects Y o u link objects together to create a W i n d o w s application. Figure 4.4. Creating a windows application. Listing 4.1 shows the first phase (preliminary, but workable) of the B a s i c l n t e r f a c e (WIF1.PAS). Listing 4.2 shows a little program y o u use throughout this chapter to test the B a s i c l n t e r f a c e . Listing 4.1. The preliminary version of Basiclnterf ace. unit WIF1; { Contains Basic Windows application interface version 1 derived from ObjectWindows } interface uses WObjects, { ObjectWindows library of objects } WinTypes, { Windows types: for accessing the API } WinProcs; { Windows processes: for accessing the API } type BasicApplication = object(TApplication) { Derive an application object } procedure InitMainWindow; virtual; {Init a main window } end; PMainWindow = "MainWindow; { Pointer to a main window } MainWindow = object(TWindow) { Derive a main window } end;
  • 138. 4 —Inheriting an Interface 119 implementation procedure BasicApplication.InitMainWindow; begin MainWindow := New(PWindow, Init(nil, 'Basic Windows Interface')); end; end. { end unit } Listing 4.2. Testing the Basiclnterf ace. program Test_Interface; { A generic way to test each phase of interface development } uses WIF5; { Basiclnterface unit } var Applicationl: BasicApplication; { An instance of BasicApplication } { Run Applicationl } begin Applicationl.Init('Basiclnterface'); { init application instance } Applicationl.Run; { Message loop } Applicationl.Done; { Destroy application instance } end. { End test program } Notice that y o u don't have to write the Init, Run, o r Done methods yourself. T h e BasicApplication object inherited these m e t h o d s from TApplication. Details Although y o u don't n e e d to k n o w h o w Init, Run, a n d Done work, y o u might appreciate a brief explanation o f h o w they handle your application for y o u . W h e n y o u construct the basic application (Applicationl .Init), the T u r b o Pascal for W i n d o w s compiler checks whether it c a n send a message to Applicationl's constructor. Applicationl, in fact, doesn't have its o w n constructor. It inherited o n e (from TApplication), so the compiler sends the construct message to TApplication (the ancestor o f BasicApplication). Note: Applicationl is an instance of the object type (BasicApplication), not the object itself.
  • 139. 120 Parti—Working with T P W T h e TApplication constructor (Init) constructs the BasicApplication. Specifically, it sends a message to its ancestor TOb j ect. Init, the base object type or c o m m o n ancestor o f all ObjectWindows object types. T h e constructor then sets the ObjectWindows global variable (Application) to @Self, a n d several of the BasicApplication fields. These fields, like the constructor, were inherited by the BasicApplication from TApplication. Init sets the BasicApplication Name field to the application n a m e it received in the message (Applicationl .Init( 'Name here'). Init then sets to zero both the BasicApplication. HAccTable (for handle to a n accelerator table) and BasicApplication.Status fields. T h e n it initializes the MainWindow and KBHandlerWnd (for keyboard handler window) to nil. Finally, if this is the first instance of the application (there can b e m o r e than o n e instance—more o n this later in this chapter), Init sends a message to InitApplication (another default TApplication method) to handle any specific initialization for a first instance o f an application. In other words, w h e w . There's a lot going o n , and y o u don't have to think about most o f it. A BasicApplication is constructed with n o effort o n your part. In most cases, this automatic construction suffices, but your application can always override this default behavior if it needs to. Applicationl.Run, the message l o o p , is where the action is. Basically, the Run m e t h o d (again inherited from TApplication) is the dispatch message l o o p y o u saw earlier in the NoFrills.pas c o d e in Chapter 3, "Objects for W i n d o w s . " Run sends a message to its MessageLoop m e t h o d , which processes incoming Windows messages. The MessageLoop works automatically (of course), so again y o u can ignore the details o f its processing o f basic W i n d o w s mes- sages. Y o u can reimplement this MessageLoop, if you're trying to optimize your application (see Chapter 12, "Sharing Libraries"). Finally, w h e n Applicationl . receives a n end message (from W i n d o w s ) , it sends a message to its destructor (Applicationl . Done), which destroys the application instance. It's worth emphasizing that destructors don't destroy object types, they destroy instances (or variables) of the object. Y o u r application c a n create m o r e than o n e instance o f an object type. Figure 4.5 illustrates this concept, a n d the following adjustment to the Basiclnterface handles multiple instances: procedure BasicApplication.InitMainWindow; begin if FirstApplication then MainWindow := New(PMainWindow, Init(nil, 'Basic Windows Interface')) else MainWindow := New(PMainWindow, Init(nil,'Additional Instance of BI')); end;
  • 140. 4 —Inheriting an Interface 121 Init multiple instances Init Instance MainWindow Instance MainWindow Run MessageLoop •one Figure 4.5. Multiple instances of Init. Although many, if not most, ofyour applications need only one instance, some of them will need multiple instances. You should include these adjust- ments in the Basiclnterface. Listing 4.3 shows this new state of the Basiclnterface (WIF2. PAS) .Throughout this chapter, use the TEST_WIF. PAS code in listing 4.2 to test the new versions ofthe Bas ic I nt e rf ace. Listing 43. A revision of Basiclnterface. unit WIF2; { Contains Basic Windows application interface derived from ObjectWindows } interface uses WObjects, { ObjectWindows library of objects } WinTypes, { Windows types: for accessing the API } WinProcs; { Windows processes: for accessing the API } type BasicApplication = object(TApplication) { Derive an application object } FirstApplication : boolean; procedure InitMainWindow; virtual; { Init a main window } procedure InitApplication; virtual; end; continues
  • 141. 122 Part I—Working with T P W Listing 43- continued PMainWindow = "MainWindow; MainWindow = object(TWindow) end; implementation { BasicApplication method implementation } procedure BasicApplication.InitMainWindow; begin if FirstApplication then MainWindow := New(PMainWindow, Init(nil, 'Basic Windows Interface')) else MainWindow := New(PMainWindow, Init(nil,'Additional Instance of BI')); end; procedure BasicApplication.InitApplication; begin FirstApplication := True; end; end. Window Messages T h e BasicApplication object (derived from TApplication) does many things for y o u : • Sets u p the interface to W i n d o w s (BasicApplication. Init) • Handles the GetMessage-Dispatch Message l o o p in the (BasicApplication.Run) • Cleans u p (BasicApplication. Done) D u r i n g Run's message l o o p , messages sent to your application by Win- d o w s (called "Windows messages") are processed automatically. T h e n the MessageLoop m e t h o d sends a message to its sister m e t h o d , ProcessAppMsg, which in turn sends messages to three "translation m e t h o d s " that get "first crack" at processing W i n d o w s messages: 1. ProcessDlg handles dialogs without m o d e l s . 2. ProcessAccels handles accelerators. 3. ProcessMDIAccels handles accelerators for M D I applications.
  • 142. 4 —Inheriting an Interface 123 This message translation is also h a p p e n i n g behind the scenes; a n d unless y o u n e e d to optimize, for example, y o u can ignore this message translation. There are well over 100 W i n d o w s messages, and they all begin with the prefix wm_. They handle everything from keyboard- a n d mouse-event process- ing to u n d o i n g operations in edit controls, to notifying a w i n d o w that its size has c h a n g e d or that a m e n u item has b e e n selected. H e r e are a few examples: * wm_LButtonDown * wm_RButtonDown * wm_LButtonUp * wm_RButtonUp * wm_MouseMove * wm_ShowWindow * wm_Size * wm_SysCommand Y o u r application's main w i n d o w object is responsible for responding to these W i n d o w s messages, and it's handled for y o u automatically by default in a m e t h o d that MainWindow inherited from TWindow: DefWndProc, which supplies default actions for each W i n d o w s message. In most cases, your application is delighted that DefWndProc is d o i n g the work. It doesn't want to be bothered resizing and showing w i n d o w s , for example. Y o u don't want to be bothered writing all that c o d e . You're concen- trating o n the details of your specific application, not o n the interface. Sometimes, t h o u g h , y o u want to intercept a W i n d o w s message to specify a behavior. For example, say that y o u want to add your o w n m o u s e interface to your application. T o respond to user events (such as the m o u s e and the keyboard), your application intercepts specific W i n d o w s messages. T o intercept a W i n d o w s message, simply override (redefine) the TWindow methods, which MainWindow inherited, for the message you want your appli- cation to respond to—like this: p r o c e d u r e WMLButtonDown(var Msg: T M e s s a g e ) ; v i r t u a l w m _ F i r s t + wm_LButtonDown; Y o u then implement the m e t h o d , detailing its behavior: p r o c e d u r e WMLButtonDown(var Msg: T M e s s a g e ) ; b e g i n { d e t a i l r e s p o n s e h e r e } end; Each time your application's main w i n d o w receives a wmLButtonDown message, it responds with whatever behavior is specified in the overridden m e t h o d . T h e message won't reach the default behavior f o r the wm_LBu t t o n Down message specified by DefWndProc.
  • 143. 1 2 4 Part I—Working with TPW What about other messages, such as a wm_RBut ton Down? Y o u r application w i n d o w hasn't specifically defined a n e w response m e t h o d for them. N o problem. Y o u override only the messages y o u want. Y o u can override o n e or 50 messages; any message y o u don't define is passed to DefWindowProc automatically. It's a great system: y o u inherit all the behavior of an object (TWindow), and override only the behaviors y o u want to override. Because m o u s e events often generate messages your applications want to respond to, y o u should put them in the B a s i c l n t e r f a c e . For n o w , y o u only implement abstract methods for them that you will implement (override) later. A n o t h e r A d v a n t a g e o f O O P You can define methods for objects and compile them to test the Basiclnterf ace without implementing any of the methods. This "prototype style" is particularly handy for large programming projects. You can add message-response methods for mouse clicks to the Basiclnterf ace MainWindow object. Listing 4.4 shows the new version of the Basiclnterface (WIF3.PAS). Listing 4A. Version 3 of Basiclnterf ace. unit WIF3; { Contains Basic Windows application interface derived from ObjectWindows } interface uses WObjects, { ObjectWindows library of objects } WinTypes, { Windows types: for accessing the API } WinProcs; { Windows processes: for accessing the API } type BasicApplication = object(TApplication) { Derive an application object } FirstApplication : boolean; procedure InitMainWindow; virtual; { Init a main window } procedure InitApplication; virtual; end; PMainWindow = "MainWindow; MainWindow = object(TWindow)
  • 144. 4 —Inheriting an Interface 1 2 5 procedure WMLButtonDown(var Msg: TMessage); virtual wm_first + wm_LButtonDown; procedure WMLButtonUp(var Msg: TMessage); virtual wm_first + wm_LButtonUp; procedure WMRButtonDown(var Msg: TMessage); virtual wm_first + wm_RButtonDown; procedure WMRButtonllp(var Msg: TMessage); virtual wm_first + wm_RButtonUp; procedure WMMouseMove(var Msg: TMessage); virtual wm_first + wm_MouseMove; end; implementation { BasicApplication method implementation } procedure BasicApplication.InitMainWindow; begin if FirstApplication then { If instance flag is set } MainWindow := New(PMainWindow, Init(nil, 'Basic Windows Interface')) else MainWindow := New(PMainWindow, Init(nil,'Additional Instance of BI')); end; procedure BasicApplication.InitApplication; begin FirstApplication := True; { Set instance flag } end; { Abstract implementation of basic MainWindow Mouse events } procedure MainWindow.WMLButtonDown(var Msg: TMessage); begin end; procedure MainWindow.WMLButtonUp(var Msg: TMessage); begin end; procedure MainWindow.WMRButtonDown(var Msg: TMessage); begin end; procedure MainWindow.WMRButtonUp(var Msg: TMessage); begin end; procedure MainWindow.WMMouseMove(var Msg: TMessage); begin end; end.
  • 145. 126 Parti—Working with T P W Before abandoning W i n d o w s messages temporarily, note that y o u c a n define response m e t h o d s for any W i n d o w s message, not just m o u s e events as I've d o n e here. Y o u probably won't want to d o s o , however; most o f the messages your application handles directly through ObjectWindows. Display Contexts Before y o u a d d anything else to your Basiclnterface (dialogs a n d m e n u s are discussed later in this chapter and in Chapter 5, "Putting Pictures in W i n d o w s " ) , I want to digress a bit a n d briefly discuss several aspects of W i n d o w s program- m i n g that text-based Pascal programming hasn't likely prepared y o u for. T h e first of these y o u n e e d to k n o w about is a display context. T o draw text or graphics in a w i n d o w , y o u u s e a display context. A display context is an element (recall the element-object dichotomy) that represents the surface o f a w i n d o w . It's a data structure maintained by the W i n d o w s Graphics Device Interface ( G D I ) . W i n d o w s associates each display context with a specific display device: the screen, a printer, a n d so o n . T h e attributes o f a display context determine text color, background color, font, coordinate mapping, a n d so o n . Whether your application is writing text or drawing pictures, it first needs to obtain a handle to a device context. This handle is simply a n u m b e r that identifies the W i n d o w s display context, a n d is defined in the W i n d o w s type, HDC, in WinTypes. W i n d o w s actually manages all display contexts for applications, but each application must use a W i n d o w s display context to display text o r pictures (other than in a resource, that is). Because device contexts are memory- intensive, they n e e d to b e released as s o o n your application finishes with them. W i n d o w s allows only five display contexts to b e active in any single W i n d o w s session. It's a simple matter for your application to use a display context. T h e following c o d e shows the process: var DisplayContext : HDC; begin DisplayContext := GetDC(HWindow); { write or draw something } ReleaseDC(HWindow); end; Get Dc is a W i n d o w s API function that actually gets the display context for the interface element designated by the ObjectWindows handle (HWindow). Note also that your applications can't use the standard T u r b o Pascal Read, Readln, Write, a n d Writeln procedures to display text. They must use the W i n d o w s function TextPut to write to a display context:
  • 146. 4 —Inheriting an Interface 127 TextOut(DisplayContext,X,Y,S,StrLen(S)); where X and Y are the screen coordinates and S is a null-terminated string (required by W i n d o w s ) . I will talk about null-terminated strings in this chapter, in the section called "Pascal and C Strings," and s h o w y o u h o w to use display contexts in many examples in later chapters. Using Resources Another n a m e for the graphical elements that comprise your W i n d o w s applica- tion is resources. These resources (cursor shape, m e n u s , icons, and so on) are similar in all your applications, so it makes sense to store t h e m in files outside your source code and link them with your source c o d e w h e n y o u n e e d them. This process eases any modification without affecting your application c o d e . Recall from Chapter 3, "Objects for W i n d o w s , " that resources are linked in automatically w h e n y o u use the $R directive. Chapter 8, "Resources and C o n - trol Objects," also details the use of resources. T h e separation of PAS (Pascal) and RES (Resource) c o d e is a crucial aspect of W i n d o w s programming. Y o u write your applications in Pascal (as usual) by deriving applications (using O O P techniques). Y o u build and modify resources with the Whitewater Resource Toolkit (that c o m e s with T u r b o Pascal for W i n d o w s ) . Figure 4.6 illustrates this concept. P r o g r a m c o d e + R e s o u r c e s = Application code ( . P A S ) ( . I N C ) resources (.RES) application (.EXE) D e v e l o p i n g a W i n d o w s a p p l i c a t i o n i s a t w o - s t e p p r o c e s s . Figure 4.6. Developing a Windows application.
  • 147. 128 Part I—Working with TPW By separating c o d e and resources, y o u transfer management responsi- bility for resources from the source c o d e to W i n d o w s . Y o u r source c o d e wants to focus o n its specifics, not o n W i n d o w s , so this is neat packaging. Resources are data characterized by the following types: • Accelerators • Bit maps • Cursors • Icons • Dialog boxes • M e n u s • Strings A n accelerator is a key (or combination of keys) that y o u can use as a shortcut for making m e n u selections. For example, y o u can define an accelera- tor (Shift-Delete, for example) to replace a m e n u selection (Edit-Cut, for example). A bit m a p is a picture, or more specifically, the data representing a picture. It is m a d e u p of pixels (dots). A cursor is the object on-screen that represents the position for the next input. In text-based applications, a cursor is either a block, a line, or something in between. In W i n d o w s applications, a cursor is a 32-by-32-pixel bit m a p . A W i n d o w s cursor can b e o n e of many different shapes, and is itself a bit m a p . A n icon is the graphical screen element that represents your application program's state. Y o u select an icon from the W i n d o w s Program Manager's w i n d o w to run programs, for example. A n icon, too, is a bit m a p . A dialog box, which is a bit m o r e complicated, is an input screen (or window) for insertion of information in your application. The dialog b o x can be baritones or contain other W i n d o w s graphical elements (called controls). T h e resource data associated with a dialog b o x specifies the dialog box's size, screen location, and text labels. A m e n u displays application options and enables y o u to select o n e . T h e menu's resource identifies the order and n u m b e r of these options. Strings are text displayed by application m e n u s , dialog boxes, error messages, and so o n . Strings don't have to be specified as resources, but maintaining t h e m as resources helps keep your specific application c o d e and its visual aspects separate. Chapter 8, "Resources and Control Objects," details the use of the Resource Toolkit and the Resource W o r k s h o p . Until then, the B a s i c I nt e r f a c e loads existing resources that I've already designed a n d c o m p i l e d in a B a s i c l n t e r f a c e resource file (WIF. RES). It supplies the resources y o u n e e d
  • 148. 4 —Inheriting an Interface 129 for many applications, a n d saves your having to learn every aspect of W i n d o w s programming at o n c e . It's also another example o f not reinventing w h e n y o u don't have t o , a sub-theme o f The Tao of Objects. Until Chapter 8, "Resources a n d C o n t r o l Objects," all the resources y o u n e e d to use with the Basiclnterface c a n b e linked into your program using the $R compiler directive: $R WIF.RES If y o u feel y o u have to k n o w everything at o n c e , skip over to Chapter 8 for resource design details. T h e complete WIF.RES file (created with the Whitewater Resource Toolkit) is o n the disk in the back of this book. Y o u don't have to use WIF.RES to use the Basiclnterface, however. Until y o u get to Chapter 8, just use the COOKBOOK. RES resource file packaged with T u r b o Pascal for W i n d o w s . It does just fine. T o include the COOKBOOK.RES, use the $R directive: $R Cookbook.res Pascal and C Strings T h e W i n d o w s API requires that strings b e null-terminated, the format used by C. In other words, a string is represented as a sequence of characters terminated by a NULL (#0). T u r b o Pascal for W i n d o w s stores null-terminated strings as arrays o f characters: type NTstring = array[0..79] of Char; A null-terminated string in T u r b o Pascal for W i n d o w s c a n b e as long as 65,535 characters (a limitation i m p o s e d by D O S a n d W i n d o w s ) . T u r b o Pascal stores its standard strings in the "string" type; a length byte followed by a sequence o f as many as 255 characters. type TPstring = string[80]; Because W i n d o w s doesn't recognize T u r b o Pascal strings, your applica- tion must either use null-terminated strings exclusively o r convert any Pascal strings to null-terminated before passing t h e m to W i n d o w s (to display, for example). T h e strings unit supplied by T u r b o Pascal for W i n d o w s provides the conversion functions a n d a complete manipulation package for handling null- terminated strings.
  • 149. 130 Part I—Working with T P W S o m e o f the functions in the strings unit are • StrPas: Converts a null-terminated string to a T u r b o Pascal string • StrPCopy: C o p i e s a T u r b o Pascal string into a null-terminated string • StrPos: Returns a pointer to the first occurrence o f a substring in a null-terminated string (similar to Pos for T u r b o Pascal strings) • StrLower: Converts a null-terminated string to lowercase Twenty or so o f these functions are in the strings unit y o u n e e d to use if y o u display strings in W i n d o w s . A d d this unit to the Basiclnterface: uses strings A Few Rules Before y o u get o n with the Basiclnterface, let's s u m u p a few "rules" y o u n e e d to keep in m i n d w h e n y o u develop W i n d o w s applications. Y o u r application creates interface objects (using ObjectWindows), but allows W i n d o w s to handle the interface elements they represent. Y o u r application allows W i n d o w s to handle m e m o r y m a n a g e m e n t (dis- cussed in Chapter 9, "Memory Matters"). Y o u r application must define message-response m e t h o d s in order to intercept W i n d o w s messages (to process m o u s e events, for example). Y o u r applications must send a message to W i n d o w s G D I functions to draw graphics in a w i n d o w or print. Y o u r application uses resources compiled outside your T u r b o Pascal source c o d e to implement m e n u s , dialogs, a n d so o n . Adding Dialogs Most of your applications use the important resource, a dialog. Dialogs c a n b e m o d a l or modeless. W h e n W i n d o w s displays a m o d a l dialog application, execution in other w i n d o w s is suspended until the user responds to the dialog. In other words, the user cannot select o r u s e the parent w i n d o w (the MainWindow in the Basiclnterface) until she clicks o n the O K or Cancel option, which destroys the dialog. For D O S users, this situation is similar to using a PAUSE; nothing h a p p e n s until another key is pressed. Displaying a dialog that is modeless, o n the other h a n d , doesn't suspend application operation, a n d thus c a n b e used repeatedly during the life o f the application. In other words, the user doesn't have to click a button in the dialog to continue processing in other w i n d o w s .
  • 150. 4 —Inheriting an Interface 131 For now, add a modal dialog to the Basiclnterf ace, because that's the one needed most often. Adding a dialog to an application is basically a two-step process, and a simple one, thanks to ObjectWindows. In short, link a dialog resource to the Pascal application code that requests the dialog through the application's ExecDialog method. Windows actually creates the dialog box (a window) for the application. Your source code just defines its behavior and uses the standard dialog resources packaged with Turbo Pascal for Windows. Thus, most ofthe work has already been done for you. To use a standard input dialog: 1. Include the STDDLGS unit: uses StdDlgs 2. Construct and execute the dialog in one step that basically looks like this: var Applicationl : Basiclnterface; if ApplicationlA .ExecDialog(New(PInputDialog, Init(@Self, 1 then { handle dialog results } ExecDialog creates the dialog's (the interface object's) corresponding element by sending a message to the dialog object's Execute method. It checks first, though, to ensure that there's enough m e m o r y to create the dialog. Listing 4.5 (WIF4. PAS) shows the new version of the Basiclnterf ace with modal dialog capability. Figure 4.7 shows a screen produced by the code in listing 4.5. Listing 4.5- Basiclnterf ace with modal dialog capability. unit WIF4; { Contains Basic Windows application interface derived from ObjectWindows } interface uses WObjects, { ObjectWindows library of objects } WinTypes, { Windows types: for accessing the API } WinProcs, { Windows processes: for accessing the API } Strings, { Null-terminated strings unit } StdDlgs; { Standard dialogs unit } type BasicApplication = object(TApplication) continues
  • 151. 132 Parti—Working with TPW Listing 4.5- continued { Derive an application object } FirstApplication : boolean; procedure InitMainWindow; virtual; { Init a main window } procedure InitApplication; virtual; end; PMainWindow = "MainWindow; MainWindow = object(TWindow) DisplayContextl : HDC; { Handle to a display context } ButtonDown : boolean; constructor Init(AParent : PWindowsObject; ATitle: PChar); procedure WMLButtonDown(var Msg: TMessage); virtual wm_first + wm_LButtonDown; procedure WMLButtonUp(var Msg: TMessage); virtual wm_first + wm_LButtonUp; procedure WMRButtonDown(var Msg: TMessage); virtual wm_first + wm_RButtonDown; procedure WMRButtonUp(var Msg: TMessage); virtual wm_first + wm_RButtonUp; procedure WMMouseMove(var Msg: TMessage); virtual wm_first + wm_MouseMove; end; implementation { BasicApplication method implementation } procedure BasicApplication.InitMainWindow; begin if FirstApplication then MainWindow := New(PMainWindow, Init(nil, 'Basic Windows Interface')) else MainWindow := New(PMainWindow, Init(nil,'Additional Instance of BI')); end; procedure BasicApplication.InitApplication; begin FirstApplication := True; end; { New MainWindow constructor } constructor MainWindow.Init(AParent : PWindowsObject; ATitle : PChar); begin
  • 152. 4 —Inheriting an Interface 133 TWindow.Init(AParent, ATitle); {Send message to ancestor's constructor} ButtonDown := False; end; { Abstract implementation of basic MainWindow Mouse events } procedure MainWindow.WMLButtonDown(var Msg: TMessage); begin end; procedure MainWindow.WMLButtonUp(var Msg: TMessage); begin end; procedure MainWindow.WMRButtonDown(var Msg: TMessage); { popup dialog if Right Button down } var InputText : array[0..15] of char; begin if not ButtonDown then begin if Application".ExecDialog(New(PInputDialog, Init(@Self,'Messagel1 ,'Message2', InputText, SizeOf(InputText)))) = id_0k then begin { Deal with message here } end; end; end; procedure MainWindow.WMRButtonUp(var Msg: TMessage); begin end; procedure MainWindow.WMMouseMove(var Msg: TMessage); begin end; end.
  • 153. 134 Parti—Working with T P W Figure 4.7. A basic Windows interface screen. Adding a File Dialog A second type of dialog you u s e in any ofyour applications that work w i t h files is the file dialog. As you're no doubt expecting, putting a file dialog in your application is no trouble at all. Y o u just use the o n e that ObjectWindows provides; it is already complete for many purposes. To a d d a file dialog to the Basiclnterf a c e : 1. U s e the stdlgs unit (which is already being used in the Basiclnterface): uses Stdlgs 2. Include its corresponding resource file (the Basiclnterf ace is already using a resource file that handles file dialogs—WIF.RES): $R WIF.RES 3. Initialize the file dialog a n d send a message to it in o n e step (much the way y o u initialized a m o d a l dialog earlier): if ApplicationlA .ExecDialog(New(PFileDialog, Init(@Self,PChar(sd_FileOpen),AFile))) = id_0K then begin OpenFile(AFile); end;
  • 154. 4 —Inheriting an Interface 1 3 5 Figure 4.8 shows a File O p e n dialog. T h e File O p e n dialog uses a list b o x to display the files o n the current directory. T h e user can either type the file to o p e n it, or double-click the particular file. T h e file is then o p e n e d with O p e n F i l e . Figure 4.8. A file dialog example. P F i l e D i a l o g i s a pointer to the stock dialog defined in ObjectWindows. Two Kinds of File Dialogs File dialogs c o m e in two stock forms: 1. O n e for o p e n i n g files 2. O n e for saving files Specify the o n e y o u want in the name parameter of the constructor c a l l . For an o p e n file: s d _ F i l e O p e n For a save file: sd F i l e S a v e
  • 155. 136 Part I—Working with T P W Constants Another aspect of ObjectWindows p r o g r a m m i n g that many programmers working in D O S - b a s e d environments often ignore is the use of constants. ObjectWindows defines n u m e r o u s constants to represent c o m m a n d messages: button, check box, and radio-button states; errors; child I D mes- sages; notification messages; streams messages; transfer flags; bit-mapped fields; and W i n d o w s messages. T h e use of constants improves program readability and makes it easier for a program to change in response to changes in subsequent versions of W i n d o w s . T h e complete B a s i c l n t e r f a c e in listing 4.7 (WIF.PAS) at the e n d of the chapter defines many of the most c o m m o n l y used constants. Y o u can, of course, c o m m e n t out the ones that your application doesn't n e e d and add the ones it does. T h e constant section in the B a s i c l n t e r f a c e serves as a handy template for adding your o w n constants. Controls At this point, the B a s i c l n t e r f a c e uses a simple (almost default) main w i n d o w (precisely, a main w i n d o w plus a m e n u ) . T h e main w i n d o w can be m u c h m o r e complicated, however, by other w i n d o w objects and controls. For example, y o u can vary the style, colors, and so o n , of the main w i n d o w and attach various child w i n d o w s to it. Future examples s h o w y o u h o w to add and vary these w i n d o w objects, which aren't necessary for the B a s i c l n t e r f a c e . For n o w , however, y o u should be aware of what controls are and h o w they're used. Controls are user interface devices. Table 4.1 shows the controls that ObjectWindows supports. Table 4.1. Windows controls supported by ObjectWindows. Control Object Type C h e c k b o x T C h e c k B o x C o m b o b o x T C o m b o B o x Edit control TEdit G r o u p b o x T G r o u p B o x List b o x TListBox M D I client T M D I C l i e n t P u s h button T B u t t o n Radio button TRadioButton Scroll bar TScrollBar Static control TStatic
  • 156. 4 —Inheriting an Interface 137 Figure 4.9 shows what a few of these controls look like. Figure 4.9. Combo box controls. Creating a control is another two-step process: 1. Construct the control object. 2. Construct its corresponding control element. Usually, you take both of these steps in the constructor of the parent window. For example, the following fragment constructs a push button: PB1 := New(PButton, Init(@Self, id_PB1, 'AButton', 30,50,300,19,False); Controls can send messages in response to user events (a user clicking a button,forexample). By default, ObjectWindows responds to these messages, if your application doesn't. Usually you want your application to handle the message itself, however. The following fragment shows h o w your application defines a response method to a button-clicked message: AMainWindow = object(MainWindow) PB1 : PButton; procedure IDPB1(var Msg: TMessage); virtual id_First + id_PB1; { other methods here } end;
  • 157. 1 3 8 Parti—Working with TPW T h e following fragment implements the IDPB1 m e t h o d : p r o c e d u r e AMainWindow.IDPB1(var Msg: T M e s s a g e ) ; b e g i n { r e s p o n s e h e r e } e n d ; T h e B a s i c l n t e r f a c e , as I said, doesn't include every control because controls are fairly specialized. Instead, I s h o w y o u h o w to use t h e m as y o u n e e d them, as y o u g o along. O n e I use often is the list box, which y o u learn h o w to use next. Adding list Boxes A list b o x is a kind of w i n d o w (it's defined by a rectangle o n the screen) that shows the user a list of information. T h e information can be integers, strings, and so o n . T h e user can click o n a list item, and the selected item can be transferred into another variable or can trigger other messages and actions. Figure 4.10 shows an example list box. Figure 4.10. A list box example. Listing 4.6 shows the c o d e required to create the list b o x displayed in figure 4.10.
  • 158. 4 —Inheriting an Interface 139 Listing 4.6. Code to create a list box. unit LBWind; interface uses Strings, WObjects, WinTypes, WinProcs; const id_LB1 = 201; id_BN2 = 203; type PListBoxWindow = "ListBoxWindow; ListBoxWindow = object(TWindow) LB1: PListBox; constructor Init(AParent: PWindowsObject; ATitle: PChar); procedure SetupWindow; virtual; { override TWindow's SetUpWindow } procedure IDLB1(var Msg: TMessage); virtual id_First + id_LB1; procedure IDBN2(var Msg: TMessage); virtual id_First + id_BN2; end; implementation constructor ListBoxWindow.Init(AParent: PWindowsObject; ATitle: PChar); begin TWindow.Init(AParent, ATitle); DisableAutoCreate; Attr.Style := ws_PopupWindow or ws_Caption or ws_Visible; Attr.X := 100; Attr.Y := 100; Attr.W := 200; Attr.H := 200; LB1 := New(PListBox, Init ((aSelf, id_LB1, 20, 20, 180, 80)); end; procedure ListBoxWindow.SetupWindow; begin TWindow.SetupWindow; { Fill the list box with strings } LB1A .AddString('Alison'); LB1".AddString('Marci'); LB1".AddString('Lizzie'); LB1".AddString('Amy'); continues
  • 159. 140 Part I—Working with T P W Listing 4.6. continued LB1A .AddString('Tammy1 ); LB1A .AddString('Susan'); LB1A .SetSelIndex(0); end; { A generic example of doing something with the list box } procedure ListBoxWindow.IDLB1(var Msg: TMessage); var SelString: array[0..25] of Char; begin if Msg.LParamHi = lbn_DblClk then begin LB1A .GetSelString(SelString, 25); end; end; procedure ListBoxWindow.IDBN2(var Msg: TMessage); begin CloseWindow; { Clean up } end; end. List box is a w i n d o w object y o u construct at specific coordinates, with a specific style, after sending a message to the base w i n d o w object type, TWindow, to handle default construction: constructor ListBoxWindow.Init(AParent: PWindowsObject; ATitle: PChar); begin TWindow.Init(AParent, ATitle); DisableAutoCreate; { So that you can create your own style } Attr.Style := ws_PopupWindow or ws_Caption or ws_Visible; Attr.X := 100; Attr.Y := 100; Attr.W := 200; Attr.H := 200; LB1 := New(PListBox, Init((PSelf, id_LB1, 20, 20, 180, 80)); end; Y o u then set u p the list b o x by adding strings: procedure ListBoxWindow.SetupWindow; begin TWindow.SetupWindow; { Fill the list box }
  • 160. 4 —Inheriting an Interface 141 LB1A .AddString('Alison'); LB1*.AddString('Marci'); end; T h e example in listing 4.6 loads the strings y o u want to add to the List Box from the source c o d e , but a m o r e general approach adds the strings in response to o n g o i n g c h a n g e s — f o r example, user input, based o n a change in the application itself, or a file f c r examples. In Chapter 6, "Painting, Collecting, a n d Streaming," w h e n streams are discussed, the ListBox is used in a m o r e interesting manner. T h e ListBoxWindow. IDLB1 m e t h o d handles m o u s e d o u b l e clicks, but at this point, it doesn't d o anything useful. It's just a generic example of h o w y o u might use it. I n Chapter 7, "Many Windows: A Multi-Document Interface," y o u add a help w i n d o w to the basic M D I interface that uses the list b o x w i n d o w to provide help information. T h e ListBoxWindow. IDBN2 m e t h o d destroys the list b o x w h e n the user clicks the Close b o x in the upper-left corner o f the list b o x w i n d o w : procedure ListBoxWindow.IDBN2(var Msg: TMessage); begin CloseWindow; { clean up } end; Message Boxes Although ObjectWindows does an amazing a m o u n t of work for y o u , sometimes y o u want to bypass ObjectWindows a n d send messages to the API directly. Y o u d o this by using the WinTypes a n d WinProcs units in your source c o d e : uses WinTypes, WinProcs T h e Basiclnterface already uses these units, but y o u still n e e d to include them in any n e w unit that needs to access t h e m directly. A particularly helpful example o f sending messages to the API is to p u t a message b o x o n the screen. Figure 4.11 shows a message b o x that the following fragment (added to the Basiclnterface) created: var MessageResponse : integer; begin MessageResponse := MessageBox(HWindow... end;
  • 161. 1 4 2 Parti—Working with T P W Figure 4.11. Popping up a message box. Closing an Application Typically, Windows applications terminate when the user double clicks the control-menu box in the upper-left corner of its main window. W h e n this happens to an application derived from the Basiclnterface, a number of messages are sent and received by the BasicApplication and MainWindow before BasicApplication is destroyed by destructor, Done. For the most part, you can ignore the complex processing that goes on behind the scenes. ObjectWindows does the work again. One addition to the Basiclnterface is helpful for double-checking whether the user of your application actually intended to quit. To double-check, reimplement (override) the MainWindow's CanClose method (that it inherited from TWindow). The following code does the trick: function MainWindow.CanClose: Boolean; var UserResponse; begin CanClose := True; UserResponse := MessageBox(HWindow, Message"! ,Message2, mb_YesNo or mb_IconQuestion); if UserResponse = idYes then CanClose := false; end;
  • 162. 4 —Inheriting an Interface 1 4 3 Wrapping Up the Basiclnterface That does it for the basics of W i n d o w s application programming, T u r b o Pascal for W i n d o w s style. There's m u c h m o r e to it than can be covered in these two chapters, but the rest is gravy. F r o m here o n I talk about varying the interface to handle the multi-document interface ( M D I ) , h o w to use other objects in the ObjectWindows library, and h o w to create many different kinds of applications using the B a s i c l n t e r f a c e . T h e complete B a s i c l n t e r f a c e consists of • A basic application • A main w i n d o w • A generic m o u s e interface • A m e n u and other basic resources • Methods for adding dialogs • A n awareness of device contexts • A few time-savers such as constant definitions, w i n d o w s message definitions, inclusion of key units, and so o n . Figure 4.12 shows the complete interface on-screen. Figure 4.12. The complete interface.
  • 163. 1 4 4 Parti—Working with T P W Listing 4.7 (WIF5.PAS) shows the Basiclnterface on-screen. Many applications (as I'11 show you) can begin with the Basiclnterface, and with little or no modification, run in Windows. By using aBasidnterface derived from ObjectWindows, you can ignore most ofthe hassles programmers traditionally associate with Windows development. Windows is a powerful environment, and ifyou use Turbo Pascal forWindows, you don't have to spend months and months coming up to speed in order to write many applications. Both user and programmer can have a powerful environment to work in without either of them going crazy. Let's hear it for Windows, object-oriented programming, and the language that brings them together: Turbo Pascal for Windows. W h o would have thought that programming Windows could be this easy? Listing 4.7. Code for the Basiclnterface on-screen. unit WIF5; { Contains Basic Windows application interface derived from ObjectWindows } interface uses WObjects, { ObjectWindows library of objects } WinTypes, { Windows types: for accessing the API } WinProcs, { Windows processes: for accessing the API } Strings, { Null-terminated strings unit } StdDlgs, { Standard dialogs unit } lbwind; { List box } {$R WIF.RES } const cm_New = 101; cm_Open = 102; cm_Save = 103; cm_SaveAs = 104; cm_Help = 901; id_LB1 = 201; type BasicApplication = object(TApplication) { Derive an application object } FirstApplication : boolean; procedure InitMainWindow; virtual; { Init a main window }
  • 164. 4 —Inheriting an Interface 145 procedure InitApplication; virtual; end; PMainWindow = "MainWindow; MainWindow = object(TWindow) DisplayContextl : HDC; { Display Context handle } ButtonDown : boolean; { Button-down status flag } constructor Init(AParent : PWindowsObject; ATitle: PChar); procedure WMLButtonDown(var Msg: TMessage); virtual wm_first + wm_LButtonDown; procedure WMLButtonUp(var Msg: TMessage); virtual wm_first + wm_LButtonUp; procedure WMRButtonDown(var Msg: TMessage); virtual wm_first + wm_RButtonDown; procedure WMRButtonUp(var Msg: TMessage); virtual wm_first + wm_RButtonUp; procedure WMMouseMove(var Msg: TMessage); virtual wm_first + wm_MouseMove; procedure ListBox(var Msg: TMessage); virtual cm_First + cm_Help; function CanClose: Boolean; end; implementation { BasicApplication method implementation } procedure BasicApplication.InitMainWindow; begin if FirstApplication then MainWindow := New(PMainWindow, Init(nil, 'Basic Windows Interface')) else MainWindow := New(PMainWindow, Init(nil,'Additional Instance of BI1 )); end; procedure BasicApplication.InitApplication; begin FirstApplication := True; end; { New MainWindow constructor } constructor MainWindow.Init(AParent : PWindowsObject; ATitle : PChar); begin continues
  • 165. 146 Part I—Working with TPW Listing 4.7. continued TWindow.Init(AParent, ATitle); { Send msg to ancestor's constructor } Attr.Menu := LoadMenu(HInstance, PChar(100)); { 100 = menu ID } ButtonDown := False; { Set status flag } end; { Abstract implementation of basic MainWindow Mouse events } procedure MainWindow.WMLButtonDown(var Msg: TMessage); begin end; procedure MainWindow.WMLButtonUp(var Msg: TMessage); begin end; procedure MainWindow.WMRButtonDown(var Msg: TMessage); { popup dialog if Right Button down } var InputText : array[0..15] of char; { Vary this for input length } begin if not ButtonDown then begin if Application".ExecDialog(New(PInputDialog, Init(@Self,'Messagel','Message2', InputText, SizeOf(InputText)))) = id_Ok then begin { Deal with message here } end; end; end; procedure MainWindow.WMRButtonUp(var Msg: TMessage); begin end; procedure MainWindow.WMMouseMove(var Msg: TMessage); begin end; procedure MainWindow.ListBox(var Msg: TMessage); var ListBoxWnd: PWindow; begin
  • 166. 4 —Inheriting an Interface 147 ListBoxWnd := New(PListBoxWindow, Init(@Self, 'List Box1 )); Application".MakeWindow(ListBoxWnd); end; function MainWindow.CanClose: Boolean; var UserResponse; begin CanClose := True; UserResponse := MessageBox(HWindow, Messagel,Message2, mb_YesNo or mb_IconQuestion); if UserResponse = idYes then CanClose := false; end; end.
  • 167. 5CHAPTER PUTTING PICTURES IN WINDOWS You can no longer think in terms of 25 lines and 80 columns of text. Charles Petzold It's worth repeating: W i n d o w s is a c o m p l e x environment, but not a difficult o n e in which to develop applications if y o u use T u r b o Pascal for W i n d o w s a n d the object-oriented techniques built into ObjectWindows. T h e Basiclnterface y o u developed in Chapter 4, "Inheriting an Interface," encapsulates most of the c o m p l e x details o f W i n d o w s programming in two objects: an application a n d its main w i n d o w . A simple way for y o u to develop n e w W i n d o w s applications is to 1. Derive the n e w application's interface from the Basiclnterface (using inheritance). 2. A d d the n e w application's specific behaviors to the derived interface. Y o u r application can focus o n its specific aspects while the Basiclnterface handles the underlying interface details. Because W i n d o w s is based o n an event-driven architecture, it makes sense to think o f your applications reacting to events (or even as being events). In other words, an application (an editor, a spreadsheet, or any other task)
  • 168. 150 Part I—Working with T P W responds to events it learns about through either W i n d o w s (wm) or c o m m a n d (cm) messages. A n application's response c a n b e a single action (displaying a dialog, a message or list b o x , a n d so o n ) , or a series o f actions (for example, a task consisting o f many functions a n d procedures). In other words, a n application running in a w i n d o w c a n behave exactly as it w o u l d if it weren't running in a w i n d o w . Because y o u allow the Basiclnterface or ObjectWindows (if y o u bypass the Basiclnterface a n d derive W i n d o w s behavior directly) to handle the interface details, your programming chore c a n b e reduced to t w o steps. These include writing the application (teaching it h o w to respond to events) and teaching it w h e n to respond to events. Y o u c a n teach your application to initiate its behavior by responding to various kinds of events. In Chapter 4, "Inheriting a n Interface," for example, y o u taught the Basiclnterface to respond in a general way to m o u s e events. O n e of the simplest a n d most useful ways to initiate an application's behavior, however, is to have it respond to a user selecting items from a m e n u . In this chapter, I focus o n this m e n u response aspect by deriving from the Basiclnterface several applications that respond to m e n u c o m m a n d mes- sages. I begin by showing the basics o f this approach, developing applications that simulate general tasks a n d using display contexts a n d W i n d o w s functions to display graphic images. I finally lead u p to a multitasking version o f the Basiclnterface. I use modeling systems, which are general-purpose, to s h o w y o u h o w y o u can develop your o w n multitasking system by plugging your applications into this version o f the Basiclnterface. In each example in this chapter y o u can associate a m e n u and its corre- sponding m e n u c o m m a n d messages to activate task w i n d o w s . M e n u s are an elegant a n d simple way to allow your users to control a W i n d o w s application. In the examples I lead y o u through, y o u find the user dynamically creating a n d destroying task w i n d o w s at run-time, w h e n y o u r programming effort is long g o n e . Menus, IDs, and Messages Each m e n u is a resource a n d also has a resource I D y o u use to identify the m e n u . Recall from the Ba s ic I n t e rf ac e that y o u attach a specific m e n u to a w i n d o w by 1. Including the m e n u resource. For example: {$R WIF.RES}
  • 169. 5 —Putting Pictures in Windows 151 2. Setting the m e n u attribute variable for the w i n d o w you're attaching the m e n u to: Attr.Menu := LoadMenu(HInstance, PChar(100)); Typically, y o u set the attribute in the window's constructor. For example: constructor ATask.Init(AParent: PWindowsObject; ATitle: PChar); begin TWindow.Init(AParent, ATitle); Attr.Style := ws_PopupWindow or ws_Caption or ws_Visible; Attr.Menu := LoadMenu(HInstance, PChar(99)); (* details here *) end; W h e n the main w i n d o w for an application is displayed, it appears with the m e n u corresponding to Att r. Menu's I D . Optionally, y o u could use a symbolic identifier to represent the m e n u , w h e n y o u set Attr. Menu: Attr.Menu := LoadMenu(HInstance, 'Taskl Menu1 ); Whetheryou use a PChar or a symbolic identifier with the Basic I nt e rf ace is u p to y o u . Y o u associate an I D with a m e n u using the Whitewater Resource Toolkit (see Chapter 8, "Resources a n d Control Objects," for the details of h o w to set u p a m e n u a n d give it a corresponding I D ) . Y o u also create the specific selections available in a m e n u in the resource file and test the m e n u in the Whitewater Resource Toolkit. However, the responses y o u want the application to make (in response to m e n u selections) must b e defined in your T u r b o Pascal source code. In other words, y o u specify a resource's attributes (in this case, a m e n u ) in the resource file, but y o u specify the specific responses an application makes to a m e n u in the T u r b o Pascal source c o d e file. This process o p e n s u p the possibility o f creating a n d testing m e n u s before y o u actually write the application. Y o u can develop the look a n d feel o f your application (prototype it) before y o u start writing c o d e ; a very useful prospect in developing large applications that involve m o r e than o n e programmer. W h e n a user selects a m e n u , the w i n d o w the m e n u is attached to receives a W i n d o w s c o m m a n d message. Y o u r application then processes the c o m m a n d message by defining a response m e t h o d for each selection. {Note: This is similar to h o w the Basiclnterface handles W i n d o w s c o m m a n d messages. Also note that W i n d o w s c o m m a n d messages are prefixed by wm_ a n d m e n u c o m m a n d messages by cm_; they represent entirely different classes o f messages.) A m e n u c o m m a n d message might look like this, for example: procedure CMNewMethod(var Msg: TMessage); virtual cm_First + 101;
  • 170. 152 Parti—Working with T P W where cmFirst is a constant (defined by ObjectWindows) designating the beginning of a range of c o m m a n d constants. 101 is the specific M e n u I D for this m e t h o d (CmNewMethod). For consistency, I use the cm_ prefix to n a m e any m e t h o d that responds to a c o m m a n d message, so it should b e easy to spot these methods within objects. Y o u can, if y o u want, use constants to represent these M e n u I D s , a n d substitute the constant for the I D . Again for consistency, I use the same prefix (cm_3 to designate any c o m m a n d message constant. For example: const cm_New = 101 procedure CMNewMethod(var Msg: TMessage); virtual cm_First + cm_New; The m e n u I showed y o u in the Basiclnterf ace (contained in WIF.RES) doesn't d o anything. It's there strictly in the abstract to s h o w y o u what a w i n d o w with a m e n u looks like. It is a simple matter to make the m e n u useful. T o make an application respond to m e n u selections: 1. Define a constant that corresponds to a m e n u message I D (in your T u r b o Pascal code). 2. Define a n d implement a m e t h o d that responds to the m e n u message (in your T u r b o Pascal code). 3. A d d the n e w m e n u selection option to the m e n u resource (using the Whitewater Resource Toolkit). The Basiclnterf ace already handles the application-Windows connec- tion, so y o u have to concentrate only o n h o w each n e w application works. Responding to events (menu c o m m a n d messages, m o u s e , a n d so forth) is the only Windows-specific aspect y o u have to worry about at this juncture. Because each application is associated with its main w i n d o w , and because I'm leading y o u u p to a mini-multitasking system within W i n d o w s (itself a multitasking system), your first response to a m e n u selection should b e the creation of a n e w w i n d o w (call it a child window) that contains the application. In other words, say that your m e n u option is called " T a s k l , " a n d the MainWindow's response to the user selecting T a s k l is to create a child w i n d o w that runs the task. Figure 5.1 shows the MainWindow with the T a s k l option. I want to keep the task simple for n o w . Say, for example, that this task simply outputs s o m e text in its w i n d o w in response to a m e n u selection. In bare- bones notation, the application accomplishes the equivalent o f a Write statement without going through the WinCrt unit. Start with the MainWindow y o u derived from TWindow in Chapter 4, "Inheriting an Interface," and derive from it a n e w w i n d o w object that responds to m e n u c o m m a n d messages. (Note that y o u don't have to start with
  • 171. 5 —Putting Pictures in Windows 1 5 3 MainWindow—you can, ofcourse, derive a new window directly from TWindow. MainWindow inherited all TWindow's characteristics and behaviors, and in addition has a characteristic you need: the Display Context. Therefore, you derive the new window from MainWindow. Figure 5.1. MainWindow with the Taskl option. This new window object, called TaskWindowl, consists of its o w n constructor and destructor, two datafieldsto represent screen coordinates, and a method to iterate the task. I call the method by the general name, cm_Iterate, using the cm_ prefix to indicate that it responds to a m e n u c o m m a n d message. It looks like this: PTaskl = "Taskl; { Pointer to this task } Taskl = object(MainWindow) { A simple task } X, Y : integer; { X and Y fields } constructor Init(AParent: PWindowsObject; ATitle: PChar); { New constructor} destructor Done; virtual; { New destructor } procedure CMIterate(var Msg: TMessage); virtual cm_First + cm_Task1; end; Notice that I've also defined a pointer to the TaskWindow (object). In general, you always construct a window using the New procedure that requires a pointer to an object, not the object itself. Because you're implementing a new constructor for TaskWindow, its ancestor's (TWindow) constructor is overridden, and thus not used. However,
  • 172. 154 Part I—Working with T P W TWindow's constructor initiates s o m e behavioryou don't want to reimplement. Y o u c a n send a message to it explicitly within TaskWindow's constructor a n d have it handle all that initialization for y o u . T h e n y o u can implement the specific behavior y o u want to a d d to TaskWindow. T h e constructor first sends a message to its ancestor's constructor, implementing a default w i n d o w for TaskWindow, a n d then loads a specific m e n u for TaskWindow by setting the m e n u attribute field: constructor Taskl.Init(AParent: PWindowsObject; ATitle: PChar); begin TWindow.Init(AParent, ATitle); { Send a message to ancestor's constructor } Attr.Menu := LoadMenu(HInstance, PChar(99)); { 99 = menu ID } end; Alternatively, the Taskl constructor c a n implement a specific kind and size o f window: constructor Taskl.Init(AParent: PWindowsObject; ATitle: PChar); begin TWindow.Init(AParent, ATitle); { Send message to ancestor's constructor } DisableAutoCreate; { Abort default window creation } { Create a specific window } Attr.Style := ws_PopupWindow or ws_Caption or ws_Visible; Attr.Menu := LoadMenu(HInstance, PChar(99)); { 99 = menu ID} Attr.X := 100; { Set window dimensions } Attr.Y := 50; Attr.W := 300; Attr.H := 200; end; N o w implement the task iterate m e t h o d , which has several responsi- bilities: 1. It makes sure that any cursor input is sent to the correct w i n d o w (TaskWindow) regardless o f where the m o u s e is located. 2. It gets a display context for TaskWindow. 3. It decides where to write the text within the w i n d o w . 4. It writes the text. 5. It releases the captured w i n d o w a n d display context: procedure Taskl.CMIterate(var Msg: TMessage); var S : array[0.14] of Char;
  • 173. 5 —Putting Pictures in Windows 1 5 5 begin X := Attr.X + 50; Y := Attr.Y + 50; EndX := X + 50; EndY := Y + 50; SetCapture(HWindow); { Certify the window } DC := GetDC(HWindow); { Get a display context } TextOut(DC,X,Y,S,SizeOf(S)); { Write something } ReleaseCapture; ReleaseDC(HWindow,DC); { Release display context } end; T h e display context is the surface o f the w i n d o w y o u have to specify in order to display text or graphics in a w i n d o w . Note also that S is a C-style (null-terminated) string, not a T u r b o Pascal string. W i n d o w s functions always require C-style strings, so if your applications use T u r b o Pascal strings, y o u always n e e d to convert t h e m before y o u use t h e m with W i n d o w s functions. T h e T u r b o Pascal for W i n d o w s strings unit contains a rich set o f C-style string-conversion a n d -manipulation functions. Part III, "Reference," details the functions. Figure 5.2 shows the default B a s i c l n t e r f a c e w i n d o w created by T W i n d o w . I n i t . F i g u r e 5.3 s h o w s t h e s p e c i f i c w i n d o w c r e a t e d b y TaskWindow. I n i t . Notice that the title a n d m e n u bars are different in the two figures. Figure 5.2. The default window of TWindow. Init.
  • 174. 156 Parti—Working with T P W Figure 53- A specific window created by TaskWindow. Init. Tasks It m a y seem overly complicated to create a w i n d o w just to output a line o f text, and o f course it is if that's all y o u ever plan to task. T h e goal o f this b o o k is to s h o w y o u general ways to create W i n d o w s applications easily. What you've just learned is in fact general e n o u g h to b e quite useful. I find it helpful to associate each w i n d o w with a task. Y o u might want to modify this approach as y o u b e c o m e m o r e experienced, but for m a n y projects, particularly as y o u discover your o w n route through W i n d o w s , one-task, o n e - w i n d o w works well. T h e task itself is an object that m a y implement dozens of m e t h o d s . Taskl just wrote a line o f text, but the mechanism you've just set u p to write a line o f text can serve as a blueprint for m u c h m o r e c o m p l e x tasking. Y o u could, of course, r e m o d e l the MainWindow (in the Basiclnterface) to reflect a n e w task. In other words, rather than derive a n e w Tas kWindow, y o u simply a d d the n e w fields (X a n d Y) a n d the n e w cmlterate m e t h o d to the MainWindow. In the simple case o f writing a line o f text, that's n o doubt what y o u w o u l d d o . For m o r e c o m p l e x tasks, adding specific functionality to the general type misses entirely the object-oriented approach. It is better t o create abstract types and use inheritance to derive n e w w i n d o w s , thus enabling task focus o n its o w n specific functionality.
  • 175. 5 —Putting Pictures in Windows 1 5 7 I've designed the Basiclnterface with this attitude in m i n d . Y o u use t h e Basiclnterfaceas your general (abstract) connection to Windows a n d derive a Specific Interface for your n e w applications or tasks. In this simple two-step process: 1. Y o u derive a n e w application from t h e Basiclnterface Application object a n d let it k n o w w h i c h w i n d o w it needs to k n o w about a n d use: TaskApp = object(BasicApplication) { TaskApp = a kind of BasicApplication } procedure InitMainWindow; virtual; { Init a specific MainWindow } end; { for the TaskApp } implementation procedure TaskApp.InitMainWindow; { Init a MainWindow for the Task } begin if FirstApplication then MainWindow := New(PTask1, Init(nil, 'Task Window Interface')) else MainWindow := New(PTask1, Init(nil,'Additional Instance of TWI')); end; 2. Derive a n e w MainWindow (object) that includes t h e n e w task: PTaskl = "Taskl; { Pointer to this task } Taskl = object(MainWindow) (* new task methods and fields here *) end; There's a (perhaps) subtle polymorphic aspect to this process. Notice that the I nit MainWindow constructs a n e w w i n d o w object type t h r o u g h the use of a pointer. Because t h e w i n d o w is constructed t h r o u g h a pointer t h e n e w w i n d o w type can b e any TWindow descendant. T h e InitMainWindow m e t h o d simply sends the message "construct a w i n d o w pointed to by t h e pointer." T h e functionality o f the w i n d o w c a n change a n d InitMainWindow is unaffected. It simply sends a general message (see figure 5.4). T h e task is set in m o t i o n w h e n t h e TaskWindow receives a c o m m a n d message generated by a m e n u selection. That is it for t h e T u r b o Pascal side o f things. When t h e m e n u message matching t h e constant c o d e is sent, t h e task is p u t in m o t i o n in its o w n window. Note that the w i n d o w has all the basic capability of a TWindow; it can b e resized, m o v e d , minimized, a n d so o n . Figure 5.5 shows t h e task w i n d o w (and task) created by t h e c o d e in listing 5.1.
  • 176. 1 5 8 Part I—Working with T P W I nitMainWindow Ptr to a window type TWindow MainWindow ModelWindow Figure 5.4. A kind of polymorphism. Figure 5.5. The task window (and task) created by listing 5.1.
  • 177. 5 —Putting Pictures in Windows 1 5 9 Listing 5.1. Code to create a task window and task. { contains two units: Writel, a task, and TaskWnd, to set up the task and a test program } unit Writel; { A model task } { responds to cm_Task1 (message) } interface uses WObjects, { Units specific to this unit } WinTypes, WinProcs, strings, StdDlgs, WIF5; { Basiclnterface : contains MainWindow } { : BasicApplication } type PTaskl = A Task1; { Pointer to this task } Taskl = object(MainWindow) { Time Series } X, Y : integer; constructor Init(AParent: PWindowsObject; ATitle: PChar); destructor Done; virtual; { Clean up } procedure cm_Iterate(var Msg: 'TMessage); virtual cm_First + cm_Task1; end; implementation constructor Taskl.Init(AParent: PWindowsObject; ATitle: PChar) ; begin TWindow.Init(AParent, ATitle); DisableAutoCreate; Attr.Style := ws_PopupWindow or ws_Caption or ws_Visible; Attr.Menu := LoadMenu(HInstance, PChar(99)); { 99 = menu ID } Attr.X := 100; { Set window dimensions } Attr.Y := 50; Attr.W := 300; Attr.H := 200; end; continues
  • 178. 160 Part I—Working with TPW Listing 5.Kcontinued procedure Task"! .cm_Iterate(var Msg: TMessage); { Act on menu's taskl (cm_) } begin X := Attr.X + 50; Y := Attr.Y + 50; SetCapture(HWindow); DC := GetDC(HWindow); { Get a display context } TextOut(DC,X,Y,'A writing Task',14); { Write something } ReleaseCapture; ReleaseDC(HWindow,DC); { Release display context } end; destructor Taskl.Done; begin TWindow.Done; { Call ancestor's destructor } end; end. { unit Writel } unit TaskWnd; { Sets up a Task } { Responds to cm_Task1 (message) } { Responds to cm_Task2 (message) } interface uses WObjects, { Units specific to this unit } WinTypes, WinProcs, strings, StdDlgs, WIF5, { Basiclnterface unit } { TaskList } writel; { Task 1 } {$R TASKWND.RES} { TaskWnd resource }
  • 179. 5 —Putting Pictures in Windows 161 type TaskApp = object(BasicApplication) { ModelApp = a kind of BasicApplication } procedure InitMainWindow; virtual; { Init a specific MainWindow } end; implementation procedure TaskApp.InitMainWindow; { Init a model application window } begin if FirstApplication then MainWindow := New(PTask1, Init(nil, 'Task Window Interface')) else MainWindow := New(PTask1, Init(nil,'Additional Instance of MI')) ; end; end. { unit TaskWnd } program Test_Interface; { A generic way to test each phase of interface development } uses WIF5, { Basiclnterface unit } taskwnd; { contains this TaskApp } type App = object(TaskApp) end; var Application: App; { An instance of BasicApplication } { Run Applicationl } begin Application.Init('Tasklnterface'); { init application instance } Application.Run; { Message loop } Application.Done; { Destroy application instance }end.
  • 180. 162 Parti—Working with T P W Note: It's not essential, but it is convenient, to associate o n e m e n u with each window. In other words, Taskl (the window) has an associate m e n u contained in the Taskl resource file (TASK1.RES). This association helps y o u keep your windows and m e n u s from straying t o o far from each other. T h e only detail left out is h o w to a d d the m e n u item. Chapter 8, "Resources a n d Control Objects," details resource creation, which in the case of adding m e n u selections, is very simple. In a nutshell, y o u o p e n the Whitewater Resource Toolkit M e n u Editor, o p e n a resource file, a d d the m e n u choice, a n d a d d its corresponding c o m m a n d code. Other Windows, Other Tasks N o w that you have a general task w i n d o w , what about adding m o r e tasks? Easily added. T h e process is more or less creating a n e w CMIterate m e t h o d for each task. For example, create a w i n d o w that displays text a n d draws a line: procedure Task2.CMIterate(var Msg: TMessage); begin X := Attr.X + 50; { Line dimensions } Y := Attr.Y + 50; EndX := X + 50; EndY := Y + 50; { Line dimensions } SetCapture(HWindow); DC := GetDC(HWindow); TextOut(DC,X,Y,'A writing Task1 ,14); DrawLine := LineTo(DC,EndX,EndY); ReleaseCapture; ReleaseDC(HWindow,DC); end; Model Tasks You're n o doubt noticing that text a n d graphics can b e displayed in a w i n d o w with similar ease. It's all pixels to a G U I like W i n d o w s . In general, y o u want to think o f your applications performing tasks in response to the messages they receive. The messages can c o m e from m e n u s , the m o u s e , the keyboard, ports, the application itself, a n d even other applications. In this next section, I show y o u h o w to set u p an abstract m o d e l task (or simulation) that demonstrates h o w y o u create your o w n specialized tasks. T h e n
  • 181. 5 —Putting Pictures in Windows 163 I s h o w y o u h o w to multitask by putting several m o d e l tasks in w i n d o w s that can be displayed simultaneously. In order for y o u to have a little fun with the tasks I develop here, I discuss m o d e l i n g in general and then eventually m o v e to o n e of the hottest topics in modeling: chaos theory. Modeling M o d e l i n g is a way to encapsulate s o m e part of a system's behavior in terms of the mathematical relationships a m o n g variables. O n e h o p e s that these variables encapsulate the system's behavior, and y o u select the variables y o u think are important in determining changes of state in the system. T h e n y o u stand back and watch the system change state. For example, in a two-dimensional system, with variables X and Y, y o u might say that the current state of Y is equal to three times the current state of X; or, in mathematical terms, Y = 3X. This is a simple linear m o d e l , and y o u can easily visualize h o w the system changes from state to state: Y is always three times as big as X . Figure 5.6 pictures this system's changing state. Figure 5.6. A linear equation. T o display this system in a w i n d o w , y o u can simply graph the values of Y for each increment in X. T o graph these changes of state, the task needs to implement several n e w data fields to represent screen coordinates, ranges to graph, initial values for variables, and methods for scaling and iterating the task.
  • 182. 164 Parti—Working with TPW Call this task Model 1 and define it this way, as a w i n d o w derived from MainWindow: PModell = "Modell; { Pointer to this task } Modell = object(MainWindow) { A Time Series model } { Task's data fields } InitX, InitY : real; { Initial points } RangeXI, RangeX2, RangeYI, RangeY2 : real; { Range to view } X, Y : integer; { Point to plot } A, B : real; { Factors for this model task } { Task's methods } constructor Init(AParent: PWindowsObject; ATitle: PChar); procedure Scale; { Scale point to window } procedure Iterate; { Iterate model task } destructor Done; virtual; { Clean up } procedure CMIterate(var Msg: TMessage); virtual cm_First + cm_Task1; end; Y o u i m p l e m e n t the m e t h o d s in a m o m e n t . For n o w , simply let App. InitMainWindow construct a Modell: procedure TaskApp.InitMainWindow; { Init a MainWindow for the Task } begin if FirstApplication then MainWindow := New(PModel1, Init(nil, 'Task Window Interface')) else MainWindow := New(PModel1, Init(nil,'Additional Instance of TWI')); end; Y o u have another task (this time a model) in a w i n d o w . Nothing n e w in this episode, but suppose that y o u want to set u p a m o r e general interface that allows y o u to multitask several w i n d o w s at o n c e . This requires two main steps: 1. Another layer of abstraction in the form of an intermediary w i n d o w that creates the various task w i n d o w s 2. A slightly m o r e c o m p l e x c o m m a n d message-response setup T h e intermediary (or setup) w i n d o w looks like this: PModelWindow = "ModelWindow;{ModelWnd is a kind of MainWnd } ModelWindow = object(MainWindow) constructor Init(AParent : PWindowsObject; ATitle : PChar); procedure CMTask1(var Msg: TMessage); virtual { run taskl } cm_First + cm_Task1; procedure CMTask2(var Msg: TMessage); virtual { run task2 } cm_First + cm_Task2; end;
  • 183. 5 —Putting Pictures in Windows 165 where CMTaskl and CMTask2 are response methods for m e n u c o m m a n d messages to construct and iterate each task. Figure 5.7 illustrates this concept. Figure 5.7. Taskl and Task2 on model windows interface. ModelWindow.CMTaskl looks like this: procedure ModelWindow.CMTaskl(var Msg: TMessage); var Taskl : PModell; { Pointer to a Task } begin Taskl := New(PModel1, Init(@Self, 'TimeSeries Model')); Application".MakeWindow(Task1); TasklA .cm Iterate; { Iterate the task } end; Responding to the cm_task1 message, CMTaskl constructs a Modell window and then iterates the model. ModelWindow.CMTask2 looks like this: procedure ModelWindow.CMTTask2(var Msg: TMessage); var Task2 : PModel2; { Pointer to a Task } begin Task2 := New(PModel2, Init(@Self, 'Henon Attractor')); Application".MakeWindow(Task2); Task2".Iterate; { Iterate the task } end;
  • 184. 166 Parti—Working with T P W Responding to the cm_task2 message, CMTask2 constructs a Model2 w i n d o w a n d then iterates the m o d e l . T o set this system in motion, have TaskApp. InitMainWindow construct a ModelWindow as its MainWindow rather than a specific m o d e l : procedure TaskApp.InitMainWindow; { Init a MainWindow for the Task } begin if FirstApplication then MainWindow := New(PModelWindow, Init(nil, 'Task Window Interface')) else MainWindow := New(PModelWindow, Init(nil,'Additional Instance of TWI')); end; That's all there is to it. N o t e that both Modell a n d the ModelWindow c a n respond to the same c o m m a n d message (cm_Task1). T h e same goes for Model2 a n d ModelWindow (cm_Task2). Note also that the same message sent to t w o different w i n d o w s results in different behaviors: polymorphism again. See listing 5.3 at the e n d o f this chapter for the implementation details. If the ModelWindow gets the cmTaskl message, it constructs a m o d e l a n d iterates it. If the Modell gets the cm_Task1 message, it iterates only itself (because it has already b e e n constructed!). C-o-o-o-1. Chaos and Strange Attractors N o w , just for f u n a n d because chaotic models are a fascinating way to explore the world, I discuss s o m e o f the theory b e h i n d Model2. In recent years, researchers in various fields that involve dynamics have used computers to m o d e l nonlinear systems that exhibit behavior not easily visualized n o r understood by just looking at the numbers. T h e key to under- standing many o f these systems is to uncover the attractors o f the system. A n attractor is, loosely, a state toward which a system evolves. Y o u find attractors in a computer-generated phase (or state) space. In state space, a point represents all the information y o u k n o w about a system's state, a n d the space itself is a picture o f a system's current state plotted against its next state (see figure 5.8). T h e key to understanding the system is to determine what state (or states) the system is evolving toward. Attractors "attract" a system. As the system evolves, the collection o f points that represent successive states c a n either: 1. Settle to o n e point (a point attractor). See figure 5.9. 2. Repeatedly return to a set o f points (a periodic attractor). See figure 5.10.
  • 185. 5 —Putting Pictures in Windows 167 3. Not return to a well-defined g r o u p of points, or return to a strange set of points (see figure 5.11). Figure 5.8. State space. Figure 5.9. A point attractor.
  • 186. 168 Parti—Working with TPW Figure 5.10. A periodic attractor. Figure 5.11. A strange attractor.
  • 187. 5 —Putting Pictures in Windows 169 T h e system evolves as the values of the current state b e c o m e the initial values of the next state. Each time, before each l o o p into the next state, the m o d e l records or plots the current system's state in phase space. M o d e l i n g systems (like tasking systems in general) are best described with object-oriented techniques for several reasons. It's easy to generalize the characteristics that models have in c o m m o n . Any m o d e l is a type of m o d e l , related to other models. F r o m a c o m p u t i n g perspective, models share low-level graphics primitives like points. They're all plotted in s o m e kind of space, although differing in h o w they generate states in that space. A dynamic system, which a m o d e l represents, can be anything • Y o u can describe by k n o w i n g the values of variables • W h o s e current state d e p e n d s o n its previous states T h e state of the system can b e something measured o n a continuous scale, something with logical changes (Is it yes? Is it on? H a s something h a p p e n e d since y o u checked last?), and so o n . In a speech-recognition system, o n e of m y favorite examples, each w o r d in the sentence carries s o m e individual weight and affects (and is affected by) all the other words in the sentence. In a sense o n e can consider a "sentence" to be a dynamic system that changes state through the addition of words and punctuation marks. Initially a sentence is empty. Y o u add a w o r d (the o n e w o r d is the n e w sentence). Y o u add a w o r d (the two words are the n e w sentence). Y o u add a w o r d (the three words are the n e w sentence). Y o u add a punctuation mark (three words plus punctuation = n e w sentence). A n d so o n . W h e n y o u speak, words necessarily follow each other. W h e n y o u write, they follow or displace o n e another (by replacing or being inserted between words). Each n e w state represents your attempts to clarify the state of the sentence. (As many of y o u k n o w , each n e w state can clarify or c o n f u s e — o n e reason that parsing sentences is so difficult.) Parsing is the breaking u p of sentences into c o m p o n e n t parts, usually for grammatical description. T h e sentence in its next state is very sensitive to its current state (or condition) and to its previous states. Y o u might say that "meanings" are the attractors in the dynamic system "sentence." At any state the sentence may have n o m e a n i n g (an extinction state), o n e m e a n i n g (a stable state), or many meanings (possibly a chaotic state). T h e m e a n i n g of the sentence d e p e n d s o n any n u m b e r of things—point of view, reading or writing skill, and so o n .
  • 188. 170 Part I—Working with T P W Mathematic Attraction Scientists (in mathematics, physics, engineering, biology, c o m p u t e r science, business, economics, a n d so o n ) are trying to understand dynamic systems. Their discoveries have led to at least o n e agreeable conclusion—anything o f interest that changes state is beautifully complex. Mathematicians a n d c o m p u t e r scientists try to twist m e a n i n g out o f c o m p l e x systems by representing t h e m with equations (or rules), a n d they visualize the system in pictures. S o m e particularly interesting pictures exist in phase (or state) space, where each point holds all the information n e e d e d to describe a dynamic system at any o n e time (or state). For example, suppose that a system varies (changes state) d e p e n d i n g o n a variable—such as size or number. Call the variable, X , a n d call its rate o f change, R. T h e n equations such as Nextx = R * X( * (1-X) can describe the system. In this case, the numeral 1 represents the system at s o m e m a x i m u m state and 0 represents the system at s o m e m i n i m u m state. Either extreme state (when Nextx = 1 o r O ) translates into an infinite state. T h e previous equation, the so-called "standard m a p " o~ "logistic equa- tion," has b e e n explored for many years by mathematically inclined folks in many fields. They've discovered that it (and presumably the dynamic system it describes) behaves unpredictably. In general, any system y o u describe with any nonlinear equation or equations behaves unpredictably. Logistic equations are unpredictable because they're extremely sensitive to initial conditions. Nearby values o f X in o n e state m a y lead to values (of Nextx) that are far apart in the next state. Y o u c a n complicate matters even m o r e by increasing the n u m b e r o f variables in a system (that is, o u r representation of a system). For example, these two rules for changes in state Nextx = AX - (1-(Y*Y*Y)) { 2 coupled nonlinear equations } Nexty = 1 - BY can present an "infinite" n u m b e r o f states (Nextx values) responding to infinitely small changes in the condition o f the previous state (or X value). This infinity o f values is the chaotic set for this dynamic system.
  • 189. 5 —Putting Pictures in Windows 171 Y o u can see this chaos easily by plotting the values of each state (Nextx) in time. (The X axis is time. T h e Y axis is the value of each X. See figure 5.12.) Figure 5.12. Chaos. Order in Chaos In even the most chaotic systems, there's an intriguing and often surprising order. O n e way to see this order is in phase space. W h e n y o u plot values of N e x t x against values of current X, y o u uncover the attractor for the chaotic set. This attractor occupies the phase space and is c o m p o s e d of all the points in the chaotic set. By mutual agreement it's called "strange." Figure 5.13 shows the strange attractor corresponding to the chaotic set in figure 5.12. Listing 5.2 shows the task c o d e to create this attractor.
  • 190. 172 Parti—Working with TPW Figure 5.13- Order in chaos. Listing 5.2. Code to create strange attractor in figure 5.13> unit Attract2; { Contains Henon Attractor } { Responds to cm_Task2 (message) } interface uses WObjects, { Units specific to this unit } WinTypes, WinProcs, strings, StdDlgs, WIF5; { Basiclnterface unit } {$R ATTRACT2.RES} const cm_ChangeFactor_A = 303; { 1 ' } type PModel2 = ~Model2; Model2 = object(MainWindow) { Henon Attractor }
  • 191. 5 —Putting Pictures in Windows 173 { Model's data fields } InitX, InitY : real; { Initial points } RangeXI, RangeX2, RangeYI, RangeY2 : real; { Range to view } X, Y : integer; { Point to plot } A, B : real; { Factors for this model } { Model's methods } constructor Init(AParent: PWindowsObject; ATitle: PChar); procedure Scale; { Scale point to window } procedure Iterate; { Iterate model } destructor Done; virtual; { Clean up } procedure cm_Iterate(var Msg: TMessage); { Iterate } virtual cm_First + cm_Task2; procedure cm_ChangeFactorA(var Msg: TMessage); virtual cm_First + cm_ChangeFactor_A; end; implementation const Iterations = 3000; { Number of iterations } constructor Model2.Init(AParent: PWindowsObject; ATitle: PChar); begin TWindow.Init(AParent, ATitle); Attr.Menu := LoadMenu(HInstance, PChar(102)); DisableAutoCreate; Attr.Style := ws_PopupWindow or ws_Caption or ws_Visible; Attr.X := 150; Attr.Y := 100; Attr.W := 300; Attr.H := 200; RangeXI := -1.03; { Set ranges to view } RangeX2 := 1.27; RangeYI := -0.3; RangeY2 := 0.45; A := 1 .4; { Set factors } B := 0.3; continues
  • 192. 1 7 4 Parti—Working with TPW Listing 5.2. continued InitX := 0.4; InitY := 0; X := 0; { Initial point in space } Y := 0; end; procedure Model2.cm_Iterate(var Msg: TMessage); begin Iterate; { Iterate the model } end; procedure Model2.cm_ChangeFactorA(var Msg: TMessage); var InputText: array[0..5] of Char; New_A : real; ErrorPos : integer; begin { Use dialog to change A factor } Str(A,InputText); if Application".ExecDialog(New(PInputDialog, Init(@Self,'Factor A',1 Input a new A Factor:1 , InputText, SizeOf(InputText)))) = id_Ok then begin Val(InputText,New_A,ErrorPos); if ErrorPos = 0 then A := New_A; end; end; procedure Model2.Scale; begin { Scale point in space to window } If (InitX = RangeXI) then { A little troubleshooting } X := Attr.X; If (InitX = RangeX2) then X := Attr.W; { And here } If (InitX = 0) then X := X; If (InitX > RangeXI) then X := round((InitX - RangeXI)/(RangeX2 - RangeXI) * (Attr.W - Attr.X)); Y := Attr.H - (round((InitY - RangeYI)/(RangeY2 - RangeYI) * (Attr.H - Attr.Y))); end; destructor Model2.Done; begin
  • 193. 5 —Putting Pictures in Windows 1 7 5 TWindow.Done; { Call ancestor's destructor } end; procedure Model2.Iterate; var I : integer; TempX, TempY : real; begin SetCapture(HWindow); DC := GetDC(HWindow); { Get a display context } for I := 1 to Iterations do begin TempX := InitX; { Save last state } TempY := InitY; { Save last state } InitX := TempY + 1 - (A * TempX * TempX); { this model } InitY := B * TempX; { this model } Scale; { Scale new state to a window } TextOut(DC,X,Y,'.1 ,1); { Draw a point } end; ReleaseCapture; ReleaseDC(HWindow,DC); { Release Display context } end; end. T h e fractal (or self-similar) nature o f the system b e c o m e s apparent w h e n y o u z o o m in o n any area of the attractor. T h e deeper y o u g o , t h e more c o m p l e x (and detailed) t h e attractor b e c o m e s , a n d yet t h e more orderly it seems. Grand Finale Listing 5.3 shows the complete code for this multitasking model system, in- cluding the specific c o d e for a chaotic m o d e l and a strange attractor. Figure 5.14 shows the display p r o d u c e d by this code. Deriving y o u r o w n m u l t i t a s k i n g f r o m this n e w v e r s i o n o f t h e Basiclnterface is a simple matter. A l t h o u g h a modeling system might not b e at all what y o u have in m i n d for your o w n applications, it's a general o n e that illustrates how easily y o u can create a multitasking system within Windows. Y o u simply create or derive your o w n tasks, define pointers to them, a n d then construct those w i n d o w s from the ModelWindow (the MainWindow for t h e multitasking system).
  • 194. 1 7 6 Parti—Working with T P W Note that I've adopted a useful convention of putting each separate task in its o w n unit. I don't know about you, but I easily lose track of where I keep objects. So a task per unit in many cases makes good sense to me. Chapter 13, "Designing Windows Applications," talks again about organization in regard to Windows applications. You, of course, decide what works best for you. Chapter 5, "Putting Pictures In Windows," closes with a reflection: Windows is a multitasking interface, so doesn't it makes sense that you can create your o w n multitasking system within Windows? ...Yes! Figure 5-14. The results of listing 53- Listing 53- Code for a chaotic model and a strange attractor. { This listing includes three units: timel attract2 modelwnd and a test interface program } { Timel } unit Timel; { A model task } { responds to cm_Task1 (message) } interface
  • 195. 5 —Putting Pictures in Windows 177 uses WObjects, { Units specific to this unit } WinTypes, WinProcs, strings, StdDlgs, WIF5; { Basiclnterface : contains MainWindow } { : contains BasicApplication } {$R TIME1.RES} { This task's new resources } type PModell = "Modell; { Pointer to this task } Modell = object(MainWindow) { Time Series } { Task's data fields } InitX, InitY : real; { Initial points } RangeXI, RangeX2, RangeYI, RangeY2 : real; { range to view } X, Y : integer; { Point to plot } A, B : real; { factors for this model task } { Task's methods } constructor Init(AParent: PWindowsObject; ATitle: PChar); procedure Scale; { Scale point to window } procedure Iterate; { Iterate model task } destructor Done; virtual; { Clean up } procedure cm_Iterate(var Msg: TMessage); virtual cm_First + cm_Task1; end; implementation const Iterations = 3000; { Number of iterations for this model } constructor Modell.Init(AParent: PWindowsObject; ATitle: PChar); begin TWindow.Init(AParent, ATitle); Attr.Menu := LoadMenu(HInstance, PChar(111)); DisableAutoCreate; Attr.Style := ws_PopupWindow or ws_Caption or ws_Visible; continues
  • 196. 1 7 8 Part I—Working with TPW Listing 53- continued Attr.X := 100; { Set window dimensions } Attr.Y := 50; Attr.W := 300; Attr.H := 200; RangeXI := -1.03; { Set ranges to view } RangeX2 := 1.27; RangeYI := -0.3; RangeY2 := 0.45; A := 1.4; { Set factors } B := 0.3; InitX := 0.4; InitY := 0; X := 0;