home *** CD-ROM | disk | FTP | other *** search
Text File | 2013-11-08 | 1.5 MB | 33,302 lines |
Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
- Microsoft Operating System/2: Programmer's Reference Volume 1
-
-
- ══════════════════════════════════════════════════════════════════════════
-
-
- Microsoft(R) Operating System/2: Programmer's Reference Volume 1
-
- Version 1.1
-
-
- ══════════════════════════════════════════════════════════════════════════
-
-
- Information in this document is subject to change without notice and does
- not represent a commitment on the part of Microsoft Corporation. The
- software and/or databases described in this document are furnished under a
- license agreement or nondisclosure agreement. The software and/or
- databases may be used or copied only in accordance with the terms of the
- agreement. The purchaser may make one copy of the software for backup
- purposes. No part of this manual and/or database may be reproduced or
- transmitted in any form or by any means, electronic or mechanical,
- including photocopying, recording, or information storage and retrieval
- systems, for any purpose other than the purchaser's personal use, without
- the written permission of Microsoft Corporation.
-
- (C) Copyright Microsoft Corporation, 1989. All rights reserved.
-
- Printed in the United States of America.
-
- Writers: Brad Hastings
- Stan Krute
- Donn Morse
- Ralph Walden
- Dan Weston
-
- The character-set tables in this manual are reprinted by permission from
- the IBM Operating System/2 User's Reference, (C) 1987 by International
- Business Machines Corporation.
-
- Microsoft(R), MS(R), MS-DOS(R), and the Microsoft logo are registered
- trademarks of Microsoft Corporation.
-
- IBM(R), Personal System/2(R), and PS/2(R) are registered trademarks of
- International Business Machines Corporation.
-
- Intel(R) is a registered trademark of Intel Corporation.
-
- PostScript(R) is a registered trademark of Adobe Systems, Inc.
-
- Document No. LN0702A-110-I00-0289
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Contents
-
-
- PART 1 Introducing MS OS/2
-
-
- Chapter 1 Introduction
- 1.1 Overview
- 1.2 About the MS OS/2 Programmer's Reference
- 1.3 How to Use This Manual
- 1.4 MS OS/2 and the C Programming Language
- 1.5 MS OS/2 Naming Conventions
- 1.6 Notational Conventions
-
- Chapter 2 MS OS/2 Overview
- 2.1 Introduction
- 2.2 MS OS/2 and Presentation Manager
- 2.3 The Window Manager
- 2.4 The Graphics Programming Interface
- 2.5 System Services
- 2.6 The MS OS/2 System Functions
-
- Chapter 3 MS OS/2 Programming Models
- 3.1 Introduction
- 3.2 Full-Screen Programs
- 3.3 Presentation Manager Applications
- 3.4 The Family Application Programming Interface
- 3.5 Using the Command Line
- 3.6 Using Structures
- 3.7 Using Bit Masks
- 3.8 Sharing Resources
- 3.9 C-Language Header Files
-
- PART 2 Window Manager
-
-
- Chapter 4 Windows
- 4.1 Introduction
- 4.2 About Windows
- 4.3 System-Modal Windows
- 4.4 Using Windows
- 4.5 Summary
-
- Chapter 5 Messages and Message Queues
- 5.1 Introduction
- 5.2 About Messages and Message Queues
- 5.3 Using Messages in an Application
- 5.4 Summary
-
- Chapter 6 Window Classes
- 6.1 Introduction
- 6.2 About Window Classes
- 6.3 Using Window Classes
- 6.4 Summary
-
- Chapter 7 Window Procedures
- 7.1 Introduction
- 7.2 About Window Procedures
- 7.3 Using a Window Procedure
- 7.4 Summary
-
- Chapter 8 Mouse and Keyboard Input
- 8.1 Introduction
- 8.2 About Mouse and Keyboard Input
- 8.3 Using the Mouse and Keyboard in an Application
- 8.4 Summary
-
- Chapter 9 Frame Windows
- 9.1 Introduction
- 9.2 About Frame Windows
- 9.3 Using Frame Windows
- 9.4 Summary
-
- Chapter 10 Control Windows
- 10.1 Introduction
- 10.2 About Control Windows
- 10.3 Using Control Windows in an Application
- 10.4 Creating a Custom Control Window
- 10.5 Summary
-
- Chapter 11 Title-Bar Controls
- 11.1 Introduction
- 11.2 About Title Bars
- 11.3 Using Title-Bar Controls in Applications
- 11.4 Default Title-Bar Behavior
- 11.5 Summary
-
- Chapter 12 Button Controls
- 12.1 Introduction
- 12.2 About Button Controls
- 12.3 Using Button Controls in an Application
- 12.4 Default Button Behavior
- 12.5 Summary
-
- Chapter 13 Entry-Field Controls
- 13.1 Introduction
- 13.2 About Entry-Field Controls
- 13.3 Using Entry-Field Controls in an Application
- 13.4 Default Entry-Field Behavior
- 13.5 Summary
-
- Chapter 14 List-Box Controls
- 14.1 Introduction
- 14.2 About List Boxes
- 14.3 Using a List Box in an Application
- 14.4 Default List-Box Behavior
- 14.5 Summary
-
- Chapter 15 Static Controls
- 15.1 Introduction
- 15.2 About Static Controls
- 15.3 Using Static Controls in an Application
- 15.4 Default Static-Control Behavior
- 15.5 Summary
-
- Chapter 16 Scroll-Bar Controls
- 16.1 Introduction
- 16.2 About Scroll Bars
- 16.3 Using Scroll Bars
- 16.4 Summary
-
- Chapter 17 Menus
- 17.1 Introduction
- 17.2 About Menus
- 17.3 Defining Menu Items in a Resource File
- 17.4 Menu Data Structures
- 17.5 Using Menus in your Applications
- 17.6 Summary
-
- Chapter 18 Accelerator Tables
- 18.1 Introduction
- 18.2 About Accelerator Tables
- 18.3 Accelerator Tables in a Resource-Definition File
- 18.4 Accelerator-Table Data Structures
- 18.5 Using an Accelerator Table in an Application
- 18.6 Summary
-
- Chapter 19 Dialog Windows
- 19.1 Introduction
- 19.2 About Dialog Windows
- 19.3 Dialog Data Structures
- 19.4 Dialog Resources
- 19.5 Using Message and Dialog Boxes
- 19.6 Summary
-
- Chapter 20 Painting and Drawing
- 20.1 Introduction
- 20.2 About Painting and Drawing
- 20.3 Strategies for Painting and Drawing
- 20.4 Printing
- 20.5 Summary
-
- Chapter 21 Drawing in Windows
- 21.1 Introduction
- 21.2 Window-Drawing Functions
- 21.3 Using Window-Drawing Functions
- 21.4 Summary
-
- Chapter 22 Mouse Pointers and Icons
- 22.1 Introduction
- 22.2 About Mouse Pointers
- 22.3 Using a Mouse Pointer in an Application
- 22.4 Summary
-
- Chapter 23 Cursors
- 23.1 Introduction
- 23.2 About Cursors
- 23.3 Using Cursors in an Application
- 23.4 Summary
-
- Chapter 24 Printing
- 24.1 Introduction
- 24.2 About Printing
- 24.3 Printing
- 24.4 Special Printing Topics
- 24.5 Summary
-
- Chapter 25 Heaps
- 25.1 Introduction
- 25.2 About Heaps
- 25.3 Using a Heap in an Application
- 25.4 Summary
-
- Chapter 26 Clipboard
- 26.1 Introduction
- 26.2 About the Clipboard
- 26.3 Using the Clipboard
- 26.4 Summary
-
- Chapter 27 Dynamic Data Exchange
- 27.1 Introduction
- 27.2 About Dynamic Data Exchange
- 27.3 Using Dynamic Data Exchange
- 27.4 Summary
-
- Chapter 28 Hooks
- 28.1 Introduction
- 28.2 About Hooks
- 28.3 Types of Hooks
- 28.4 Using Hooks
- 28.5 Hook Example
- 28.6 Summary
-
- Chapter 29 Help
- 29.1 Introduction
- 29.2 About Help
- 29.3 Using Help in an Application
- 29.4 Summary
-
- PART 3 Graphics Programming Interface
-
-
- Chapter 30 Presentation Spaces and Device Contexts
- 30.1 Introduction
- 30.2 About Presentation Spaces and Device Contexts
- 30.3 Using Presentation Spaces and Device Contexts
- 30.4 Summary
-
- Chapter 31 Coordinate Spaces and Transformations
- 31.1 Introduction
- 31.2 About Coordinate Spaces and Transformations
- 31.3 Using Coordinate Spaces and Transformations
- 31.4 Summary
-
- Chapter 32 Line and Arc Primitives
- 32.1 Introduction
- 32.2 About Line and Arc Primitives
- 32.3 Using Line and Arc Primitives
- 32.4 Summary
-
- Chapter 33 Fonts and Character Primitives
- 33.1 Introduction
- 33.2 About Fonts and Character Primitives
- 33.3 Using Fonts and Character Primitives
- 33.4 Summary
-
- Chapter 34 Color and Mix Modes
- 34.1 Introduction
- 34.2 About Color and Mix Modes
- 34.3 Using Colors and Mix Modes
- 34.4 Summary
-
- Chapter 35 Paths
- 35.1 Introduction
- 35.2 About Paths
- 35.3 Using Paths
- 35.4 Summary
-
- Chapter 36 Area Primitives
- 36.1 Introduction
- 36.2 About Areas and Area Primitives
- 36.3 Using Areas and Area Primitives
- 36.4 Summary
-
- Chapter 37 Marker Primitives
- 37.1 Introduction
- 37.2 About Marker Primitives
- 37.3 Using Markers
- 37.4 Summary
-
- Chapter 38 Bitmaps
- 38.1 Introduction
- 38.2 About Bitmaps
- 38.3 Using Bitmaps
- 38.4 Summary
-
- Chapter 39 Regions
- 39.1 Introduction
- 39.2 About Regions
- 39.3 Using Regions
- 39.4 Summary
-
- Chapter 40 Clipping
- 40.1 Introduction
- 40.2 About Clipping
- 40.3 Using Clipping
- 40.4 Summary
-
- Chapter 41 Metafiles
- 41.1 Introduction
- 41.2 About Metafiles
- 41.3 Using Metafiles
- 41.4 Summary
-
- Chapter 42 Segments and Retained Graphics
- 42.1 Introduction
- 42.2 About Segments and Retained Graphics
- 42.3 Using Segments and Retained Drawings
- 42.4 Summary
-
- PART 4 System Services
-
-
- Chapter 43 Processes, Threads, and Sessions
- 43.1 Introduction
- 43.2 About Processes, Threads, and Sessions
- 43.3 Using Processes
- 43.4 Using Threads
- 43.5 Summary
-
- Chapter 44 The Memory Manager
- 44.1 Introduction
- 44.2 About the Memory Manager
- 44.3 Using the Memory Manager
- 44.4 Summary
-
- Chapter 45 Dynamic Linking
- 45.1 Introduction
- 45.2 About Dynamic Linking
- 45.3 Building Dynamic-Link Libraries
- 45.4 Using Dynamic Linking
- 45.5 Summary
-
- Chapter 46 The File System
- 46.1 Introduction
- 46.2 About the File System
- 46.3 Using the File System
- 46.4 Summary
-
- Chapter 47 Video Input and Output
- 47.1 Introduction
- 47.2 About Video Input and Output
- 47.3 Using Video Input and Output
- 47.4 Summary
-
- Chapter 48 Advanced Video Input and Output
- 48.1 Introduction
- 48.2 About Advanced Video Input and Output
- 48.3 Using Advanced Video Input and Output
- 48.4 Summary
-
- Chapter 49 The Mouse
- 49.1 Introduction
- 49.2 About the Mouse
- 49.3 Using the Mouse
- 49.4 Summary
-
- Chapter 50 The Keyboard
- 50.1 Introduction
- 50.2 About the Keyboard
- 50.3 Using the Keyboard
- 50.4 Summary
-
- Chapter 51 Interprocess Communication
- 51.1 Introduction
- 51.2 About Interprocess Communication
- 51.3 Using Interprocess Communication
- 51.4 Summary
-
- Chapter 52 Timers
- 52.1 Introduction
- 52.2 About Timers
- 52.3 Using Timers
- 52.4 Summary
-
- Chapter 53 Window Timers
- 53.1 Introduction
- 53.2 About Window Timers
- 53.3 Using Window Timers
- 53.4 Summary
-
- Chapter 54 Device Monitors
- 54.1 Introduction
- 54.2 About Device Monitors
- 54.3 Using Device Monitors
- 54.4 Summary
-
- Chapter 55 Atom Tables
- 55.1 Introduction
- 55.2 About Atom Tables
- 55.3 Using Atom Tables in an Application
- 55.4 Summary
-
- Chapter 56 System Information
- 56.1 Introduction
- 56.2 About System Information
- 56.3 Using System Information
- 56.4 Summary
-
-
- ────────────────────────────────────────────────────────────────────────────
- Figures
-
- Figure 2.1 A Typical Presentation Manager Window
- Figure 11.1 Frame Window with Title Bar
- Figure 12.1 Button Types
- Figure 14.1 Typical List-Box Control
- Figure 17.1 Menu-Bar and Pull-Down Menus
- Figure 17.2 Submenus
- Figure 19.1 Sample Message Box
- Figure 19.2 Sample Dialog Box
- Figure 20.1 Application-to-Device Path
- Figure 20.2 Clip Region and Visible Region
- Figure 20.3 Update Region and Visible Region
- Figure 20.4 Cached-Micro Presentation Space
- Figure 20.5 Micro Presentation Space
- Figure 20.6 Normal Presentation Space
- Figure 21.1 Rectangle Types
- Figure 22.1 Bit Values in the AND and XOR Masks
- Figure 24.1 Application to Device Path
- Figure 24.2 World-Space to Device-Space Translation
- Figure 24.3 Portrait-Mode Pages in World Space
- Figure 24.4 Landscape-Mode Pages in World Space
- Figure 24.5 IBM4201 Page Setup
- Figure 25.1 Heap in Automatic Data Segment
- Figure 25.2 Back Pointer for Moveable Heap Object in Automatic
- Data Segment
- Figure 25.3 Back Pointer for Moveable Heap Object in Separate
- Data Segment
- Figure 27.1 Typical DDE Segment
- Figure 29.1 Help Menu Item
- Figure 31.1 Device Coordinate System
- Figure 31.2 Video Display and Single-Coordinate-Space System
- Figure 31.3 Diagonal Line in a Single-Coordinate-Space System
- Figure 31.4 One Rectangle Displayed on Two Different Devices
- Figure 31.5 Fixed Value
- Figure 31.6 Rotating an Object
- Figure 31.7 Subpictures in Four Chained Segments in World Space
- Figure 31.8 Two Model Spaces
- Figure 31.9 Viewing Limit in Model Space
- Figure 31.10 Retained Subpicture Drawn Using Model Transformations
- Figure 31.11 Clip Path in World Space
- Figure 31.12 Scaling the Clipped Part of a Subpicture in Model
- Space
- Figure 31.13 Presentation Page in Page Space
- Figure 31.14 Page Viewport in Device Space
- Figure 31.15 Determining Scaling Factors
- Figure 31.16 Translating the Page Viewport in Device Space
- Figure 32.1 Sample Illustrations Using Line and Arc Functions
- Figure 32.2 Arcs
- Figure 32.3 Transforming the Unit Circle Using the Arc Parameters
- Figure 32.4 Line Styles
- Figure 33.1 Strokes
- Figure 33.2 Serifs
- Figure 33.3 Bold Font
- Figure 33.4 Italic Font
- Figure 33.5 Normal Font
- Figure 33.6 Character Cell
- Figure 33.7 Em Height
- Figure 33.8 X Height
- Figure 33.9 Maximum Ascender
- Figure 33.10 Maximum Descender
- Figure 33.11 Lowercase Ascent
- Figure 33.12 Lowercase Descent
- Figure 33.13 Internal Leading
- Figure 33.14 External Leading
- Figure 33.15 Em Increment
- Figure 33.16 Maximum Baseline Extent
- Figure 33.17 Character Slope
- Figure 33.18 In-line Direction
- Figure 33.19 Character Rotation
- Figure 33.20 Superscript
- Figure 33.21 Subscript
- Figure 33.22 Image Font
- Figure 33.23 Outline Font
- Figure 33.24 Character-Cell Alignment
- Figure 33.25 Proportional and Fixed Fonts
- Figure 33.26 Code Page 437
- Figure 33.27 Character Shear
- Figure 33.28 Image Font and Character Shear
- Figure 33.29 Image Font and Character Angle
- Figure 33.30 Image Font and Three Sizes of Character Box
- Figure 33.31 Outline Font and Character Shear
- Figure 33.32 Outline Font and Character Angle
- Figure 33.33 Outline Font and Three Sizes of Character Box
- Figure 33.34 Graph with Outline Font
- Figure 35.1 Stroked and Filled Rectangles
- Figure 35.2 Geometric Lines and Normal Lines
- Figure 35.3 Stroked Paths
- Figure 35.4 Filled Paths
- Figure 35.5 Fill Modes
- Figure 35.6 Alternate-Mode Test
- Figure 35.7 Winding-Mode Test
- Figure 35.8 Triangular Clip Path
- Figure 35.9 Geometric Line Ends
- Figure 35.10 Geometric Line Joins
- Figure 36.1 Two Areas
- Figure 36.2 Disjoint Area
- Figure 36.3 Predefined Fill Patterns
- Figure 37.1 Default Marker Set
- Figure 37.2 Markers Used in a Graph
- Figure 38.1 Bitmap and Image
- Figure 38.2 Bitmap Shown on Two Displays with Different Aspect
- Ratios
- Figure 38.3 Bits and Pels in a Bitmapped Image
- Figure 38.4 A Bitcount and its Associated Color Table
- Figure 38.5 Bits and Pels in a Special Bitmapped Image
- Figure 39.1 Disjoint Region
- Figure 39.2 Region of Two Intersecting Rectangles
- Figure 39.3 Text in Client Area
- Figure 39.4 Disjoint Clip Region
- Figure 39.5 Combining Regions
- Figure 39.6 Three Square Regions and Three Fill Patterns
- Figure 40.1 Text in an Elliptical Clipping Area
- Figure 40.2 Valid Clipping Areas
- Figure 40.3 Clipping in Four Coordinate Spaces
- Figure 42.1 Combining Subpictures to Create a Floor Plan
- Figure 42.2 Chained and Called Segments
- Figure 42.3 Correlation Operation
- Figure 42.4 Inserting a New Element in a Segment
- Figure 42.5 Replacing an Element with a New Element
- Figure 48.1 2-Byte Character Format
- Figure 48.2 4-Byte Character Format
-
-
- ────────────────────────────────────────────────────────────────────────────
- Tables
-
- Table 30.1 Presentation-Space Features and Restrictions
- Table 38.1 Drawing Modes and Bitmapped Output
- Table 38.2 GpiBitBlt Output
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- PART 1 INTRODUCING MS OS/2
- ────────────────────────────────────────────────────────────────────────────
- Chapter 1 Introduction
- Chapter 2 MS OS/2 Overview
- Chapter 3 MS OS/2 Programming Models
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 1 Introduction
-
- 1.1 Overview
- 1.2 About the MS OS/2 Programmer's Reference
- 1.3 How to Use This Manual
- 1.4 MS OS/2 and the C Programming Language
- 1.5 MS OS/2 Naming Conventions
- 1.6 Notational Conventions
-
-
- 1.1 Overview
-
- This manual describes the Microsoft(R) Operating System/2 (MS(R) OS/2)
- system functions. MS OS/2 is a single-user, multitasking operating system
- for personal computers. MS OS/2 system functions let programs use the
- operating system to carry out tasks such as reading from and writing to
- disk files, allocating memory, and starting other programs.
-
- Part 1, "Introducing MS OS/2," introduces the MS OS/2 system functions. It
- provides a brief description of the Microsoft Operating System/2
- Programmer's Reference, describes the role of the C programming language
- in the Programmer's Reference, and gives the calling and notational
- conventions used in this manual. The chapters in this part provide a
- general overview of the MS OS/2 system functions and describe the three MS
- OS/2 programming models.
-
- Part 2, "Window Manager," describes the portion of MS OS/2 that lets
- applications create and manage windows. The chapters in this part provide
- detailed information about windows, messages, message queues, control
- windows, dialog windows, and other window-management topics.
-
- Part 3, "Graphics Programming Interface," describes the portion of MS OS/2
- that lets applications use device-independent graphics. The chapters in
- this part provide detailed information about presentation spaces,
- transformations, device contexts, graphics primitives, retained graphics,
- metafiles, and other graphics-related topics.
-
- Part 4, "System Services," describes the portion of MS OS/2 that lets
- applications use the basic multitasking services of MS OS/2. The chapters
- in this part provide detailed information about processes and threads,
- memory management, the file system, dynamic linking, keyboard and mouse
- input, video output, device control, and other information about the
- system.
-
- This manual is intended to describe the purpose of the MS OS/2 system
- functions and to explain the operating-system concepts behind them. It
- also shows how the MS OS/2 system functions work together to carry out
- specific tasks. It does not show how to write, compile, and link programs
- containing these functions. For more information on these topics, see
- Microsoft Operating System/2 Programming Tools.
-
-
- 1.2 About the MS OS/2 Programmer's Reference
-
- The Microsoft Operating System/2 Programmer's Reference, a set of three
- volumes, fully describes the MS OS/2 system functions and related data
- types, macros, structures, messages, and file formats. The Programmer's
- Reference is the source for specific information about programming for MS
- OS/2.
-
- This manual, Volume 1 of the three-volume set, describes the purpose of
- the MS OS/2 system functions and the concepts and principles behind the
- functions. Volume 1 is intended for programmers new to MS OS/2 or learning
- parts of MS OS/2 for the first time. This volume provides the basic
- information needed for an understanding of MS OS/2.
-
- Volumes 2 and 3 consist of alphabetical listings of MS OS/2 system
- functions and related data types, macros, structures, and messages. These
- two volumes define the details of the syntax, parameters, and return
- values of each MS OS/2 system function. Volumes 2 and 3 are intended to be
- used by programmers already acquainted with MS OS/2 and who need only
- specifics of particular functions.
-
-
- 1.3 How to Use This Manual
-
- This manual describes the MS OS/2 system functions in individual-topic
- chapters. Each chapter describes the portion of MS OS/2 that lets an
- application carry out a specific task or set of related tasks. For
- example, the chapter on memory management defines the basic memory
- management terms, describes the role of the memory-management functions,
- and illustrates how to use those functions.
-
- Each chapter has three parts: a general description, programming samples,
- and a summary. The general description contains a thorough discussion of
- the purpose and operation of pertinent MS OS/2 functions. The programming
- samples show how to use those MS OS/2 functions in applications to carry
- out useful tasks. The summary briefly describes each function and message
- described in the chapter.
-
- In many cases, the reader must have some basic knowledge of other portions
- of MS OS/2 in order to understand the concepts described in the chapter.
- Each chapter lists the prerequisite topics.
-
-
- 1.4 MS OS/2 and the C Programming Language
-
- The C programming language is the preferred development language for MS
- OS/2 programs. Many of the programming features of MS OS/2 were designed
- with C and other high-level languages in mind. MS OS/2 programs can also
- be developed in Pascal, FORTRAN, BASIC, and assembly language, but C is
- the most straightforward and easiest language to use to access MS OS/2
- functions. For this reason, all syntax and program samples in this manual
- are written in the C programming language.
-
- The MS OS/2 system functions use many types, macros, and structures that
- are not part of standard C language. These types, macros, and structures
- have been defined to make the task of creating MS OS/2 programs simpler
- and to make program sources clearer and easier to understand.
-
- All types, macros, and structures discussed in this manual are defined in
- the MS OS/2 C-language include files. Programmers may wish to use these
- include files when developing MS OS/2 programs in other computer languages
- such as Pascal or assembly language. If include files for a given language
- are not available, a programmer can translate the definitions by following
- the guidelines given in Volumes 2 and 3 of the Programmer's Reference.
-
- Many chapters in this manual include program examples. These examples show
- how to use MS OS/2 system functions to accomplish simple tasks. In nearly
- all cases, the examples are code fragments, not complete programs. A code
- fragment is intended to show the context in which a function can be used;
- it often assumes that variables, structures, and constants used in the
- example have been defined and/or initialized. A code fragment may also use
- comments to represent a task instead of giving the actual statements.
-
- Although the examples are not complete, you can use them in your programs
- by taking the following steps:
-
- ■ Include the os2.h file in your program.
-
- ■ Define the appropriate include constants for the functions, structures,
- and constants used in the example.
-
- ■ Define and initialize all variables.
-
- ■ Replace comments that represent tasks with appropriate statements.
-
- ■ Check return values for errors and take appropriate actions.
-
- Some examples in this manual combine both MS OS/2 and C run-time functions
- to carry out their tasks.
-
-
- 1.5 MS OS/2 Naming Conventions
-
- In this manual, all parameter, variable, structure, field, and constant
- names conform to MS OS/2 naming conventions. MS OS/2 naming conventions
- are rules that define how to create names that indicate both the purpose
- and data type of an item used with MS OS/2 system functions. These naming
- conventions are used in this manual to help you readily identify the
- purpose and type of the function parameters, structure fields, and
- variables. These conventions are also used in most MS OS/2 sample program
- sources to make the sources more readable and informative.
-
- The following list briefly describes the MS OS/2 naming conventions:
-
- ╓┌─┌──────────┌──────────────────────────────────────────────────────────────╖
- Item Convention
- ──────────────────────────────────────────────────────────────────────────
- Variable All variable, parameter, and field names consist of up to three
- Parameter elements: a prefix, a base type, and a qualifier. The names
- Field always consist of at least a base type or a qualifier. In most
- cases, the name also includes a prefix. The base type
- identifies the data type of the item; the prefix specifies
- additional information, such as whether the item is a pointer,
- an array, or a count of bytes. The qualifier specifies the
- purpose of the item. All letters in the prefix and base type
- are lowercase. The letters in the qualifier are mixed-case
- (both uppercase and lowercase). When naming variables, the
- prefix and base type are optional for common integer types such
- as SHORT and USHORT.
-
- Structure All structure names consist of a word or phrase that specifies
- the purpose of the structure. All letters in the structure name
- are uppercase.
-
- Constant All constant names consist of a prefix (derived from the name
- of the function associated with the constant) and a word or
- Item Convention
- ──────────────────────────────────────────────────────────────────────────
- of the function associated with the constant) and a word or
- phrase that specifies the meaning of the constant in terms of a
- value, action, color, or condition. All letters in the constant
- name are uppercase and an underscore (_) separates the prefix
- from the rest of the name.
-
- Function All function names consist of a three-letter system prefix and
- a word or phrase that describes the action of the function.
- Each word in the function name starts with an uppercase letter.
- Verb and noun combinations, such as DosGetDateTime, are
- recommended.
- ──────────────────────────────────────────────────────────────────────────
-
-
- The following examples show some of the standard prefix and base types you
- will see in this manual:
-
- ╓┌─┌───────────────┌───────────────────────────┌─────────────────────────────╖
- Prefix/Base Description Example
- Prefix/Base Description Example
- type
- ──────────────────────────────────────────────────────────────────────────
- f Boolean flag; TRUE if BOOL fSuccess;
- successful
- ch 8-bit character CHAR chChar;
-
- s 16-bit signed integer SHORT sRate;
-
- l 32-bit signed integer LONG lDistance;
-
- uch 8-bit unsigned character UCHAR uchScan;
-
- us 16-bit unsigned integer USHORT usHeight;
-
- ul 32-bit unsigned integer ULONG ulWidth;
-
- b 8-bit unsigned integer BYTE bAttribute;
-
- sz Zero-terminated array of CHAR szName[];
- characters
- Prefix/Base Description Example
- type
- ──────────────────────────────────────────────────────────────────────────
- characters
- fb Array of flags in a byte BYTE fbMask;
-
- fs Array of flags in a short USHORT fsMask;
-
- fl Array of flags in a long ULONG flMask;
-
- sel 16-bit segment selector SEL selSegment;
-
- p 32-bit far pointer to a PCH pchBuffer;
- given type
- np 16-bit near pointer to a NPCH npchBuffer;
- given type
- a Array of a given type CHAR achData[1];
-
- i Index to an array of a USHORT ichIndex;
- given type
- c Count of items of a given USHORT cb;
- Prefix/Base Description Example
- type
- ──────────────────────────────────────────────────────────────────────────
- c Count of items of a given USHORT cb;
- type
- hf Handle identifying a given HFILE hf;
- object
- off Offset USHORT offSeg;
-
- id Identifier for a given USHORT idSession;
- object
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- 1.6 Notational Conventions
-
- The following notational conventions are used throughout this manual:
-
- Convention Meaning
- ──────────────────────────────────────────────────────────────────────────
- bold Bold type is used for keywords──for example, the names of
- functions, data types, structures, and macros. These names
- are spelled exactly as they should appear in source
- programs.
-
- italics Italic type is used to indicate the name of an argument;
- this name must be replaced by an actual argument. Italics
- are also used to show emphasis in text.
-
- this font This font is used for example program-code fragments.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 2 MS OS/2 Overview
-
- 2.1 Introduction
- 2.2 MS OS/2 and Presentation Manager
- 2.2.1 Queued Input
- 2.2.2 Device-Independent Graphics
- 2.2.3 Shared Resources
- 2.3 The Window Manager
- 2.3.1 Windows
- 2.3.2 Menus
- 2.3.3 Dialog Windows
- 2.3.4 The Message Loop
- 2.4 The Graphics Programming Interface
- 2.4.1 Presentation Spaces and Device Contexts
- 2.4.2 Graphics Primitives
- 2.4.3 Other Graphics Tools
- 2.4.4 Drawing
- 2.4.5 Retained Graphics and Segments
- 2.4.6 Metafiles
- 2.5 System Services
- 2.5.1 Multitasking
- 2.5.2 Dynamic Linking
- 2.5.3 Memory Management
- 2.5.4 The File System
- 2.5.5 Full-Screen Keyboard, Mouse, and Video Operations
- 2.5.6 Interprocess Communication
- 2.6 The MS OS/2 System Functions
-
- 2.1 Introduction
-
- This chapter is an overview of the features of Microsoft Operating
- System/2. The most important of these features are the graphical user
- interface and device-independent graphics provided by the MS OS/2
- Presentation Manager and the multitasking and other system services
- provided by the MS OS/2 base. In particular, this overview describes the
- following:
-
- ■ MS OS/2 and Presentation Manager
-
- ■ The window manager
-
- ■ The graphics programming interface (GPI)
-
- ■ The system services
-
- ■ The MS OS/2 system functions
-
-
- 2.2 MS OS/2 and Presentation Manager
-
- In a multitasking environment, it is important to give all applications
- some portion of the screen through which they can interact with the user.
- One of the principal goals of MS OS/2 is to provide visual access to most,
- if not all, applications at the same time. This access can be granted
- either by giving selected applications full use of the screen while other
- applications wait in the background or by letting applications share the
- screen. In MS OS/2, each application decides which method to use by
- choosing a "session" to run in. The session dictates whether the
- application receives complete control of the screen or must share it with
- other applications.
-
- When MS OS/2 first starts, it creates the Presentation Manager session.
- All applications in this session share the screen. Applications that run
- in this session are called Presentation Manager applications, since
- Presentation Manager is the portion of MS OS/2 that creates and manages
- the Presentation Manager session. When a new application starts, it can
- direct the system to create a new session for it. The new session gives
- complete control of the screen to the application. Applications that use
- the full screen are called full-screen applications.
-
- A Presentation Manager application shares the display with other
- applications by using a "window" for interaction with the user. Basically,
- a window is a rectangular portion of the system display that the system
- grants to an application. However, a window is also a combination of
- visual devices, such as menus, controls, and scroll bars, with which the
- user directs the actions of the application.
-
- A Presentation Manager application must create its own window before
- producing any output or receiving any input. Once the application creates
- its window, MS OS/2 provides the application with detailed information
- about what the user is doing with the window and automatically carries out
- many of the tasks the user requests, such as moving and sizing the window.
-
- A Presentation Manager application can create and use any number of
- windows to display information in a variety of ways. The system manages
- the screen, controlling the placement and display of windows and ensuring
- that no two applications attempt to access the same part of the system
- display at the same time. (In the latter case, the system overlaps the
- window of one application with the window of the other.)
-
- 2.2.1 Queued Input
-
- In traditional programming environments, a program reads from the keyboard
- by making an explicit call to a function (getchar, for example). The
- function typically waits until the user presses a key before returning the
- character code to the program. A Presentation Manager application does not
- make explicit calls to read from the keyboard. Instead, MS OS/2 receives
- all input from the keyboard, mouse, and timer into its system queue and
- automatically redirects the input to the application by copying it from
- the system queue to the application queue. When the application is ready
- to retrieve input, it reads from its queue and dispatches the message to
- the appropriate window.
-
- In Presentation Manager, input from the keyboard and mouse is provided
- automatically to every window that is created. MS OS/2 provides input in a
- uniform format called an input message. This message contains information
- about the input that far exceeds the information available in other
- environments. An input message specifies the system time, the position of
- the mouse, the state of the keyboard, the scan code of the key (if a key
- is pressed), the number of the mouse button (if a button is pressed), and
- the device that generated the message. For example, the keyboard message
- WM_CHAR corresponds to a press or release of a specific key. In each
- message, MS OS/2 provides a device-independent virtual-key code that
- identifies the key, as well as the device-dependent scan code generated by
- the keyboard. The message also specifies the status of other keys on the
- keyboard, such as SHIFT, CTRL, and NUMLOCK. Keyboard, mouse, and timer
- messages all have the same format and are processed in the same manner.
-
- 2.2.2 Device-Independent Graphics
-
- In Presentation Manager, you have access to a rich set of
- device-independent graphics operations. This means that your applications
- can easily draw lines, rectangles, circles, and complex regions, and can
- use the same calls and data to draw on a high-resolution graphics display
- as they use to draw on a dot-matrix printer.
-
- MS OS/2 requires device drivers to convert graphics-output requests to
- output for a printer, plotter, display, or other output device. A device
- driver is a special executable library that an application can load and
- use to carry out graphics operations in the "context" of the specific
- device──that is, the device driver, the output device, and the
- communications port.
-
- 2.2.3 Shared Resources
-
- MS OS/2 is a multitasking system. This means that more than one
- application can run at a time. Presentation Manager applications must
- share the display, the keyboard, the mouse, and even the CPU with all
- other applications that are currently running in the same session. For
- this reason, MS OS/2 carefully controls these resources and requires
- applications to use a specific program interface that guarantees this
- control.
-
-
- 2.3 The Window Manager
-
- The MS OS/2 window manager consists of the MS OS/2 system functions that
- let applications create and manage windows and related elements. These
- related elements are primarily menus, dialog windows, and the message
- loop. The window manager provides the elements that your applications need
- to construct a graphical user interface.
-
- 2.3.1 Windows
-
- A window is the primary input and output device of any Presentation
- Manager application. It is the application's only access to the system
- display, so, since nearly all Presentation Manager applications interact
- with the user in some way through the system display, these applications
- must use windows.
-
- A window is a rectangle on the system display. A typical window is
- composed of a title bar, a menu bar, scroll bars, borders, and other
- features. You list the features you want for a window when you create the
- window. MS OS/2 then draws and manages the window. Figure 2.1 shows the
- main features of a window:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 2.1 can be found in Section 2.3.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 2.1 A Typical Presentation Manager Window
-
- Interestingly, most Presentation Manager user-interface elements are also
- windows, including menus, title bars, buttons, entry fields, icons, and
- scroll bars.
-
- Although an application creates a window and technically "owns" it, the
- management of the window is actually a collaborative effort between the
- application and the system. The system maintains the position and
- appearance of the window, manages the standard window features such as the
- border, scroll bars, and title, and carries out many tasks initiated by
- the user that directly affect the window. The application maintains
- everything else about the window──in particular, the client window, in
- which the application is free to display anything it wants.
-
- To manage this collaborative effort, MS OS/2 advises each window of
- changes that might affect it. Every window must have a corresponding
- window procedure that receives these window-management messages and
- responds appropriately. Window-management messages either specify actions
- for the function to take or request information from the function.
-
- 2.3.2 Menus
-
- Menus are the principal means of user input for a Presentation Manager
- application. A menu is a list of commands that the user can view and
- choose from. When you create an application, you supply the menu name and
- the command names. MS OS/2 displays and manages the menus for you, sending
- a message to the window procedure when the user makes a choice. This
- message is the signal to carry out the command.
-
- 2.3.3 Dialog Windows
-
- A dialog window is a temporary window that you can create to let the user
- supply more information for a command. A dialog window contains one or
- more controls. A control is a small window that has a very simple input or
- output function. The controls in a dialog window give the user a means of
- supplying filenames, choosing options, and otherwise directing the action
- of the command. For example, an entry-field control lets the user enter
- and edit text.
-
- 2.3.4 The Message Loop
-
- Since your application receives input through a message queue, the chief
- feature of any Presentation Manager application is the message loop. The
- message loop retrieves input messages from the message queue and
- dispatches them to the appropriate windows.
-
- For example, MS OS/2 collects hardware input, in the form of messages, in
- its system queue. It then copies this input to the appropriate message
- queue. The message loop in the application retrieves a message from the
- message queue and dispatches it, through the system, to the appropriate
- window procedure. The window procedure can respond to an input message by
- calling MS OS/2 functions to carry out work in the window.
-
- For a more specific example, consider how the system and an application
- collaborate to process keyboard-input messages. The system receives
- keyboard input when the user presses and releases a key. The system copies
- the keyboard messages from the system queue to the application's message
- queue. The message loop retrieves the keyboard messages, translates them
- into ANSI-character WM_CHAR messages, and dispatches the WM_CHAR messages
- to the appropriate window procedure. The window procedure then uses the
- GpiCharString function to display the character in the client window.
-
- MS OS/2 sends window-management messages directly to a window (Win)
- function. For example, after MS OS/2 carries out a request to destroy a
- window, it sends a WM_DESTROY message directly to the window procedure,
- bypassing the message queue. The window procedure must then use the
- WinPostMsg function to copy a WM_QUIT message into the message queue,
- signaling the main function that the window is destroyed and that the
- application should terminate. When the message loop retrieves the WM_QUIT
- message, the loop terminates and the main function exits.
-
-
- 2.4 The Graphics Programming Interface
-
- The graphics programming interface (GPI) consists of the MS OS/2 system
- functions that let you create device-independent graphics for your
- applications. The Gpi functions are used in conjunction with the window
- manager to draw lines, shapes, and text in a window. Applications can also
- use the Gpi functions to draw graphics output on such devices as raster
- printers and vector plotters.
-
- 2.4.1 Presentation Spaces and Device Contexts
-
- A presentation space is the key to an application's access to the system
- display, to printers, and to other graphics-output devices. Conceptually,
- a presentation space is a device-independent space in which you can create
- and manipulate graphics for display. The presentation space defines your
- drawing environment by specifying the tools you have available to create
- graphics. These tools include the graphics primitives granted to every
- presentation space, as well as the bitmaps and fonts that your application
- loads for its exclusive use.
-
- Actually, a presentation space is little more than a data structure whose
- fields contain values that define the drawing environment. The values
- represent the colors, widths, styles, and other attributes of the graphics
- you draw. The system creates the data structure when you create the
- presentation space and initializes the structure to default values.
-
- You must create a presentation space to create graphics. You must also
- create a device context to display those graphics on a device. A device
- context is a bridge from a presentation space to a specific device. You
- create a device context by specifying the device you want to access and
- the type of access you want, such as direct or queued (for printing). You
- begin displaying graphics on the device by associating the device context
- with the presentation space. Once you have associated the device context,
- any lines, text, and images you draw in the presentation space are also
- displayed on the given device.
-
- Like a presentation space, a device context is a data structure. It
- contains information about the device driver that supports the specified
- device. The device driver interprets graphics commands sent to it from the
- presentation space and creates the corresponding commands for its device.
- It then sends the commands either directly to the device or to the
- spooler, depending on the type of access you gave the device context when
- you created it.
-
- 2.4.2 Graphics Primitives
-
- In MS OS/2, graphics primitives are lines, arcs, markers, text, areas, and
- images. They are called primitives because you use them as the basic tools
- to create the documents, pictures, and other composite graphics that your
- applications display to the user.
-
- You draw a primitive by using a Gpi function. For example, to draw a line,
- you use the GpiLine function and specify the ending point of the line. The
- function uses the current point as the starting point for the line and
- draws from the starting point to the ending point. The current point is
- simply the ending point of the last primitive, unless you explicitly set
- the current point by using a function such as GpiMove.
-
- A line primitive is a straight line. An arc primitive is a curve. Curves
- can be arcs of a circle or of an ellipse, or they can be more complex
- curves such as splines and fillets. A marker primitive is a mark or
- character that you draw at a specific point. Markers are typically used to
- plot points in a graph. An area primitive is a closed figure that has been
- filled with a pattern. A common use for an area primitive is to represent
- a cross-section in a mechanical drawing. An image is a bitmapped image,
- with each bit representing the color of a pel (picture element) on the
- device. Images are often used for complex pictures that cannot easily be
- drawn.
-
- Every primitive has a corresponding set of primitive attributes. The
- attributes specify the color, style, size, and orientation of the
- primitive when your application draws it. The primitive attributes are
- given default values when you create the presentation space, so you can
- use the primitives immediately. However, you can reset the attributes at
- any time. You have the choice of changing the attributes for individual
- primitives or changing a specific attribute for all primitives. For
- example, you can set the color for all primitives by using the GpiSetColor
- function, or you can set it for just the line primitive by using the
- GpiSetAttrs function.
-
- 2.4.3 Other Graphics Tools
-
- In addition to the graphics primitives, MS OS/2 provides graphics tools
- that you can use to draw graphics and to affect how the graphics are
- drawn. These tools are paths, bitmaps, clipping areas, transformations,
- and color tables.
-
- A path is a sequence of lines that you can use to create a filled area, a
- geometric line, or a clip path. A path is very much like an area
- primitive, in that you can use the path as a closed figure and fill it
- with a pattern. Unlike an area primitive, however, a path can be used to
- create geometric lines, sometimes called wide lines. Geometric lines are
- drawn, using a given width and pattern, so that they follow the outline
- specified by the path. Geometric lines give you a selection of line styles
- and patterns that are not available with the line primitive.
-
- A bitmap is an array of bits that represents an image that you can display
- on a raster output device. Bitmaps typically represent scanned images and
- icons and are very much like image primitives. Unlike an image primitive,
- however, a bitmap can have several different formats, each format
- specifying color information that an image primitive cannot contain. Also,
- bitmaps can be used to create fill patterns that you can use to fill
- figures created using paths and area primitives. Finally, bitmaps can be
- copied from one presentation space to another or even from one location to
- another within the same presentation space.
-
- A font is a collection of characters and symbols that you can use to draw
- text. Characters in a font belong to the same typeface and share
- stroke-width and serif characteristics. Some common fonts are 12-point
- Helvetica, 10-point Times Roman Bold, and 12-point Courier Italic. To use
- fonts in an application, you first create a logical font that describes
- the typeface and other characteristics that you want. Then you use the
- local identifier for the logical font to set that font as the current font
- for the presentation space. Subsequent text functions use the current font
- to draw text.
-
- Clipping is a process that limits graphics output to a specific region on
- the display or on a page of printer paper. You can use clipping with a
- presentation space by creating a clipping area. The clipping area is the
- region where output can appear. If an application attempts to draw output
- outside a clipping area, the system will "clip" the output, preventing it
- from appearing on the device. You can create a clipping area for a
- presentation space by setting the dimensions of the graphics field and
- viewing limits or by creating a clip path or clip region. The final
- clipping area is the intersection of these four possible clip regions.
-
- A transformation defines how the system should map the points in one
- coordinate space onto another coordinate space. Since all graphics
- primitives and other drawing tools use coordinate spaces, a transformation
- affects the way all graphics are drawn by your application. For example,
- you can use a transformation to move a figure from one place to another on
- the display or to rotate or adjust the size of the figure. Transformations
- are typically used to give the user different perspectives on a single
- drawing or to create rotated or sheared figures that would be
- time-consuming for the application to plot and draw.
-
- A logical color table is an array of colors that an application uses when
- drawing graphics. Any primitive or other graphic you draw has one of the
- colors given in the table. You specify a color by giving a color index.
- The index identifies the table entry defining the color you want. Every
- presentation space has a default color table when it is created, but you
- can create a new logical color table to replace the default table if you
- need other colors. Creating a new table associates the color indexes with
- whatever color you have specified in the corresponding table entry.
-
- 2.4.4 Drawing
-
- You draw graphics by using the MS OS/2 drawing functions. A drawing
- function draws a primitive or other graphic, applying the primitive
- attributes and whatever information you supply to the function when you
- call it. For example, when drawing line primitives, the system applies the
- current line color and style. The style determines whether the line is
- solid or a series of dashes, dots, or both.
-
- Some attributes apply to all graphics primitives. For example, the
- foreground and background colors and mix modes affect all primitives. The
- foreground color defines the color of the primitive and the background
- color defines the color "behind" the primitive. For a line drawn using a
- dashed style, the dashes have the foreground color and the gaps between
- the dashes have the background color. The mix modes define how the
- foreground and background colors are combined with colors already on the
- display. The mix mode can cause the color to overpaint the existing color,
- leave it alone, or mix with it by using a binary operator such as the
- exclusive-OR operator.
-
- Some attributes are specific to a particular graphics primitive. For
- example, the arc parameters apply only to arcs. The arc parameters specify
- a transformation that maps a circle to another circle, ellipse, or similar
- shape. When you draw an arc, the system uses the shape defined by the
- transformed circle as the shape for your arc. You supply a multiplier to
- set the final size of the arc.
-
- A number of drawing functions use loadable resources to draw graphics. For
- example, the text-drawing functions, such as GpiCharString and
- GpiCharStringPos, can use a loaded font to draw text. To make a loadable
- resource available for these functions, you typically load the resource
- into memory and create a local identifier for the resource. For example,
- to use a font resource, you load it using the GpiLoadFonts function and
- then set the local identifier by using the GpiCreateLogFont function. Once
- you have a local identifier, you can set the resource to be the current
- resource by using a function such as GpiSetCharSet. Along with the
- text-drawing functions, the marker and area functions can use resources
- when they draw.
-
- 2.4.5 Retained Graphics and Segments
-
- MS OS/2 lets you retain the graphics you draw in your application by
- storing them in retained segments. You create a retained segment by
- setting the drawing mode of the presentation space to DM_RETAIN or
- DM_DRAWANDRETAIN and opening the segment. All subsequent graphics are
- stored in the segment (and are also drawn on the device, if you specified
- DM_DRAWANDRETAIN). You can close the segment at any time and draw the
- contents by using a function such as GpiDrawSegment.
-
- Retained segments are useful for storing graphics that result from user
- input. Once stored, the graphics can be redrawn or edited at any time. An
- element pointer lets the application move to a specific graphics element
- in a segment. The element can then be drawn or replaced, or new elements
- can be inserted.
-
- 2.4.6 Metafiles
-
- A metafile, created by using a special device context, is another method
- of storing graphics. In this case, you associate the metafile device
- context with the presentation space, draw the graphics you want in the
- metafile, and then disassociate the device context and close it. Closing
- the metafile returns a handle that you can use to save the metafile in a
- disk file.
-
- Metafiles are a useful way of transferring graphics images from one
- computer to another. An application can load a metafile from disk and play
- it into a presentation space. The presentation space can be associated
- with any device──display or printer. The graphics in the metafile are
- stored as graphics commands, not as a bitmap, so an application can
- examine and extract portions of the metafile if necessary.
-
-
- 2.5 System Services
-
- The system services consist of all the MS OS/2 system functions that let
- you create processes and threads, access disk files and devices, allocate
- memory, and retrieve or set information about the system. In Presentation
- Manager applications, the system-service functions are typically used to
- carry out tasks for which no corresponding window-manager or Gpi function
- exists. In full-screen programs, system-service functions are used almost
- exclusively, even to interact with the user and access the devices of the
- computer.
-
- 2.5.1 Multitasking
-
- Multitasking, one of the principal features of MS OS/2, is the ability of
- the system to manage the execution of more than one program at a time.
- This ability helps to optimize use of the computer, since time normally
- spent by a program waiting for user input is distributed to other programs
- that may be printing a document or recalculating a spreadsheet.
-
- MS OS/2 provides multitasking in the traditional sense of having more than
- one program run at a time, and it also extends this concept to permit a
- single program to run more than one copy of itself at the same time.
-
- Every program that has been loaded into memory and is running is called a
- process. Each copy of a process is called a thread. A process always has
- at least one thread, called the main thread or thread 1, and can create
- more threads. These additional threads are useful for carrying out tasks
- unrelated to the processing of the main thread. For example, a process may
- create a thread to write data to a disk file. This frees the main thread
- so that it can continue to process user input.
-
- 2.5.2 Dynamic Linking
-
- Dynamic linking lets a program gain access at run time to functions that
- are not part of its executable code. These functions are contained in
- dynamic-link libraries──special program modules that contain executable
- code but cannot be run as programs. Instead, programs load the appropriate
- dynamic-link libraries and execute the code in the libraries by linking to
- them dynamically.
-
- Dynamic-link libraries are very common in MS OS/2. In fact, most of the
- system is contained in dynamic-link libraries. The chief advantage of
- dynamic-link libraries is that they reduce the amount of memory needed by
- a program. A program loads a library only if it needs to execute a
- function in the library. Once the library is loaded, the system also
- shares it with any other program that needs it. This means that only one
- copy of the library is ever loaded at any one time.
-
- 2.5.3 Memory Management
-
- Programs can, at any time, allocate additional memory for their own use.
- MS OS/2 controls access to system memory through the use of selectors. A
- selector is a unique number identifying a specific segment in memory. When
- a program allocates a segment, it specifies the size of the segment (in
- bytes) and receives a selector for that segment. This selector can then be
- used to access the memory.
-
- MS OS/2 protects memory from unauthorized use. The process that allocates
- memory owns that memory, and no other process can access it. Attempting to
- access memory owned by another process causes a protection violation and
- usually terminates the process.
-
- If two processes need to share memory, a process can create shared memory
- and either pass the selector to the process that is to share the memory or
- pass the name of the shared segment to that process. When two processes
- share a segment, no protection violation occurs for them, but the memory
- remains protected from all other processes. The sharing processes must
- manage the shared memory.
-
- 2.5.4 The File System
-
- MS OS/2 programs have complete access to the disk files and devices of the
- computer. MS OS/2 manages its disk files and its devices in essentially
- the same way. For example, a program can use the same functions to open
- and read from a disk file as it uses to open and read from a serial port.
- Each open file or device is identified by a unique file handle. The
- program uses the handle in system functions to access the file or device.
-
- MS OS/2 lets programs create, open, move, and delete files and directories
- in the file system. When a process opens a file, it specifies whether the
- file can be shared──that is, whether it can be accessed and possibly
- modified by other processes. This sharing also applies to devices that a
- process may open. Processes can open any device directly, including the
- parallel port, the serial ports, and the disk drive. MS OS/2 provides a
- wide range of input-and-output-control functions that a process can use to
- access and set the modes of the devices it has opened.
-
- Ordinarily, the system automatically opens three files when a program
- starts: the standard-input, standard-output, and standard-error files.
- These files correspond to the keyboard and the full-screen display. The
- program can use these files to read from the keyboard and write to a
- full-screen display.
-
- 2.5.5 Full-Screen Keyboard, Mouse, and Video Operations
-
- For full-screen programs, MS OS/2 provides access to the keyboard, the
- mouse, and the video display. A program can open these devices in much the
- same way as it opens a file. The MS OS/2 keyboard (Kbd) functions return
- much more information about a keystroke than do the standard file-system
- functions. Also, the keyboard functions let a program create logical
- keyboards and manage these keyboards for the processes in the same screen
- group.
-
- Similarly, a program can open the mouse and read events from the
- mouse-event queue. An event is a mouse motion or button click. The program
- can also manage the mouse pointer, moving it, hiding it, and showing it as
- necessary.
-
- Any full-screen program can write individual characters and strings
- directly to a character-based display. Unlike Presentation Manager
- applications, which must write characters to windows, a full-screen
- program has complete control of the system display while its session is in
- the foreground. The program can write both characters and attributes to
- the display, read characters from the display, and change modes for the
- display. A program that uses the video functions in a full-screen session
- must manage the display for that session.
-
- The keyboard and mouse functions should not be used in Presentation
- Manager applications, since the system provides its own mouse and keyboard
- management. Many of the video functions can be used in a special type of
- Presentation Manager application called an advanced-video-input-and-output
- (AVIO) program. An AVIO program creates a window but uses the video
- functions to write text to the window.
-
- 2.5.6 Interprocess Communication
-
- MS OS/2 provides several methods of interprocess communication:
- semaphores, pipes, signals, and queues.
-
- A semaphore is a special variable that a process can use to signal the
- beginning and ending of a given operation and to prevent more than one
- thread within the process from accessing a specific resource at the same
- time. A process can create and use three types of semaphores: system, RAM,
- and fast-safe RAM. System semaphores are used between processes to control
- access to a shared resource. RAM semaphores are used between threads in
- the same process to control a resource or to signal the end of an
- operation. Fast-safe RAM semaphores are used between threads or processes
- to control a resource. The RAM semaphores are typically used when
- semaphore processing must be fast.
-
- A pipe is a special file that two processes can use to transfer data.
- Although a pipe is like a file, it does not correspond to a device or a
- file on disk. Instead, the pipe is maintained by the system. Two processes
- use a pipe by opening the pipe and retrieving two handles: a read handle
- and a write handle. One process uses the write handle to write data to the
- pipe. The other process uses the read handle to read the data from the
- pipe.
-
- A signal is a special interrupt that is sent to a process by the system or
- by another process. The signal temporarily stops normal execution of the
- process and causes the process to execute a signal handler. Signals are
- typically used to stop a process and exit. For example, pressing the
- CTRL+C key combination in a full-screen session generates a signal that
- usually stops the current process. The signal handler defines what a
- process does when it receives a signal. If a process does not want default
- signal handling, it can disable a signal or replace the signal handler
- with one of its own.
-
- A queue is a special buffer that a process creates and shares with other
- processes. A queue is a convenient way for one process to channel data
- from two or more related processes into a single buffer. Note that this
- kind of queue is different from the message queue used by Presentation
- Manager. The queues are not related.
-
-
- 2.6 The MS OS/2 System Functions
-
- The MS OS/2 system functions give applications access to all the features
- of MS OS/2. The MS OS/2 features, such as windows, device-independent
- graphics, and multitasking, let you create programs that make optimal use
- of the computer's memory, display, and CPU while still meeting the needs
- of a wide range of users through either the traditional character-based
- interface or the graphical user interface of Presentation Manager.
-
- The MS OS/2 system functions are organized into several distinct groups,
- as described in the following list:
-
- ╓┌─┌───────────────┌─────────────────────────────────────────────────────────╖
- Function group Usage
- ──────────────────────────────────────────────────────────────────────────
- Dev Use the Presentation Manager device (Dev) functions to
- open and control Presentation Manager device drivers.
- These functions let you create device contexts that you
- can associate with a presentation space and use with the
- Gpi functions to carry out device-independent graphics
- operations for displays, printers, and plotters.
-
- Dos Use the disk-operating-system (Dos) functions in
- full-screen and Presentation Manager sessions to read from
- and write to disk files, to allocate memory, to start
- threads and processes, to communicate with other
- processes, and to access the computer's devices directly.
- Most functions in this group can be used in Presentation
- Manager applications.
-
- Gpi Use the graphics-programming-interface (Gpi) functions to
- create graphics output for a display, a printer, or other
- Function group Usage
- ──────────────────────────────────────────────────────────────────────────
- create graphics output for a display, a printer, or other
- output devices. The Gpi functions give you a full range of
- graphics primitives, from lines to complex curves to
- bitmaps. You choose the attributes for the primitives
- (such as color, line width, and pattern) and then draw
- lines, text, and shapes. The retained-graphics capability
- lets you save the drawings in segments and build complex
- pictures by drawing a chain of segments.
-
- Kbd Use the keyboard (Kbd) functions in full-screen sessions
- to read keystrokes from the keyboard, to manage multiple
- logical keyboards, and to change code pages and
- translation tables. Since the Presentation Manager session
- provides its own keyboard support, Kbd functions are not
- needed in Presentation Manager applications.
-
- Mou Use the mouse (Mou) functions in full-screen sessions to
- read mouse input from the mouse-event queue, to set the
- mouse-pointer shape, and to manage the mouse for all
- Function group Usage
- ──────────────────────────────────────────────────────────────────────────
- mouse-pointer shape, and to manage the mouse for all
- processes in a session. As with the keyboard, the
- Presentation Manager session provides its own mouse
- support, so Mou functions are not needed in Presentation
- Manager applications.
-
- Vio Use the video-input-and-output (Vio) functions in
- full-screen sessions to write characters and character
- attributes to the screen, to create pop-up <windows for
- messages, to change video modes, and to access physical
- video memory. Vio functions can also be used in
- advanced-video-input-and-output (AVIO) applications for
- the Presentation Manager session, to write characters and
- character attributes in a window. Most Presentation
- Manager applications, however, use the
- graphics-programming-interface (Gpi) functions to write
- text in a window.
-
- Win Use the window-manager (Win) functions to create and
- Function group Usage
- ──────────────────────────────────────────────────────────────────────────
- Win Use the window-manager (Win) functions to create and
- manage windows. Presentation Manager applications use
- windows as the main interface with the user. The Win
- functions let you create menus, scroll bars, and dialog
- windows that let the user choose commands and supply
- input. Your application receives all mouse and keyboard
- input as messages from the message queue. The Win
- functions let you retrieve messages from the queue and
- dispatch them to the window the input is intended for.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 3 MS OS/2 Programming Models
-
- 3.1 Introduction
- 3.2 Full-Screen Programs
- 3.3 Presentation Manager Applications
- 3.4 The Family Application Programming Interface
- 3.5 Using the Command Line
- 3.6 Using Structures
- 3.7 Using Bit Masks
- 3.8 Sharing Resources
- 3.9 C-Language Header Files
-
- 3.1 Introduction
-
- This chapter describes the types of programs that you can develop for MS
- OS/2. MS OS/2 supports the following program types:
-
- ■ Full-screen programs
-
- ■ Full-screen programs in a window
-
- ■ Presentation Manager applications
-
- ■ Advanced-video-input-and-output (AVIO) programs
-
- ■ Family-application-programming-interface (FAPI) programs
-
-
- 3.2 Full-Screen Programs
-
- A full-screen program is any MS OS/2 program that does not create a
- Presentation Manager message queue. In other words, it is a program that
- does not rely on the Presentation Manager mouse and keyboard processing
- for input. Full-screen programs typically run in a full-screen session.
-
- Most full-screen programs use the Dos functions to perform input, output,
- memory management, and other activities. Full-screen programs also
- commonly use the standard-input, standard-output, and standard-error files
- created for them when they start.
-
- A full-screen program uses a main function as its starting point and can
- call as many other functions as needed to complete its designated task.
- The following simple full-screen program copies the line "Hello, world" to
- the screen:
-
- #include <os2.h>
-
- main( )
- {
- USHORT cbWritten;
-
- DosWrite(1, "Hello, world\r\n", 14, &cbWritten);
- }
-
- The MS OS/2 system functions use many structures, data types, and
- constants that are not part of the standard C language. For example, the
- data type USHORT is a special MS OS/2 data type that specifies an unsigned
- short integer. In order to use these items, you must include the MS OS/2
- header file os2.h at the beginning of your program source file. For more
- information about the C-language header files, see Section 3.9.
-
- The MS OS/2 system functions are not standard C functions. They use the
- Pascal calling convention. This means, for example, that the MS OS/2
- functions expect parameters to be passed in left-to-right order instead of
- the standard right-to-left order of C functions. To use the MS OS/2
- functions in a C-language program, you must declare them with the pascal
- keyword, which directs the C compiler to generate proper instructions for
- the function call. All MS OS/2 functions are declared this way within the
- os2.h file, so including the file saves you the trouble of declaring each
- function individually.
-
- The os2.h file also declares the parameter types for each function.
- Without these declarations, many function parameters would require type
- casting to avoid compiler errors. For example, the DosWrite function shown
- in the preceding example requires the second parameter to be a complete
- far (32-bit) address to the given string. Since the os2.h file declares
- the second parameter with this type, the compiler does the cast for you.
-
- Some full-screen programs can also run in a window in the Presentation
- Manager session. Although the program runs in a window, it does not create
- the window. Instead, the system creates the window and provides the input
- and output to the program just as if it were running in a full-screen
- session. A full-screen program can run in a window only if it does not use
- functions that directly access the devices that Presentation Manager
- controls. For example, a program that attempts to retrieve the address of
- the video buffer or to change video modes may fail.
-
-
- 3.3 Presentation Manager Applications
-
- A Presentation Manager application is any MS OS/2 program that creates a
- message queue. A window is the only means a Presentation Manager
- application has to receive input and display output, so Presentation
- Manager applications typically create one or more windows to interact with
- the user.
-
- All MS OS/2 Presentation Manager applications have essentially the
- following structure:
-
- ■ A main function
-
- ■ One or more window procedures
-
- ■ Optional functions to support the main function and/or the window
- procedures
-
- Since nearly all Presentation Manager applications create and use windows,
- the main function carries out the same basic tasks in most applications.
- The typical main function does the following, in the order shown:
-
- 1. Initializes the application for Presentation Manager.
-
- 2. Creates a message queue.
-
- 3. Creates a window class.
-
- 4. Creates a window.
-
- 5. Starts the message loop and continues to dispatch messages until the
- WM_QUIT message is retrieved.
-
- 6. Destroys the window when finished using it.
-
- 7. Destroys the message queue.
-
- 8. Terminates the application.
-
- Every MS OS/2 Presentation Manager application has at least one thread of
- execution. Each thread that calls Presentation Manager functions must
- register with the system by calling the WinInitialize function. This
- function creates an anchor block and returns an anchor-block handle that
- the thread can use in subsequent functions.
-
- An anchor block links a process with the system. The anchor block includes
- an instance data segment in which to store the process's environment and
- storage for error messages. The anchor-block handle is used in the call to
- the WinTerminate function that ends the association with the anchor block
- just before the application terminates.
-
- The application creates the message queue by using the WinCreateMsgQueue
- function. This function returns a queue handle that can be used in
- subsequent functions. Once the queue is created, the application can
- register a window class, create a window and start the message loop. After
- the message loop ends, the application can destroy the window and use the
- queue handle in the WinDestroyMsgQueue function to destroy the queue.
-
- Once the application is initialized and a message queue and window are
- created, the application can enter the main message loop. The application
- waits there for messages to appear in the queue, retrieves them, and
- dispatches them, as appropriate, to its windows. When the user or system
- chooses to terminate an application, a WM_QUIT message is used to trigger
- an exit from the message loop.
-
- After leaving the message loop, an application carries out various
- termination activities, including destroying windows, releasing memory,
- destroying message queues, closing files, and severing connections with
- the shell and other applications.
-
- The following code fragment from a simple Presentation Manager application
- copies the line "Hello, world" to its window:
-
- #define INCL_WIN
- #define INCL_DOS
- #include <os2.h>
- HAB hab; /* anchor-block handle */
- HMQ hmq; /* message-queue handle */
- QMSG qmsg; /* message-queue structure */
-
- MRESULT CALLBACK MyWindowProc(HWND, USHORT, MPARAM, MPARAM);
-
- HWND hwndFrame; /* frame-window handle */
- HWND hwndClient; /* client-window handle */
- ULONG flStyle = FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
- FCF_MINMAX | FCF_SHELLPOSITION | FCF_TASKLIST;
-
- main()
- {
- /*
- * Initialize the thread for making Presentation Manager calls and
- * create the message queue.
- */
-
- hab = WinInitialize(0);
- hmq = WinCreateMsgQueue(hab, DEFAULT_QUEUE_SIZE);
-
- /* Register the class, terminate on failure. */
-
- if (!WinRegisterClass(hab, "MyClass",
- MyWindowProc, CS_SIZEREDRAW, NULL))
- DosExit(EXIT_PROCESS, 0);
-
- /* Create the window, terminate on failure. */
-
- if (!(hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE,
- &flStyle, "My Window!", 0L, NULL, 0, &hwndClient)))
- DosExit(EXIT_PROCESS, 0);
-
- /* Get and dispatch messages. */
-
- while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
- WinDispatchMsg(hab, &qmsg, NULL, 0, 0);
- WinDestroyWindow(hwndFrame); /* destroy the main window */
- WinDestroyMsgQueue(hmq); /* destroy the message queue */
- WinTerminate(hab); /* terminate */
- }
-
- MRESULT CALLBACK MyWindowProc(hwnd, usMessage, mp1, mp2)
- HWND hwnd;
- USHORT msg;
- MPARAM mp1;
- MPARAM mp2;
- {
- HPS hps; /* presentation-space handle */
- RECTL rcl; /* rectangle structure */
- POINTL ptl; /* point structure */
-
- switch (msg) {
- case WM_PAINT:
- hps = WinBeginPaint(hwnd,
- NULL, NULL); /* start painting */
- WinQueryWindowRect(hwnd, &rcl); /* get window size */
- WinFillRect(hps, &rcl, CLR_WHITE); /* fill background */
- ptl.x = (rcl.xRight - rcl.xLeft) / 2;
- ptl.y = (rcl.yTop - rcl.yBottom) / 2;
- GpiMove(hps, &ptl); /* move to center of window */
- GpiCharString(hps, 12L,
- "Hello, world"); /* draw string */
- WinEndPaint(hps); /* end painting */
- return (0L);
-
- default:
- return (WinDefWindowProc(hwnd, msg, mp1, mp2));
- }
- }
-
- An advanced-video-input-and-output (AVIO) program is a Presentation
- Manager program that uses the advanced Vio functions for text output.
- These function let a Presentation Manager application write text to a
- window just as if it were writing the text to a full screen. These
- programs must run in the Presentation Manager session and must create at
- least one window for input and output.
-
-
- 3.4 The Family Application Programming Interface
-
- Many MS OS/2 functions can be used in programs intended to be run in real
- mode. These functions, collectively called the family application
- programming interface (family API, or FAPI), let developers create MS OS/2
- programs that can run in both protected and real modes; that is, they can
- run under MS OS/2 and under MS-DOS versions 2.x and 3.x.
-
- To use the family API in real-mode programs, you must use only the MS OS/2
- functions that belong to the FAPI, and you must observe the restrictions
- that apply to these functions when running in real mode. Also, you must
- bind your program by using the Microsoft Operating System/2 Bind utility
- (bind). The bind utility supplies the code needed to link the MS OS/2
- functions to the corresponding MS-DOS system calls. This code is used only
- when the program is run in real mode; that is, a bound program can still
- run in protected mode.
-
- Not all MS OS/2 functions belong to the FAPI, and some that do belong have
- slightly different behavior when used in real mode than when used in
- protected mode. The following is a complete list of the FAPI functions.
- Those functions marked with a dagger (╪) operate differently in real mode
- than in protected mode; all other FAPI functions operate identically in
- both protected and real modes.
-
-
- DosAllocHuge ╪ DosInsMessage ╪ KbdFlushBuffer ╪
- DosAllocSeg ╪ DosMkDir KbdGetStatus╪
- DosBeep DosMove KbdPeek ╪
- DosBufReset DosNewSize KbdSetStatus ╪
- DosCaseMap ╪ DosOpen ╪ KbdStringIn╪
- DosChDir DosPutMessage ╪ VioGetBuf
- DosChgFilePtr DosQCurDir VioGetCurPos
- DosClose DosQCurDisk VioGetCurType
- DosCreateCSAlias ╪ DosQFHandState VioGetMode
- DosDelete DosQFileInfo VioGetPhysBuf
- DosDevConfig DosQFileMode VioReadCellStr
- DosDevIOCtl ╪ DosQFSInfo VioReadCharStr
- DosDupHandle DosQVerify VioScrLock ╪
- DosErrClass DosRead ╪ VioScrollDn
- DosError ╪ DosReallocHuge ╪ VioScrollLf
- DosExecPgm ╪ DosReallocSeg ╪ VioScrollRt
- DosExit ╪ DosRmDir VioScrollUp
- DosFileLocks DosSelectDisk VioScrUnLock
- DosFindClose DosSetDateTime VioSetCurPos
- DosFindFirst ╪ DosSetFHandState ╪ VioSetCurType
- DosFindNext ╪ DosSetFileInfo VioSetMode
- DosFreeSeg ╪ DosSetFileMode VioShowBuf
- DosGetCollate ╪ DosSetFSInfo VioWrtCellStr
- DosGetCtryInfo ╪ DosSetSigHandler ╪ VioWrtCharStr
- DosGetDateTime DosSetVec ╪ VioWrtCharStrAtt
- DosGetDBCSEv ╪ DosSetVerify VioWrtNAttr
- DosGetEnv DosSleep VioWrtNCell
- DosGetHugeShift DosSubAlloc VioWrtNChar
- DosGetMachineMode DosSubFree VioWrtTTY
- DosGetMessage ╪ DosSubSet
- DosGetVersion DosWrite
- DosHoldSignal ╪ KbdCharIn ╪
-
- ──────────────────────────────────────────────────────────────────────────
- Note
- The DosGetMachineMode function is especially useful in FAPI programs,
- since it specifies which environment the program is running in: MS OS/2
- or MS-DOS.
- ──────────────────────────────────────────────────────────────────────────
-
- Following are the real-mode restrictions and/or differences in operation
- for the FAPI functions marked with daggers (╪) in the preceding list:
-
- DosAllocHuge Rounds the usPartialSeg parameter value up to the next
- paragraph (16-byte) value. This function copies the actual segment
- address, not a selector, to the variable pointed to by the psel parameter.
-
- DosAllocSeg Rounds the usSize parameter value up to the next paragraph
- (16-byte) value. This function copies the actual segment address, not a
- selector, to the variable pointed to by the psel parameter.
-
- DosCaseMap Provides no method of identifying the boot drive. The system
- assumes that the country.sys file is in the root directory of the current
- drive.
-
- DosCreateCSAlias Returns as a selector the actual segment address of the
- allocated memory. Freeing either the returned selector or the original
- selector immediately frees the block of memory.
-
- DosDevIOCtl Restricts the input-and-output-control functions that can be
- used. Categories 2, 3, 4, 6, 7, 10, and 11 cannot be used. Also, some
- control functions in categories 1, 5, and 8 can be used with MS-DOS 3.x
- but not with MS-DOS 2.x. The following input-and-output-control functions
- can be used in FAPI programs:
-
- ASYNC_SETBAUDRATE
- ASYNC_SETLINECTRL
- DSK_BLOCKREMOVABLE
- DSK_GETLOGICALMAP
- DSK_LOCKDRIVE DSK_REDETERMINEMEDIA DSK_SETLOGICALMAP
- DSK_UNLOCKDRIVE PRT_GETFRAMECTL
- PRT_GETINFINITERETRY
- PRT_GETPRINTERSTATUS
- PRT_INITPRINTER
- PRT_SETFRAMECTL (for IBM Graphics Printers only)
- PRT_SETINFINITERETRY (current program only)
-
- DosError If the fEnable parameter is HARDERROR_DISABLE, causes all
- subsequent int 24h requests to fail, until another call is made to the
- DosError function with fEnable set to HARDERROR_ENABLE.
-
- DosExecPgm Allows only the value EXEC_SYNC for the fExecFlags parameter.
- Other values cause errors. The buffer pointed to by the pchFailName
- parameter is filled with blanks, even if the function fails. The
- codeResult field of the RESULTCODES structure receives the exit code for
- the DosExit function or the MS-DOS call that terminates the program.
-
- DosExit Exits from the currently executing program, since there are no
- threads in the real-mode environment. If the fTerminate parameter is
- EXIT_THREAD, the entire process ends, not just a thread.
-
- DosFindFirst Requires the phdir parameter to be HDIR_SYSTEM.
-
- DosFindNext Requires the hdir parameter to be HDIR_SYSTEM.
-
- DosFreeSeg Does not treat a code-segment selector (created by using the
- DosCreateCSAlias function) and the corresponding data-segment selector as
- unique. Freeing one frees both.
-
- DosGetCollate Provides no method of identifying the boot drive. The
- system assumes that the country.sys file is in the root directory of the
- current drive.
-
- DosGetCtryInfo Provides no method of identifying the boot drive. The
- system assumes that the country.sys file is in the root directory of the
- current drive.
-
- DosGetDBCSEv Provides no method of identifying the boot drive. The system
- assumes that the country.sys file is in the root directory of the current
- drive.
-
- DosGetMessage Provides no method of identifying the boot drive. The
- system assumes that the message file is in the root directory of the
- current drive.
-
- DosHoldSignal Recognizes only the signal-interrupt (SIG_CTRLC) and
- signal-break (SIG_CTRLBREAK) signals.
-
- DosInsMessage Provides no method of identifying the boot drive. The
- system assumes that the message file is in the root directory of the
- current drive.
-
- DosOpen Restricts the values that can be used with the fsOpenMode
- parameter. The parameter can be a combination of the following values:
-
- ╓┌─┌─────────────────────────────┌───────────────────────────────────────────╖
- Value Meaning
- ──────────────────────────────────────────────────────────────────────────
- OPEN_ACCESS_READONLY Read-only access mode.
-
- OPEN_ACCESS_WRITEONLY Write-only access mode.
-
- OPEN_ACCESS_READWRITE Read/write access mode.
-
- Value Meaning
- ──────────────────────────────────────────────────────────────────────────
- OPEN_SHARE_DENYREADWRITE Deny read/write share mode. Not available in
- MS-DOS 2.x. Available in MS-DOS 3.x only
- when the share command has been used.
-
- OPEN_SHARE_DENYWRITE Deny-write share mode. Not available in
- MS-DOS 2.x. Available in MS-DOS 3.x only
- when the share command has been used.
-
- OPEN_SHARE_DENYREAD Deny-read share mode. Not available in
- MS-DOS 2.x. Available in MS-DOS 3.x only
- when the share command has been used.
-
- OPEN_SHARE_DENYNONE Deny-none share mode. Not available in
- MS-DOS 2.x. Available in MS-DOS 3.x only
- when the share command has been used.
-
- OPEN_FLAGS_NOINHERIT Inheritance flag. Not available in MS-DOS
- 2.x.
- Value Meaning
- ──────────────────────────────────────────────────────────────────────────
- 2.x.
-
- OPEN_FLAGS_WRITE_THROUGH Write-through flag. Not available in MS-DOS
- 2.x.
-
- OPEN_FLAGS_DASD Direct-access-storage-device (DASD) flag.
- ──────────────────────────────────────────────────────────────────────────
-
-
- The fail-on-error flag (OPEN_FLAGS_FAIL_ON_ERROR) is not available to
- real-mode programs.
-
- DosPutMessage Provides no method of identifying the boot drive. The
- system assumes that the message file is in the root directory of the
- current drive.
-
- DosRead Uses the KbdStringIn function whenever the specified file handle
- identifies the keyboard device. In real mode, KbdStringIn reads only the
- number of characters specified in the call, then beeps to signal the user
- that no additional characters can be entered. (In protected mode, the user
- can enter characters until the keyboard buffer is full.)
-
- DosReallocHuge Rounds the usPartialSize parameter value up to the next
- paragraph (16-byte) value.
-
- DosReallocSeg Rounds the usNewSize parameter value up to the next
- paragraph (16-byte) value.
-
- DosSetFHandState Requires that the OPEN_FLAGS_FAIL_ON_ERROR flag and the
- OPEN_FLAGS_WRITE_THROUGH flag not be set. Also, the OPEN_FLAGS_NOINHERIT
- flag must not be set in MS-DOS 2.x.
-
- DosSetSigHandler Can be used to install signal handlers for only the
- signal-interrupt (SIG_CTRLC) and signal-break (SIG_CTRLBREAK) signals.
- Furthermore, the SIG_CTRLC and SIG_CTRLBREAK signals are treated as the
- same signal, so the function accepts only the SIG_CTRLC value when setting
- a signal handler.
-
- DosSetVec Does not accept VECTOR_EXTENSION_ERROR as the usVecNum value,
- since this exception is not raised in machines using the 8088 or 8086
- microprocessor.
-
- KbdCharIn Does not copy the system time to the KBDKEYINFO structure and
- provides no interim character support. This function retrieves characters
- only from the default keyboard (handle 0). The fbStatus field can be
- 0x0000 or SHIFT_KEY_IN. The hkbd parameter is ignored.
-
- KbdFlushBuffer Ignores the hkbd parameter.
-
- KbdGetStatus Does not support the interim or turnaround character.
-
- KbdPeek Does not copy the system time to the KBDKEYINFO structure and
- provides no interim character support. This function retrieves characters
- only from the default keyboard (handle 0). The fbStatus field can be
- 0x0000 or SHIFT_KEY_IN. The hkbd parameter is ignored.
-
- KbdSetStatus Does not support the interim character or the turnaround
- character. Raw input mode with echo mode on is not supported. The hkbd
- parameter is ignored.
-
- KbdStringIn Ignores the hkbd parameter.
-
- VioScrLock Always indicates that the lock was successful.
-
-
- 3.5 Using the Command Line
-
- In standard C-language programs, you can use the argc and argv parameters
- of the main function to retrieve individual copies of the command-line
- arguments. You can use these parameters in MS OS/2 programs, but you can
- also retrieve the entire command line, exactly as the user typed it, by
- using the DosGetEnv function.
-
- When it starts a program, MS OS/2 prepares an environment segment for the
- program. This segment contains definitions of all environment variables,
- as well as the command line. The DosGetEnv function retrieves the segment
- selector for this environment segment and the address offset within that
- segment for the start of the command line.
-
- You can echo the command line on the screen by using the DosGetEnv
- function to get the address of the command line in the environment
- segment, as shown in the following sample program:
-
- #define INCL_DOS
- #include <os2.h>
-
- main( )
- {
- SEL selEnvironment;
- USHORT offCommand;
- PSZ pszCommandLine;
- USHORT cbWritten;
- USHORT i, cch;
-
- DosGetEnv(&selEnvironment, &offCommand);
- pszCommandLine = MAKEP(selEnvironment, offCommand);
-
- /*
- * The first string is the program name. The command line is the
- * next null-terminated string.
- */
-
- for (i = 0; pszCommandLine[i]; i++);
-
- /* Find the length of the command-line string. */
-
- for (i++, cch = 0; pszCommandLine[cch + i]; cch++);
-
- DosWrite(1, &pszCommandLine[i], cch, &cbWritten);
- }
-
- The command line has two parts. The first part is the program name,
- terminated by a zero byte. The second part is the rest of the command
- line, terminated by two zero bytes. The preceding program echoes the
- command line by skipping over the program name and then writing everything
- up to the next zero byte to the screen. The first for statement skips over
- the command name; the second for statement computes the length of the
- string. The MAKEP macro creates the far pointer that is needed to access
- the command line in the environment segment.
-
- You can examine your program's environment by using the selector retrieved
- by the DosGetEnv function. The program's environment consists of the
- environment variables that have been declared and passed to the program.
- Each program has a unique environment that is typically inherited from the
- program that started it──for example, from the MS OS/2 command processor,
- cmd.
-
- You can use the DosScanEnv function to scan for a specific environment
- variable. This function takes as an argument the name of the environment
- variable that you are interested in and copies the current value of this
- variable to a buffer that you supply. The following sample program uses
- DosScanEnv to display the value of the environment variable specified in
- the command line:
-
- #define INCL_DOSQUEUES
- #include <os2.h>
-
- main( )
- {
- SEL selEnvironment;
- USHORT offCommand;
- PSZ pszCommandLine;
- PSZ pszValue;
- USHORT cbWritten;
- USHORT i, cch;
-
- DosGetEnv(&selEnvironment, &offCommand);
- pszCommandLine = MAKEP(selEnvironment, offCommand);
-
- for (i = 0; pszCommandLine[i]; i++);
- for (i++; pszCommandLine[i] == ' '; i++);
-
- if (!DosScanEnv(&pszCommandLine[i], &pszValue)) {
- for (cch = 0; pszValue[cch]; cch++);
- DosWrite(1, pszValue, cch, &cbWritten);
- }
- }
-
-
- 3.6 Using Structures
-
- Many MS OS/2 functions use structures for input and output. To use a
- structure in an MS OS/2 function, you first define the structure in your
- program and then pass the 32-bit far address of the structure as a
- parameter in the function call.
-
- For example, the DosGetDateTime function copies the current date and time
- to a DATETIME structure whose address you supply. The fields of the
- DATETIME structure define the month, day, and year, as well as the time of
- day (to hundredths of a second). The DATETIME structure, defined in the
- os2.h file, has the following form:
-
- typedef struct _DATETIME { /* date */
- UCHAR hours;
- UCHAR minutes;
- UCHAR seconds;
- UCHAR hundredths;
- UCHAR day;
- UCHAR month;
- USHORT year;
- SHORT timezone;
- UCHAR weekday;
- } DATETIME;
-
- To retrieve the date and time, you call the DosGetDateTime function, using
- the address operator (&) to specify the address of the DATETIME structure.
- The following sample program shows how to make the call:
-
- #include <os2.h>
-
- CHAR szDayName[] = "MonTueWedThuFriSatSun";
- CHAR szMonthName[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
- CHAR szDate[] = "xx:xx:xx xxx xxx xx, xxxx\r\n";
- main( )
- {
- DATETIME date;
- SHORT offset;
- SHORT i;
- USHORT usYear;
- USHORT cbWritten;
-
- DosGetDateTime(&date); /* address of DATETIME structure */
-
- szDate[0] = (date.hours / 10) + '0';
- szDate[1] = (date.hours % 10) + '0';
- szDate[3] = (date.minutes / 10) + '0';
- szDate[4] = (date.minutes % 10) + '0';
- szDate[6] = (date.seconds / 10) + '0';
- szDate[7] = (date.seconds % 10) + '0';
- offset = date.weekday * 3;
- for (i = 0; i < 3; i++)
- szDate[i + 9] = szDayName[i + offset];
- offset = (date.month - 1) * 3;
- for (i = 0; i < 3; i++)
- szDate[i + 13] = szMonthName[i + offset];
- szDate[17] = (date.day < 10) ? ' ' : (date.day / 10 + '0');
- szDate[18] = (date.day % 10) + '0';
- usYear = date.year;
- szDate[21] = (usYear / 1000) + '0';
- usYear = usYear % 1000;
- szDate[22] = (usYear / 100) + '0';
- usYear = usYear % 100;
- szDate[23] = (usYear / 10) + '0';
- szDate[24] = (usYear % 10) + '0';
-
- DosWrite(1, szDate, 27, &cbWritten);
- }
-
- One drawback to using MS OS/2 functions exclusively is that there are no
- formatted output functions, such as the C-language printf function.
- Therefore, the preceding program formats the data itself before displaying
- it. The program uses the integer-division operators (/ and %) to convert
- binary numbers to ASCII characters. The program then copies the ASCII
- characters to a string and displays the string by using the DosWrite
- function.
-
- Some MS OS/2 functions require that you fill one or more fields of the
- structure before calling the function. For example, there are some
- structures whose length depends on the version of the operating system
- being used; MS OS/2 requires that you supply the expected length so that
- the function does not copy data beyond the end of your structure.
-
-
- 3.7 Using Bit Masks
-
- In MS OS/2, many functions use bit masks. A bit mask (also called an array
- of flags) is a combination of two or more Boolean flags in a single byte,
- word, or double-word value. In C-language programs, you can use the
- bitwise AND, OR, and NOT operators to examine and set the values in a bit
- mask.
-
- If a function retrieves a bit mask, you can check a specific flag in the
- bit mask by using the AND operator, as shown in the following code
- fragment:
-
- USHORT fsEvent;
-
- if (fsEvent & 0x0004)
- /* is the flag set? */
-
- You can set a flag in a bit mask by using the OR operator, as shown in the
- following code fragment:
-
- ULONG flFunctions;
-
- flFunctions = flFunctions | KR_KBDPEEK;
-
- Finally, you can clear a flag in a bit mask by using the AND and NOT
- operators, as shown in the following code fragment:
-
- USHORT fsEvent;
-
- fsEvent = fsEvent & ~0x0004;
-
-
- 3.8 Sharing Resources
-
- Many MS OS/2 functions let you use the resources of the computer, such as
- the keyboard, screen, disk, and even the system speaker. Since MS OS/2 is
- a multitasking operating system and more than one program may be running
- at a time, MS OS/2 considers all resources of the computer to be shared
- resources. As a result, programs must not claim exclusive access to a
- given resource.
-
- Consider a simple program that plays a short tune by using the DosBeep
- function. This function, when called by a single program, generates a tone
- at the system speaker, but if two programs call DosBeep at the same time,
- the result is chaotic. For example, try running two or more copies of the
- following program at the same time:
-
- #include <os2.h>
-
- #define CNOTES 14
- USHORT ausTune[] = {
- 440, 1000,
- 480, 1000,
- 510, 1000,
- 550, 1000,
- 590, 1000,
- 620, 1000,
- 660, 1000
- };
-
- main( )
- {
- int i;
-
- for (i = 0; i < CNOTES; i += 2)
- DosBeep(ausTune[i], ausTune[i + 1]);
- }
-
- The first parameter of the DosBeep function specifies the frequency of the
- note. The second parameter specifies the duration. The array ausTune
- defines frequency and duration values for each note in the tune.
-
- DosBeep is intended to be used for signaling the user when an error
- occurs, such as pressing an incorrect key. Since the system speaker is a
- shared resource, a process should use the DosBeep function sparingly.
-
-
- 3.9 C-Language Header Files
-
- The MS OS/2 C-language header file os2.h contains the definitions you need
- to use the functions, data types, structures, and constants described in
- the Microsoft Operating System/2 Programmer's Reference.
-
- When you include the os2.h file, the C preprocessor automatically defines
- many, but not all, of the most commonly used MS OS/2 functions. The os2.h
- header file is the "master" file of a set of files that contain the MS
- OS/2 function definitions. Each file contains definitions for the
- functions, data types, structures, and constants associated with a
- specific group of MS OS/2 functions. To minimize the time required to
- process the many header files, each function group is conditionally
- processed on the basis of whether a corresponding constant is defined
- within the program source file. The following is a list of these
- constants, with descriptions of the function groups they represent:
-
- ╓┌─┌────────────────────────┌────────────────────────────────────────────────╖
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_AVIO Includes all MS OS/2 version 1.1 AVIO functions.
-
- INCL_BASE Include all MS OS/2 version 1.1 system functions
- (Dos, Vio, Kbd, Mou).
-
- INCL_BITMAPFILEFORMAT Include the bitmap file-header structure
- BITMAPFILEHEADER.
-
- INCL_DEV Include all MS OS/2 version 1.1 device functions
- (Dev).
-
- INCL_DEVERRORS Include the Dev-function error constants.
-
- INCL_DOS Include all MS OS/2 version 1.1 kernel functions
- (Dos).
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- (Dos).
-
- INCL_DOSDATETIME Include the date/time and timer functions.
-
- INCL_DOSDEVICES Include the device and IOPL support functions.
-
- INCL_DOSDEVIOCTL Include all MS OS/2 version 1.1 input-and-output
- control functions (IOCtls).
-
- INCL_DOSERRORS Include the Dos-function error constants.
-
- INCL_DOSFILEMGR Include the file-management functions.
-
- INCL_DOSINFOSEG Include the information-segment functions.
-
- INCL_DOSMEMMGR Include the memory-management functions.
-
- INCL_DOSMISC Include miscellaneous Dos functions.
-
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_DOSMODULEMGR Include the module-manager functions.
-
- INCL_DOSMONITORS Include the monitor functions.
-
- INCL_DOSNLS Include national-language-support functions.
-
- INCL_DOSNMPIPES Include named-pipe functions.
-
- INCL_DOSPROCESS Include the process- and thread-support
- functions.
-
- INCL_DOSQUEUES Include the queue functions and other
- miscellaneous functions.
-
- INCL_DOSRESOURCES Include the resource-support functions.
-
- INCL_DOSSEMAPHORES Include the semaphore functions.
-
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_DOSSESMGR Include the session-manager functions.
-
- INCL_DOSSIGNALS Include the signal functions.
-
- INCL_DOSTRACE Include the DosPTrace function.
-
- INCL_ERRORS Include all MS OS/2 version 1.1 error constants.
-
- INCL_FONTFILEFORMAT Include the font-file structures.
-
- INCL_GPI Include all MS OS/2 version 1.1
- graphics-programming-interface functions (Gpi).
-
- INCL_GPIBITMAPS Include the bitmap and pel functions.
-
- INCL_GPICONTROL Include the basic presentation-space-control
- functions.
-
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_GPICORRELATION Include the pick-aperture, boundary, and
- correlation functions.
-
- INCL_GPIERRORS Include the Gpi-function error constants.
-
- INCL_GPILCIDS Include the physical- and logical-font functions.
-
- INCL_GPILOGCOLORTABLE Include the logical-color-table functions.
-
- INCL_GPIMETAFILES Include the metafile functions.
-
- INCL_GPIPATHS Include the path and clipping functions.
-
- INCL_GPIPRIMITIVES Include the drawing-primitive and
- primitive-attribute functions.
-
- INCL_GPIREGIONS Include the region and clipping functions.
-
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_GPISEGEDITING Include the segment-editing functions.
-
- INCL_GPISEGMENTS Include the segment-control and drawing
- functions.
-
- INCL_GPITRANSFORMS Include the transformation and
- transform-conversion functions.
-
- INCL_KBD Include all MS OS/2 version 1.1 keyboard
- functions (Kbd).
-
- INCL_MOU Include all MS OS/2 version 1.1 mouse functions
- (Mou).
-
- INCL_NOCOMMON Exclude any function group not explicitly
- defined.
-
- INCL_PM Include all MS OS/2 version 1.1 Presentation
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_PM Include all MS OS/2 version 1.1 Presentation
- Manager functions and structures.
-
- INCL_SHLERRORS Include the shell error constants.
-
- INCL_SUB Include all MS OS/2 version 1.1 video, keyboard,
- and mouse functions (Vio, Kbd, and Mou).
-
- INCL_VIO Include all MS OS/2 version 1.1 video functions
- (Vio).
-
- INCL_WIN Include all MS OS/2 version 1.1 window functions
- (Win).
-
- INCL_WINACCELERATORS Include the keyboard-accelerator functions.
-
- INCL_WINATOM Include the atom-manager functions.
-
- INCL_WINBUTTONS Include the button-control functions.
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_WINBUTTONS Include the button-control functions.
-
- INCL_WINCATCHTHROW Include the WinCatch and WinThrow support
- functions.
-
- INCL_WINCLIPBOARD Include the clipboard-manager functions.
-
- INCL_WINCOUNTRY Include the country-support functions.
-
- INCL_WINCURSORS Include the text-cursor functions.
-
- INCL_WINDIALOGS Include the dialog-box functions.
-
- INCL_WINENTRYFIELDS Include the entry-field functions.
-
- INCL_WINERRORS Include the Win-function error constants.
-
- INCL_WINFRAMECTLS Include the frame-control (title bar and size
- border) functions.
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- border) functions.
-
- INCL_WINFRAMEMGR Include the frame-manager functions.
-
- INCL_WINHEAP Include the heap-manager functions.
-
- INCL_WINHOOKS Include the hook-manager functions.
-
- INCL_WININPUT Include the mouse- and keyboard-input functions.
-
- INCL_WINLISTBOXES Include the list-box-control functions.
-
- INCL_WINMENUS Include the menu-control functions.
-
- INCL_WINMESSAGEMGR Include the message-management functions.
-
- INCL_WINPOINTERS Include the mouse-pointer functions.
-
- INCL_WINPROGRAMLIST Include the shell-program-list API functions.
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_WINPROGRAMLIST Include the shell-program-list API functions.
-
- INCL_WINRECTANGLES Include the rectangle functions.
-
- INCL_WINSCROLLBARS Include the scroll-bar-control functions.
-
- INCL_WINSHELLDATA Include the shell-data functions.
-
- INCL_WINSTATICS Include the static-control functions.
-
- INCL_WINSWITCHLIST Include the shell-switch-list API functions.
-
- INCL_WINSYS Include the system-value and color functions.
-
- INCL_WINTIMER Include the timer functions.
-
- INCL_WINTRACKRECT Include the WinTrackRect function.
-
- INCL_WINWINDOWMGR Include the general window-management functions.
- Constant Meaning
- ──────────────────────────────────────────────────────────────────────────
- INCL_WINWINDOWMGR Include the general window-management functions.
- ──────────────────────────────────────────────────────────────────────────
-
-
- To use a function within your program, you simply define the corresponding
- constant by using the #define directive before you include the os2.h file.
- For example, the following code fragment includes definitions for the
- memory-management and file-management functions:
-
- #define INCL_DOSMEMMGR
- #define INCL_DOSFILEMGR
- #include <os2.h>
-
- main( )
- {
- .
- .
- .
- }
-
- Once you have defined a constant, you can use any function, structure, or
- data type in that function group.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- PART 2 WINDOW MANAGER
- ────────────────────────────────────────────────────────────────────────────
- Chapter 4 Windows
- Chapter 5 Messages and Message Queues
- Chapter 6 Window Classes
- Chapter 7 Window Procedures
- Chapter 8 Mouse and Keyboard Input
- Chapter 9 Frame Windows
- Chapter 10 Control Windows
- Chapter 11 Title-Bar Controls
- Chapter 12 Button Controls
- Chapter 13 Entry-Field Controls
- Chapter 14 List-Box Controls
- Chapter 15 Static Controls
- Chapter 16 Scroll-Bar Controls
- Chapter 17 Menus
- Chapter 18 Accelerator Tables
- Chapter 19 Dialog Windows
- Chapter 20 Painting and Drawing
- Chapter 21 Drawing in Windows
- Chapter 22 Mouse Pointers and Icons
- Chapter 23 Cursors
- Chapter 24 Printing
- Chapter 25 Heaps
- Chapter 26 Clipboard
- Chapter 27 Dynamic Data Exchange
- Chapter 28 Hooks
- Chapter 29 Help
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 4 Windows
-
- 4.1 Introduction
- 4.2 About Windows
- 4.2.1 Desktop Windows
- 4.2.2 Application Windows
- 4.2.3 Window Creation
- 4.2.3.1 Window-Creation Functions
- 4.2.3.2 Window-Creation Messages
- 4.2.4 Window Handles
- 4.2.5 Window Size and Position
- 4.2.6 Window Styles
- 4.2.7 Window Destruction
- 4.2.8 Locked Windows
- 4.2.9 Disabled Windows
- 4.3 System-Modal Windows
- 4.3.1 Window Data
- 4.3.2 Subclassed Windows
- 4.3.3 Window Relationships
- 4.3.3.1 Parent-Child Relationship
- 4.3.3.2 Ownership
- 4.3.3.3 Object Windows
- 4.3.4 Visibility
- 4.3.5 Size
- 4.3.6 Position
- 4.3.6.1 Size and Position Messages
- 4.3.7 Z Order
- 4.3.8 Maximized and Minimized Windows
- 4.3.9 Redrawing Windows
- 4.3.10 System Commands
- 4.4 Using Windows
- 4.4.1 Creating a Window
- 4.4.2 Creating a Frame Window
- 4.4.3 Destroying a Window
- 4.4.4 Setting and Querying Window Data
- 4.4.5 Creating a Top-Level Window
- 4.4.6 Creating an Object Window
- 4.4.7 Changing the Parent Window
- 4.4.8 Finding a Parent, Child, or Owner Window
- 4.4.9 Setting an Owner Window
- 4.4.10 Finding a Child or Owned Window
- 4.4.11 Enumerating Top-Level Windows
- 4.4.12 Moving and Sizing a Window
- 4.4.13 Moving a Window in a Stack of Windows
- 4.4.14 Showing and Hiding a Window
- 4.4.15 Maximizing, Minimizing, and Restoring a Window
- 4.5 Summary
- 4.5.1 Window Functions
- 4.5.2 Standard Window Messages
- 4.5.3 Relationship Functions
- 4.5.4 Functions for Moving, Sizing, and Changing
- 4.5.5 Messages for Moving, Sizing, and Changing
-
- 4.1 Introduction
-
- This chapter describes the portions of MS OS/2 that let you create and use
- windows; manage relationships between windows; and size, move, and display
- windows in your Presentation Manager application. You should also be
- familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Application initialization and termination
-
- ■ Messages and message queues
-
- ■ Window classes and window procedures
-
-
- 4.2 About Windows
-
- A window is a rectangular area of the screen where an application displays
- output and receives input from the user. You might think of a window as a
- "graphics terminal" that shares the screen with other terminals. Only one
- "terminal" is active at a time, and when it is, a user can use the mouse
- and keyboard to interact with the application that owns the terminal.
-
- Unlike a graphics terminal, however, a window must be created by an
- application before it can be used. MS OS/2 does not create a window by
- default. This means that one of the first tasks of a Presentation Manager
- application is to create a window.
-
- 4.2.1 Desktop Windows
-
- MS OS/2 automatically creates two windows: the desktop window and the
- desktop-object window. The desktop window is the base (bottom-most) window
- in the Presentation Manager session. It is the window that paints the
- background for this session. It serves as the base for all windows created
- and displayed by applications. The desktop-object window is like a desktop
- window that is never displayed. It serves as a base for windows that
- coordinate the activity of other windows that are not displayed.
-
- 4.2.2 Application Windows
-
- Every application creates at least one window, called the main window, to
- serve as the "graphics terminal" for the application. The application also
- creates many other windows either directly or indirectly to carry out
- tasks related to the main window. In fact, most windows used by an
- application are composed of several different windows. Each window plays a
- part in displaying output and receiving input from the user.
-
- Typically, an application's main window is made up of several windows
- acting together as one. The main window is usually a frame window that
- contains a client window and one or more control windows, such as a title
- bar and a System menu.
-
- An application can use several types of windows: frame windows, client
- windows, control windows, dialog windows, message boxes, and menus.
-
- A frame window is a special window that the application uses as the base
- when constructing a main window or other composite window. A frame window
- provides basic features, such as borders and system-command processing,
- that a main window needs to conform to the MS OS/2 user-interface
- guidelines.
-
- A dialog window is a frame window that contains one or more control
- windows. Dialog windows are used almost exclusively for prompting the user
- for input. An application usually creates a dialog window when it needs
- additional information to complete a command. It then destroys the dialog
- window when the requested information has been entered.
-
- A message box is a frame window that an application uses to display a
- note, caution, or warning to the user. Message boxes are commonly used to
- inform the user of problems the application encounters while carrying out
- a task.
-
- A client window is the window in which the application displays the
- current document or data. For example, a desktop-publishing application
- displays the current page of a document in a client window. Most
- applications create at least one client window. The application must
- process input to the window and then display output.
-
- A control window is any window used in conjunction with another window to
- carry out useful input or output tasks, such as displaying messages or
- reading text. MS OS/2 provides several predefined control-window classes
- that can be used to create control windows. Control windows include
- buttons, entry fields, list boxes, menus, scroll bars, static text, and
- title bars.
-
- A menu is a control window that presents a list of commands and other
- menus to the user. The user chooses commands from the list by using a
- mouse or keyboard. The application then carries out the chosen task.
-
- Many simple applications create only a main window. The application
- manages the client window and allows the frame and control windows to
- operate as defined by MS OS/2.
-
- 4.2.3 Window Creation
-
- An application creates windows by using a window-creation function, such
- as WinCreateWindow, and supplying information about the window to be
- created. An application can create one or more windows in any thread for
- which it has created a message queue. An application creates a message
- queue for a thread by using the WinCreateMsgQueue function after
- initializing the application for Presentation Manager by using the
- WinInitialize function.
-
- The following information must be supplied when creating a window:
-
- ■ Window class
-
- ■ Window name
-
- ■ Parent window
-
- ■ Window position relative to the parent window
-
- ■ Window position relative to its sibling windows (Z order)
-
- ■ Window width and height
-
- ■ Window styles
-
- ■ Owner window
-
- ■ Window identifier
-
- ■ Class-specific data
-
- Every window belongs to a window class. The window class defines how the
- window behaves and appears when operating. The chief component of the
- window class is the window procedure. The window procedure is a function
- that receives and processes all input and requests for action sent to the
- window by the system. The window class also defines the class styles.
- These tell MS OS/2 what initial window styles to give a window created
- with this class.
-
- A window can have a name. A window name is a text string that identifies
- the window for the user. The window name is typically displayed in the
- window or in a title bar within the window. How the name is used depends
- on the window class.
-
- Every window created has a parent window. The parent window provides the
- coordinate system used for positioning the window and defines the
- relationship the new window has with other windows in the system. The
- parent window also affects the behavior and appearance of the window. For
- example, when the parent window is hidden, the child window is also
- hidden.
-
- Every window has a position, size, and Z-order position. The position
- specifies the location on the screen of the window's lower-left corner.
- This position is relative to the lower-left corner of the parent window
- (in pels). A window's size is the width and height in the window (in
- pels). A window's Z-order position specifies the position of the window in
- the stack of overlapping windows. The window at the top of the Z order
- overlaps all sibling windows (that is, windows having the same parent
- window). A window at the bottom of the Z order is overlapped by all
- sibling windows. An application sets a window's Z-order position by
- placing it behind a given sibling window.
-
- Every window can have a style. The window style specifies how the window
- behaves or appears. For example, a window style can specify whether the
- window is visible or invisible when first created. A few window styles
- apply to all windows, but most apply to windows of specific window
- classes. The window procedure for that class interprets the style.
-
- A window can be owned by another window. An owner window is similar to a
- parent window, but it does not affect the behavior or appearance of the
- window in the same way. The owner window usually coordinates the activity
- of a window so that it can operate in conjunction with other windows. The
- window sends messages about its state to its owner window; the owner
- window sends messages about what action to carry out next.
-
- A window can have a window identifier. A window identifier uniquely
- identifies a window that operates in conjunction with other windows. A
- window identifier is especially useful if a window sends information to
- the owner window.
-
- A window can have class-specific data. This data further defines how the
- window behaves and appears when first created. The system passes
- class-specific data to the window procedure. The window procedure then
- applies the data to the new window.
-
- 4.2.3.1 Window-Creation Functions
-
- The basic window-creation function is WinCreateWindow. The WinCreateWindow
- function takes window class, style, size, and position information and
- creates a new window. All other window-creation functions, such as
- WinCreateStdWindow and WinCreateDlg, supply some of this information by
- default and create windows of a specific class or style.
-
- Although WinCreateWindow provides the most direct means of creating a
- window, most applications do not use it. Instead, they typically use the
- WinWinCreateStdWindow function to create a main window and use the
- WinDlgBox or WinCreateDlg function to create dialog windows.
-
- The WinCreateMenu, WinLoadMenu, WinLoadDlg, WinMessageBox, and
- WinCreateFrameControls functions also create windows. Each of these
- functions substitutes for one or more calls to the WinCreateWindow
- function required to create a given window. For example, you can create a
- frame window, one or more control windows, and a client window, all in a
- single call to WinCreateStdWindow.
-
- 4.2.3.2 Window-Creation Messages
-
- The system sends messages to the window procedure as it creates a window.
- Each window procedure receives a WM_CREATE message, specifying that the
- window is being created.
-
- The system also sends a WM_ADJUSTWINDOWPOS message, specifying the size
- and position for the window. This message allows the window procedure to
- adjust the size and position before they are actually applied to the
- window.
-
- The system also sends other messages. The number and order of these
- messages depend on the window class and style and on the function used to
- create the window.
-
- 4.2.4 Window Handles
-
- When a window is created, the creation function returns a window handle. A
- window handle uniquely identifies the window and can be used in functions
- to direct the action of the function to the window. Window handles have
- the data type HWND; applications must use this type when declaring the
- variables that hold window handles.
-
- There are several special constants that can be used in place of a window
- handle in certain functions. For example, HWND_DESKTOP can be used in the
- WinCreateWindow function to specify the desktop window as the new window's
- parent window. Similarly, HWND_OBJECT represents the desktop-object
- window. HWND_TOP and HWND_BOTTOM represent the top and bottom positions
- when setting the Z-order position for a window.
-
- Although the NULL constant is not a window handle, it can be used in some
- functions to specify that no window is affected. For example, NULL can be
- used in the WinCreateWindow function to specify that there is no owner
- window. Some functions may return NULL, indicating that the given action
- applies to no window.
-
- 4.2.5 Window Size and Position
-
- A window's size and position can be expressed as a bounding rectangle,
- given in coordinates relative to its parent window. The window's size and
- position can be explicitly specified when it is created, or the system can
- use default values. The window's size and position can be changed at any
- time.
-
- The default coordinate system for a window specifies that the point (0,0)
- is at the window's lower-left corner; coordinates increase upward and to
- the right.
-
- When two sibling windows overlap, the system must specify which window is
- displayed in front. This ordering of sibling windows is known as the Z
- order. For more information about Z order, see Section 4.3.7.
-
- 4.2.6 Window Styles
-
- A window style is a value that specifies how a window behaves or appears
- in a given situation. Window styles let applications adapt windows of a
- given class for special circumstances. For example, an application can
- give a window the style WS_SYNCPAINT to cause it to paint immediately
- whenever any portion of the window becomes invalid. A window normally
- paints only if there are no messages waiting in the message queue.
-
- An application usually sets the window style when it creates the window.
- It can also set the window style after creation by using the WinShowWindow
- and WinSetWindowULong functions. MS OS/2 provides several standard window
- styles that apply to all windows. It also provides many styles for the
- predefined frame and control windows. The frame and control styles are
- unique to each predefined window class and can be used only for windows
- belonging to the corresponding class.
-
- Initially, the class styles of the window class used to create the window
- determine the window styles of the new window. If the window class has the
- style CS_SYNCPAINT, all windows created using that class have the style
- WS_SYNCPAINT by default.
-
- MS OS/2 has the following standard window styles:
-
- ╓┌─┌───────────────────┌─────────────────────────────────────────────────────╖
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- WS_VISIBLE Makes the window visible. MS OS/2 draws the window on
- the screen unless overlapping windows completely
- obscure it. Windows without this style are hidden. If
- overlapping windows completely obscure the window, the
- window is still considered to be visible. Visibility
- simply means that MS OS/2 draws the window if it can.
-
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- WS_DISABLED Disables mouse and keyboard input to the window. This
- style is used to temporarily prevent the user from
- using the window.
-
- WS_CLIPCHILDREN Prevents a window from painting over its child
- windows.
-
- WS_CLIPSIBLINGS Prevents a window from painting over its sibling
- windows.
-
- WS_PARENTCLIP Prevents a window from painting over its parent
- window.
-
- WS_SAVEBITS Saves the image under the window as a bitmap. When the
- window is moved or hidden, the system restores the
- image by copying the bits.
-
- WS_SYNCPAINT Causes the window to immediately receive WM_PAINT
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- WS_SYNCPAINT Causes the window to immediately receive WM_PAINT
- messages after a part of the window becomes invalid.
- Without this style, the window receives WM_PAINT
- messages only if no other message is waiting to be
- processed.
-
- WS_MINIMIZED Reduces the window to the minimum size.
-
- WS_MAXIMIZED Enlarges the window to the maximum size.
-
- WS_GROUP Identifies the window as the first dialog item in a
- group of dialog items. This style is used with
- controls in dialog windows to permit the user to move
- among the controls by pressing the direction keys.
-
- WS_TABSTOP Identifies the window as a tabstop window. This style
- is used with controls in dialog windows to permit the
- user to move to the control by pressing the TAB key.
- ──────────────────────────────────────────────────────────────────────────
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- ──────────────────────────────────────────────────────────────────────────
-
-
- 4.2.7 Window Destruction
-
- An application can destroy the windows it has created. When a window is
- destroyed, the system hides the window if it is visible, and then removes
- any internal data associated with the window. This invalidates the window
- handle; it can no longer be used in functions. An application destroys a
- window by using the WinDestroyWindow function.
-
- Most applications destroy the windows they create soon after creating
- them. For example, an application usually destroys any dialog windows as
- soon as the application has sufficient input from the user to continue its
- task. An application eventually destroys the main window of the
- application (before terminating). In general, an application must destroy
- all the windows it creates.
-
- Destroying a window does not affect the window class from which the window
- is created. New windows can still be created using that class and any
- existing windows of that class continue to operate.
-
- Destroying a window also destroys that window's child and owned windows.
- The WinDestroyWindow function sends a WM_DESTROY message to the window,
- which in turn sends the same message to all its child and owned windows.
- Each child and owned window passes the message on to other child and owned
- windows. In this way, all descendant windows of the window being destroyed
- are also destroyed.
-
- Before destroying a window, an application should save or remove any data
- associated with the window and release any resources. For example, a
- presentation space created for the window by the WinGetPS function must be
- released by calling the WinReleasePS function. This must be done before
- calling the WinDestroyWindow function. If a presentation space is
- associated with the device context for the window, the application should
- disassociate or destroy the presentation space by using the GpiAssociate
- or GpiDestroyPS function before calling WinDestroyWindow. Failing to
- release a resource can cause an error.
-
- The WinDestroyWindow function may send several messages to a window. The
- following is a list of possible messages sent by WinDestroyWindow:
-
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_DESTROY Always sent to the window being destroyed after it has been
- hidden, but before its child windows have been destroyed.
-
- WM_ACTIVATE Sent with the first message parameter equal to FALSE if the
- window being destroyed is the active window.
-
- WM_OTHERWINDOWDESTROYED
- Sent to all main windows of the window being destroyed and
- to its descendant windows, if the window being destroyed
- has been registered with the WinRegisterWindowDestroy
- function.
-
- WM_RENDERALLFMTS
- Sent if the clipboard owner is being destroyed and there
- are unrendered formats on the clipboard.
- ──────────────────────────────────────────────────────────────────────────
-
- If the window being destroyed is the active window, both the active and
- focus states are transferred to another window. The window that becomes
- the active window is the next window (as defined by the ALT+ESC key
- combination). The new active window determines which window has the input
- focus.
-
- 4.2.8 Locked Windows
-
- A window can be locked. An application typically locks a window to prevent
- it from being destroyed. This is useful whenever a window needs to access
- data that may be lost if the associated window is destroyed. An
- application can lock a window by using the WinLockWindow function.
-
- Each window has a lock count. When a window is created, its lock count is
- set to zero, meaning that the window is unlocked. An application can use
- the WinLockWindow function to increment or decrement the lock count. If
- the lock count is greater than zero, the window is locked. If the lock
- count is zero, the window is unlocked. The lock count can never be less
- than zero. An application can retrieve the current lock count by using the
- WinQueryWindowLockCount function.
-
- The WinQueryWindow, WinQueryActiveWindow, and WinQuerySysModalWindow
- functions also lock a window if specified.
-
- 4.2.9 Disabled Windows
-
- A window can be disabled. A disabled window temporarily receives no
- keyboard or mouse input. An application typically disables a window to
- prevent the user from using the window. For example, the application may
- disable a push button in a dialog window to prevent the user from choosing
- it. An application can enable a disabled window at any time. Enabling a
- window restores normal input. An application enables or disables a window
- by using the WinEnableWindow function.
-
- By default, a window is enabled when created. The WS_DISABLED style can be
- specified, however, to disable a new window. If an application uses the
- WinEnableWindow function to disable an existing window, that window also
- loses the keyboard focus. The keyboard focus is set to NULL, meaning no
- window has the focus. If a child window or other descendant window has the
- keyboard focus, the descendant window loses it when the window is
- disabled.
-
- An application can determine whether a window is disabled by using the
- WinIsWindowEnabled function.
-
-
- 4.3 System-Modal Windows
-
- System-modal windows require the user to respond immediately to warnings
- about the state of the system. Because the system-modal window receives
- all keyboard and mouse input, all other windows are effectively disabled
- when the system-modal window is set; the user cannot continue working in
- other windows until the system-modal window has been cleared. An
- application sets and clears the system-modal window by using the
- WinSetSysModalWindow function.
-
- Due to its absolute control of input, applications must use care when
- setting a system-modal window. Ideally, an application uses a system-modal
- window only when there is danger of losing data if the user does not
- respond to the problem immediately.
-
- Although an application can destroy a system-modal window, the new active
- window will also be the new system-modal window. An application can also
- make another window active while the system-modal window exists. Again,
- the new active window is also the new system-modal window. In general,
- once a system-modal window is set, a system-modal window will continue to
- exist in the Presentation Manager session until explicitly cleared.
-
- 4.3.1 Window Data
-
- Every window has an associated data structure. The window data structure
- contains all the information specified for the window when it was created
- and any additional information supplied for the window since creation.
- Although the exact number and meaning of fields in the window data
- structure is private to the system, an application can directly access any
- of the following fields:
-
- ■ Pointer to window-class data structure
-
- ■ Pointer to window procedure
-
- ■ Parent-window handle
-
- ■ Owner-window handle
-
- ■ Handle of first child window
-
- ■ Handle of next sibling window
-
- ■ Window size and position (expressed as a rectangle)
-
- ■ Lock count
-
- ■ Window style
-
- ■ Window identifier
-
- ■ Update-region handle
-
- ■ Message-queue handle
-
- An application can examine and modify these fields by using functions such
- as WinQueryWindowUShort and WinSetWindowUShort. These functions let an
- application access fields, such as the lock count, which are stored as
- 16-bit integers. Other functions let an application access fields
- containing 32-bits integers and pointers. There are several fields that
- indirectly affect the fields in the window data structure. For example,
- the WinLockWindow function modifies the lock-count field; the
- WinSubclassWindow function replaces the window-procedure pointer.
-
- An application can extend the number of available fields in the window
- data structure by specifying a count of extra bytes when it registers the
- corresponding window class. The window procedure can then use these bytes
- to store information about the window. Functions such as
- WinQueryWindowUShort and WinSetWindowUShort give direct access to the
- extra bytes.
-
- If a window needs more than a few bytes of storage added to the window
- data structure, using extra bytes alone is not the best solution. One
- common alternative is to dynamically allocate some memory and then store a
- pointer to that dynamic memory in the extra bytes of the window data
- structure.
-
- 4.3.2 Subclassed Windows
-
- A subclassed window is any window whose original window procedure has been
- replaced with another window procedure. The original window procedure is
- specified by the window class used to create the window. An application
- typically subclasses a window (replaces the window procedure) so that it
- can support additional capabilities in a window created with a given
- class. For example, an application may subclass a push-button control so
- that it can add sound when the user chooses the button. An application
- subclasses a window by using the WinSubclassWindow function.
-
- Typically, a window procedure used to subclass a window will pass most (if
- not all) messages on to the original window procedure. The usual goal of
- subclassing is to add capability. The WinSubclassWindow function returns
- the address of the original window procedure, making it easy to call the
- original function from the new window procedure. The following code
- fragment shows the general format of a window procedure used for
- subclassing:
-
- PFNWP pfnwp;
-
- main() {
-
- /* Subclass in main function or other window procedure. */
-
- pfnwp = WinSubclassWindow(hwnd, MySubClass);
- }
-
- MRESULT CALLBACK MySubClass(hwnd, usMessage, mp1, mp2)
- HWND hwnd;
- USHORT usMessage;
- MPARAM mp1;
- MPARAM mp2;
- {
- switch (usMessage) {
- .
- . /* Process messages. */
- .
- }
- return (pfnwp(hwnd, usMessage, mp1, mp2));
- }
-
- Note that the replacement window procedure calls the original window
- procedure instead of the WinDefWindowProc function.
-
- An application can subclass only one window at a time. It cannot subclass
- an entire class.
-
- 4.3.3 Window Relationships
-
- Window relationships define how windows interact with each other on the
- screen and through messages. There are parent-child window relationships
- and ownership relationships.
-
- The parent-child relationship determines how a window looks when drawn on
- the screen. It also determines what happens to a window when a related
- window is destroyed or hidden. The parent-child rules apply to all windows
- at all times and cannot be modified.
-
- Ownership determines how windows communicate using messages. Cooperative
- windows define the rules of ownership and then carry them out. Although
- some windows, such as windows belonging to the preregistered, public
- window class WC_FRAME, have quite complex rules of ownership, the
- application ordinarily defines the ownership rules.
-
- 4.3.3.1 Parent-Child Relationship
-
- Most windows have a parent window. (The exceptions to this rule are the
- desktop and the desktop-object windows. These windows, created by the
- system when it first starts, have no parent windows.) An application sets
- the parent window when it creates the window; the system uses the parent
- window to determine where and how to draw the new window, as well as when
- to destroy the window.
-
- A window is drawn relative to its parent window. The coordinates given to
- specify the position of a window's lower-left corner are relative to the
- lower-left corner of its parent window. For example, a window whose
- coordinates are (10,10) is placed 10 pels left and 10 pels up from the
- lower-left corner of its parent window. A window is a top-level window if
- its parent window is the desktop window. Top-level windows are drawn
- relative to the lower-left corner of the screen (the desktop window's
- lower-left corner).
-
- Windows with the same parent window are called sibling windows. All
- top-level windows are sibling windows since they share a common parent
- window, the desktop window. Sibling windows can overlap; an application or
- a user can arrange the windows so that some appear on top of others. Every
- sibling window has a Z-order position that specifies where it lies in the
- stack of overlapping windows. The parent window for the sibling windows is
- always at the bottom of the stack.
-
- A window is clipped to its parent window. This means that no part of a
- child window is ever drawn outside of its parent window. If an application
- creates a child window that is larger than the parent window or positions
- a child window so that some or all of the window extends beyond the edges
- of the parent window, the system automatically clips (does not draw) the
- portion of the child window that extends beyond the edges. Depending on
- the window styles for a window, a window may also be clipped to its child
- and its sibling windows. When a window has the style WS_CLIPCHILDREN or
- WS_CLIPSIBLINGS, the system clips the window.
-
- A window is destroyed when its parent window is destroyed. When the parent
- window is destroyed, the system sends WM_DESTROY messages to each child
- window. This is convenient for composite windows (for example, the
- application's main window) since an application needs to destroy only the
- parent window; all the related windows, including the client window, are
- destroyed automatically. The parent window is always the last window to be
- destroyed. This allows the parent window to use any data saved or left
- behind by its child windows.
-
- While every window has only one parent window, a window can have any num-
- ber of child windows. Any child window can have child windows. Each child
- window in this chain of windows is a called a descendant window of the
- original parent window. Immediate child windows are child windows directly
- related to the parent window, not just descendant windows.
-
- An application can change a window's parent window at any time. Changing
- the parent window changes where and how the child window is drawn.
-
- 4.3.3.2 Ownership
-
- Any window can have an owner window. An owner is a window, not necessarily
- a parent window, that controls some aspect of another window. Applications
- typically use ownership to establish a connection between windows so that
- together they can carry out useful tasks. For example, the title bar in an
- application's main window is owned by the frame window. Together they let
- the user move the entire main window by clicking the mouse in the title
- bar. An application can set the owner window when it creates the window,
- or it can set the owner window at a later time.
-
- Ownership establishes a relationship between windows that is independent
- of the parent-child relationship. Unlike parent and child windows, there
- are no predefined rules for how the owner and owned windows interact. The
- window procedures for the owner and owned windows must carry out any
- special interactions specified.
-
- The preregistered, public window classes provided by MS OS/2 recognize
- ownership. Control windows, created with classes such as WC_TITLEBAR and
- WC_SCROLLBAR, notify their owners of events; frame windows, created using
- the WC_FRAME class, receive and process notification messages from the
- control windows they own. For example, a title-bar control sends a
- notification message to its owner when it receives a mouse click. If the
- owner is a frame window, the frame window receives the notification
- message and prepares to move the frame window and its child windows.
-
- Owner and owned windows must be created by the same thread; that is, they
- must belong to the same message queue. Since ownership is independent of
- the parent-child relationship, the owner and owned windows do not have to
- be descendants of the same parent window. This means one window can be a
- descendant of the desktop window and the other a descendant of the
- desktop-object window. This can affect how windows are destroyed.
- Destroying the owner window does not necessarily destroy the owned window.
- An application must explicitly destroy any owned window that is not a
- descendant window of the owner.
-
- Frame windows often have owned windows that are not descendants (they are
- sibling windows instead). A frame window has the following special
- properties:
-
- ■ Destroys all owned windows, even if they are not descendants, when the
- frame window is destroyed.
-
- ■ Moves owned windows when the frame window moves. The owned windows that
- are not descendants maintain their position relative to the upper-left
- (not the usual lower-left) corner of the owner window. Any owned window
- with the style FS_NOMOVEWITHOWNER does not move.
-
- ■ Changes the Z-order position of all owned windows when the frame window
- changes.
-
- ■ Hides all owned windows when the frame window is minimized or hidden.
- Owned windows hidden in this way are restored when the frame window is
- restored.
-
- If an application needs the same special processing for its own window
- classes, it must provide that support in the window procedures for those
- classes.
-
- 4.3.3.3 Object Windows
-
- Any descendant of the desktop-object window is called an object window. An
- object window is like any other window but it is not displayed.
- Applications typically use object windows to provide services for windows.
- For example, an application might use an object window to manage a shared
- database. The advantage of using an object window in this way is that a
- window can request information from the database by sending a message to
- the object window and receive a reply as a message.
-
- Because object windows are not displayed, the window procedure for an
- object window does not have to process input and paint messages. This
- means that an application can use object windows just as it would other
- objects in object-oriented environments. The object window processes
- messages that affect the data belonging to the object.
-
- The rules for parent-child relationship and ownership also apply to object
- windows. In particular, changing the parent window of an object window to
- the desktop window or to a descendant of the desktop window causes the
- system to display the window if it is visible.
-
- 4.3.4 Visibility
-
- A window can be visible or invisible. The system displays visible windows
- on the screen. It hides invisible windows by not drawing them. If a window
- is visible, the user can supply input to the window and view output. If a
- window is invisible, the window is effectively disabled. An application
- sets a window's visibility state when it creates the window. Later, a user
- or the application can change these initial values.
-
- A window is visible if the style WS_VISIBLE is set for the window. An
- application can set this style when it creates the window. By default, the
- WinCreateWindow function creates invisible windows unless the WS_VISIBLE
- style is given. After a window is created, an application typically hides
- a window to hide the details of operation from the user. For example, an
- application may keep a new window invisible while it customizes the
- window's appearance.
-
- Even if a window is visible, the user may not be able to see the window on
- the screen. Other windows may completely overlap the window or the window
- may have been moved beyond the edge of the screen. The window is
- considered visible but it cannot be seen.
-
- A visible window is subject to the clipping rules established by its
- parent-child relationship. If the window's parent window is not visible,
- the window will not be visible. Since a child window is drawn relative to
- the parent's lower-left corner, if the parent window is moved beyond the
- edge of the screen, the child window will also move.
-
- A user may move only part of the parent window containing the child window
- off the edge of the screen, so although the window and its parent window
- are visible, the user may not be able to see them. An application
- determines whether the user can actually see a visible window by checking
- the window's current position.
-
- 4.3.5 Size
-
- Every window has a size (width and height) given in pels. The size can be
- any integer value in the range 0 through 65,535. A window can have zero
- width and/or height. A window with zero width or height is not drawn on
- the screen even though it may be visible.
-
- Although an application can create very large windows, it should consider
- the size of the screen when choosing a window size. One way to choose an
- appropriate size is to use the WinGetMaxPosition function to retrieve the
- size of the maximized window. A window that is larger than its maximized
- size will also be larger than the screen.
-
- An application can retrieve the current size of the window by using the
- WinQueryWindowRect function.
-
- 4.3.6 Position
-
- Every window has a position. The position is specified as the coordinates
- of the window's lower-left corner. The coordinates, sometimes called
- window coordinates, are always relative to the lower-left corner of the
- parent window.
-
- To improve drawing performance, a frame window may adjust its horizontal
- position so that it is a multiple of 8, relative to the screen origin (the
- lower-left corner of the screen). Coordinates that are multiples of 8
- correspond to byte boundaries in the screen-memory bitmap. It is usually
- faster to draw starting at a byte boundary. An application can override
- this action by using the FCF_NOBYTEALIGN style when creating the window.
-
- 4.3.6.1 Size and Position Messages
-
- A window receives messages when it changes size or position. Before a
- change is actually made, the system may send a WM_ADJUSTWINDOWPOS
- message to allow the window procedure to make final adjustments to the
- window's size and position. This message includes an SWP structure that
- contains the width, height, and position requested. If the window
- procedure adjusts these values in the structure, the system uses the
- adjusted values to draw the new window. The WM_ADJUSTWINDOWPOS message is
- not sent if the change is a result of a call to the WinSetWindowPos
- function and the SWP_NOADJUST constant is specified.
-
- After a change has been made to a window, the system sends a WM_SIZE
- message to specify the new size of the window. If the window has the class
- style CS_MOVENOTIFY, the system also sends a WM_MOVE message. The WM_MOVE
- message includes the new position for the window. The system sends a
- WM_SHOW message if the visibility of the window has changed.
-
- 4.3.7 Z Order
-
- Every window has a Z-order position. Imagine an axis extends outward from
- the screen toward the viewer. A window at the top of the Z order is
- displayed in front of its sibling windows when the windows overlap. A
- window at the bottom of the Z order is displayed behind its sibling
- windows when the windows overlap.
-
- 4.3.8 Maximized and Minimized Windows
-
- A maximized window is a window that has been enlarged so it fills the
- screen. Although a window's size can be set so it exactly fills the
- screen, a maximized window is slightly different──the system automatically
- moves the window's title bar to the top of the screen and sets the
- WS_MAXIMIZED window style.
-
- A minimized window is a window whose size has been reduced so that it is
- exactly the size of an icon. Like a maximized window, a minimized window
- is more than just a window of a given size. The system typically moves the
- minimized window to the lower part of the screen and sets the WS_MINIMIZED
- style for that window. The lower part of the screen is sometimes call the
- icon area. The system moves a minimized window into the first available
- icon position in the icon area if no other position is specified.
-
- If a window is created with the styles WS_MAXIMIZED or WS_MINIMIZED, the
- system draws the window as a maximized or minimized window.
-
- An application can restore a maximized or minimized window to its previous
- size and position.
-
- 4.3.9 Redrawing Windows
-
- After the system moves or changes the size of a window, it may invalidate
- all or part of the window. If at all possible, the system tries to
- preserve the contents of the window and simply copy them to the new
- position. But if a window's size has increased, the window must fill the
- area exposed by the size change. If a window has moved from behind an
- overlapping window, any area that was formerly obscured by the other
- window must be drawn. In these cases, the system invalidates the exposed
- areas and the window receives a WM_PAINT message.
-
- An application can require that the system invalidate the entire window
- for each move or size change by setting the CS_SIZEREDRAW class style in
- the corresponding window class. This class style is typically used for
- applications that use the window's current size and position to determine
- how to draw the window. For example, a clock application may always draw
- the face of the clock so that it exactly fills the window.
-
- An application can also explicitly specify which parts of the window to
- preserve during a move or size change. Before any change is made, the
- system sends a WM_CALCVALIDRECTS message to windows that do not have the
- style CS_SIZEREDRAW. This allows the window procedure to specify what part
- of the window to save and where to align it after the move or size change.
-
- 4.3.10 System Commands
-
- An application that has a window with a System menu can change the size
- and position of that window by sending system commands. The system
- commands are usually generated by the user choosing commands from the
- System menu. An application can emulate the user action by sending a
- WM_SYSCOMMAND message to the window.
-
- Some of the system commands are listed here:
-
- Command Description
- ──────────────────────────────────────────────────────────────────────────
- SC_SIZE Starts a size command. The user can change the size of
- the window by using the mouse or keyboard.
-
- Starts a move command. The user can move the window by
- using the mouse and keyboard.
-
- SC_MOVE Starts a move command. The user can move the window by
- using the mouse and keyboard.
-
- SC_MINIMIZE Minimizes the window.
-
- SC_MAXIMIZE Maximizes the window.
-
- SC_RESTORE Restores a minimized or maximized window to its previous
- size and position.
-
- SC_CLOSE Closes the window. This command sends a WM_CLOSE message
- to the window. The window carries out any steps needed
- to clean up and destroy itself.
- ──────────────────────────────────────────────────────────────────────────
-
-
- 4.4 Using Windows
-
- The following sections explain how to create and use windows in an
- application, how to manage ownership and parent-child window
- relationships, and how to move and size windows.
-
- 4.4.1 Creating a Window
-
- You create windows by using the WinCreateWindow function.
-
- For all windows, the parent-child relationship is set when you create the
- window using the WinCreateWindow function or other window-creation
- function. You can set the ownership for a window at any time. (Note that a
- window does not need an owner window unless you want to establish a
- relationship other than the standard parent-child relationship for the
- window.)
-
- You can specify the initial size and position for a window when you create
- it. You can change these settings at any time.
-
- 4.4.2 Creating a Frame Window
-
- Although WinCreateWindow can be used to create all windows, most
- applications do not call this function. Instead, they use the
- WinCreateStdWindow function to create frame windows and the WinDlgBox or
- WinCreateDlg function to create dialog windows.
-
- 4.4.3 Destroying a Window
-
- You can destroy a window by using the WinDestroyWindow function. The
- following code fragment shows how to create and then destroy an
- entry-field control:
-
- HWND hwndMain; /* application's main window */
- HWND hwnd;
-
- hwnd = WinCreateWindow(...);
-
- /* Read from the control. */
-
- WinDestroyWindow(hwnd);
-
- 4.4.4 Setting and Querying Window Data
-
- You can examine the data associated with a window by using the
- WinQueryWindowUShort and WinQueryWindowULong functions.
-
- Each of these functions specifies a field to examine. The index value can
- be an integer representing a zero-based index or a constant (QW_) that
- specifies a specific field.
-
- 4.4.5 Creating a Top-Level Window
-
- You can create a top-level window by setting the desktop window as the
- window's parent window. Almost all main windows for applications are
- top-level windows; the desktop window is frequently given in calls to the
- WinCreateStdWindow function.
-
- The following code fragment creates a top-level window for an application:
-
- /* Set the creation flags. */
-
- ULONG flCreationFlags =
- FCF_TITLEBAR | /* title bar */
- FCF_SIZEBORDER | /* size border */
- FCF_MINMAX | /* minimize and maximize buttons */
- FCF_MENU | /* menu */
- FCF_SYSMENU | /* System menu */
- FCF_HORZSCROLL | /* horizontal scroll bar */
- FCF_VERTSCROLL; | /* vertical scroll bar */
-
- /*
- * Create a frame window with a client window that belongs to the
- * window class "MyPrivateClass".
- */
-
- hwndFrame = WinCreateStdWindow(
- HWND_DESKTOP, /* owner is desktop window */
- 0L, /* no styles for frame window */
- &flCreationFlags, /* frame controls */
- "MyPrivateClass", /* window class for client */
- "Sample Window", /* window title */
- 0L, /* no styles for client */
- NULL, /* use application's module */
- 1, /* resource ID */
- &hwndClient); /* client handle */
-
- 4.4.6 Creating an Object Window
-
- You can create an object window by using the WinCreateWindow function and
- setting the desktop-object window as the parent window.
-
- The following code fragment creates an object window:
-
- hwndObject = WinCreateWindow(
- HWND_OBJECT, /* parent is object window */
- "MyPrivateClass", /* window class for client */
- "Sample Window", /* window title */
- 0L, /* no styles for object window */
- 0, 0, /* lower-left corner */
- 0, 0, /* width and height */
- NULL, /* no owner */
- HWND_TOP, /* insert at top of Z order */
- 1, /* window ID */
- NULL, /* no class-specific data */
- NULL); /* no presentation data */
-
- 4.4.7 Changing the Parent Window
-
- You can change a window's parent window by using the WinSetParent
- function. For example, an application that uses child windows to display
- documents may want only the active-document window to show a System menu.
- One way to do this is to change that menu's parent window back and forth
- between the document window and the object window when WM_ACTIVATE
- messages are received. This is shown in the following code fragment:
-
- case WM_ACTIVATE:
- hwndMenu = WinWindowFromID(hwnd, FID_MENU);
- if (SHORT1FROMMP(mp1) == TRUE)
- WinSetParent(hwndMenu, hwnd, TRUE);
- else
- WinSetParent(hwndMenu, HWND_OBJECT, TRUE);
-
- 4.4.8 Finding a Parent, Child, or Owner Window
-
- You can determine the parent, child, and owner windows for any window by
- using the WinQueryWindow function. The function returns the window handle
- of the requested window. It can also lock that window. If a window is
- locked, it must be unlocked by using the WinLockWindow function.
-
- The following code fragment determines the parent window of the given
- window (it does not lock the parent window):
-
- HWND hwndParent;
-
- hwndParent = WinQueryWindow(hwnd, QW_PARENT, FALSE);
-
- The following code fragment determines the topmost child window and locks
- it:
-
- HWND hwndChild;
-
- if (hwndChild = WinQueryWindow(hwnd, QW_TOP, TRUE)) {
-
- /* Lock the child window. */
-
- WinLockWindow(hwndChild, FALSE);
- }
-
- If a given window does not have an owner or child window, the function
- returns NULL.
-
- 4.4.9 Setting an Owner Window
-
- You can set the owner for a window by using the WinSetOwner function.
- After setting the owner, a window typically notifies the owner window of
- the new relationship by sending a message.
-
- The following code fragment shows how to set the owner window and send it
- a message:
-
- #define NEW_OWNER 1
- HWND hwnd; /* window to get new owner */
- HWND hwndOwner; /* window to become new owner */
-
- if (WinSetOwner(hwnd, hwndOwner)) {
-
- /* Send a notification message. */
-
- WinSendMsg(hwndOwner, /* send to owner */
- WM_CONTROL, /* control message for notification */
- MAKELONG(NEW_OWNER, 1), /* notification code and ID */
- NULL); /* no extra data */
- }
-
- A window can have only one owner, so WinSetOwner removes any previous
- owner.
-
- 4.4.10 Finding a Child or Owned Window
-
- A parent or owner window can retrieve the handle of a child or owned
- window by using the WinWindowFromID function and supplying the identifier
- of the child or owned window. WinWindowFromID searches all child and owned
- windows to locate the window having the given identifier. The window
- identifier is set when the application creates the child or owned window.
-
- An owner window typically uses the WinWindowFromID function to respond to
- a notification message from an owned window.
-
- The following code fragment retrieves the window handle of the owned
- window having the window identifier 1:
-
- hwndOwned = WinWindowFromID(hwndOwner, 1);
- WinSendMsg(hwndOwned, WM_ENABLE, MPFROM2SHORT(0, TRUE), NULL);
-
- You can also retrieve the handle of a child window by using the
- WinWindowFromPoint function and supplying a point in the corresponding
- parent window.
-
- 4.4.11 Enumerating Top-Level Windows
-
- You can enumerate all top-level windows by using the WinBeginEnumWindows
- and WinGetNextWindow functions. An application can create a list of all
- child windows for a given parent window by using the WinBeginEnumWindows
- function. This list contains the window handles of immediate child
- windows. An application can retrieve, one at a time, the window handles
- from the list using the WinGetNextWindow function. When the application
- has finished using the list, it must release it by using the
- WinEndEnumWindows function.
-
- The following code fragment shows how to enumerate all top-level windows
- (all immediate child windows of the desktop window):
-
- /* Enumerate all top-level windows. */
-
- henum = WinBeginEnumWindows(HWND_DESKTOP);
-
- /*
- * Loop through all enumerated windows, performing the desired task
- * on each one.
- */
-
- while (hwnd = WinGetNextWindow(henum)) {
- .
- . /* Lock the window. */
- .
- WinLockWindow(hwnd, FALSE); /* unlock window when done */
- }
-
- /* Return memory required for enumeration back to the system. */
-
- WinEndEnumWindows(henum);
-
- 4.4.12 Moving and Sizing a Window
-
- You can move a window by using the WinSetWindowPos function and specifying
- the SWP_MOVE constant. The function changes the position of the window to
- the specified position. The position is always given as coordinates
- relative to the parent window.
-
- The following code fragment moves the window to the position (10,10):
-
- WinSetWindowPos(
- hwnd, /* window handle */
- NULL, /* not used for moving and sizing */
- 10, 10 /* new position */
- 0, 0, /* not used for moving */
- SWP_MOVE); /* move and size */
-
- You can set the size of a window by using the WinSetWindowPos function and
- specifying the SWP_SIZE constant. The function changes the width and
- height of the window to the specified width and height.
-
- You can combine moving and sizing in a single function call, as shown in
- the following code fragment:
-
- WinSetWindowPos(
- hwnd, /* window handle */
- NULL, /* not used for moving and sizing */
- 10, 10 /* new position */
- 200, 200, /* width and height */
- SWP_MOVE | SWP_SIZE); /* move and size */
-
- You can retrieve the current size and position of a window by using the
- WinQueryWindowPos function. This function copies the current information
- to an SWP structure.
-
- The following code fragment uses the current size and position to change
- the height of the window, but leaves the width and position unchanged:
-
- SWP swpCurrent;
-
- WinQueryWindowPos(hwnd, &swpCurrent);
- WinSetWindowPos(
- hwnd, /* window handle */
- NULL, /* not used for moving and sizing */
- 0, 0, /* not used for sizing */
- swpCurrent.cx, /* current width */
- swpCurrent.cy + 200, /* new height */
- SWP_SIZE); /* change the size */
-
- You can also move and change the size of several windows at once by using
- the WinSetMultWindowPos function. This function takes an array of SWP
- structures. Each structure specifies the window to be moved or changed.
-
- 4.4.13 Moving a Window in a Stack of Windows
-
- You can move a window to the top or bottom of the Z order by passing the
- SWP_ZORDER constant to the WinSetWindowPos function. You specify where to
- move the window by specifying HWND_TOP or HWND_BOTTOM.
-
- The following code fragment uses WinSetWindowPos to reorder a stack of
- child windows:
-
- HENUM henum;
- HWND hwndParent;
- HWND hwndNext;
-
- henum = WinBeginEnumWindows(hwndParent);
-
- while (hwndNext = WinGetNextWindow(henum)) {
- WinSetWindowPos(
- hwndNext, /* next window to move */
- HWND_TOP, /* put window on top */
- 0, 0, 0, 0, /* not used for Z order */
- SWP_ZORDER); /* change Z order */
-
- WinLockWindow(hwndNext, FALSE); /* unlock window */
- .
- . /* Wait a little before doing the next window. */
- .
- }
-
- WinEndEnumWindows(henum);
-
- You can also specify the window you want the given window to move behind.
- In this case, you specify the window handle instead of the HWND_TOP or
- HWND_BOTTOM constant.
-
- If you enumerate windows as shown in the previous code fragment, the
- following code fragment will reverse the order of every other pair of
- windows:
-
- hwndExchange = WinGetNextWindow(henum);
-
- /* hwndNext has top window, hwndExchange has window under the top */
-
- WinSetWindowPos(
- hwndNext, /* next window to move */
- hwndExchange, /* put lower window on top */
- 0, 0, 0, 0, /* not used for Z order */
- SWP_ZORDER); /* change Z order */
-
- 4.4.14 Showing and Hiding a Window
-
- Moving and sizing a window still applies if a window is not visible. The
- effects of moving and sizing cannot be seen until the window is visible.
- You can show and hide a window by using the WinShowWindow function. This
- function changes the WS_VISIBLE style for a window to the specified
- setting. You can also use the WinIsWindowVisible function to check the
- visibility of a window. The function returns TRUE if the window is
- visible.
-
- 4.4.15 Maximizing, Minimizing, and Restoring a Window
-
- You can maximize, minimize, or restore a frame window by using the
- WinSetWindowPos function and specifying the constant SWP_MAXIMIZE,
- SWP_MINIMIZE, or SWP_RESTORE. Only a frame window can maximize and
- minimize by default. For any other window, you must provide support for
- these actions in the corresponding window procedure.
-
- The following code fragment shows how to maximize a frame window:
-
- SWP swpCurrent;
-
- WinQueryWindowPos(hwnd, &swpCurrent);
- WinSetWindowPos(
- hwnd, /* window handle */
- NULL, /* not used to maximize */
- swpCurrent.x,
- swpCurrent.y, /* stored for restoring window */
- swpCurrent.cx,
- swpCurrent.cy, /* stored for restoring window */
- SWP_MAXIMIZE | SWP_SIZE | SWP_MOVE); /* maximize */
-
-
- 4.5 Summary
-
- The following sections list all the functions and messages an application
- can use to create, maintain, and destroy windows; to manage window
- relationships; and to set, query, and initialize the size, position, and
- visibility of windows.
-
- 4.5.1 Window Functions
-
- The following functions are used by an application to create, maintain,
- and destroy windows:
-
- WinCreateWindow Creates a window. This is the most flexible, general
- purpose window-creation function. It can be used to create windows of any
- class. The function's parameters let you specify the window class, the
- parent window, the owner window, the window size and position, the Z-order
- position, the window identifier, general and class-specific window styles,
- and additional class-specific data. Other window-creation functions make
- one or more calls to this function to create their window(s).
-
- WinDestroyWindow Destroys a window. Related child windows and owned
- windows will also be destroyed.
-
- WinEnableWindow Enables or disables a window. A disabled window loses the
- focus and ignores input. This function clears or sets the WS_DISABLED
- style.
-
- WinIsWindow Determines if a window handle is valid.
-
- WinIsWindowEnabled Determines whether a window is enabled or disabled.
- The function tests the WS_DISABLED style.
-
- WinLockWindow Increments or decrements a window lock count. The lock
- count is initialized to zero and must be zero for the window to be
- destroyed.
-
- WinQuerySysModalWindow Determines the system-modal window. This function
- returns the system-modal window handle if successful or NULL if there is
- no system-modal window.
-
- WinQueryWindowLockCount Retrieves the window lock count.
-
- WinQueryWindowPtr Examines a pointer in a window data structure.
-
- WinQueryWindowULong Examines a 32-bit field in a window data structure.
-
- WinQueryWindowUShort Examines a 16-bit field in a window data structure.
-
- WinRegisterWindowDestroy Notifies other applications when the specified
- window is destroyed.
-
- WinSetSysModalWindow Sets a window as the system-modal window or ends the
- system-modal state. This function should be called only while processing
- keyboard or mouse input.
-
- WinSetWindowBits Sets bits in a 32-bit field in a window data structure.
-
- WinSetWindowPtr Sets a pointer in a window data structure.
-
- WinSetWindowULong Sets a 32-bit field in a window data structure.
-
- WinSetWindowUShort Sets a 16-bit field a window data structure.
-
- WinSubclassWindow Changes a window procedure. If successful, the function
- returns a pointer to the previous window procedure.
-
- 4.5.2 Standard Window Messages
-
- The following are standard window messages:
-
- WM_CREATE Sent to a window during processing of the WinCreateWindow
- function, before the window is sized, positioned, or shown.
-
- WM_DESTROY Sent to the window being destroyed. This message is sent after
- the window has been hidden on the device but before its child windows have
- been destroyed.
-
- WM_ENABLE This message is sent when a window is being enabled.
-
- WM_OTHERWINDOWDESTROYED Sent to all top-level windows when a window is
- destroyed.
-
- WM_QUERYWINDOWPARAMS Sent to obtain certain window data. The data is
- specified and returned by using a WNDPARAMS data structure.
-
- WM_SETWINDOWPARAMS Sent to set window data.
-
- 4.5.3 Relationship Functions
-
- The following functions can be used to manage window relationships:
-
- WinBeginEnumWindows Begins the window-enumeration process. This function
- creates an enumeration list of the immediate child windows of a window and
- returns the list handle.
-
- WinEndEnumWindows Ends a window enumeration process. This function
- destroys the enumeration list (just the list, not the windows) created by
- the WinBeginEnumWindows function.
-
- WinGetNextWindow Obtains a window handle from a window list created by a
- call to the WinBeginEnumWindows function. Each call returns the next
- window in the list or NULL at the end of the list. The function locks the
- window that has the returned handle. The application must unlock the
- window after processing. Calling this function after it has returned NULL
- causes it to wrap around to the beginning of the list.
-
- WinIsChild Determines if one window is the child of another window.
-
- WinQueryDesktopWindow Obtains a handle of the desktop window
- HWND_DESKTOP.
-
- WinQueryObjectWindow Obtains a handle of the desktop-object window
- HWND_OBJECT.
-
- WinQueryWindow Retrieves a window's parent, owner, or child windows. This
- function returns the handle of the specified window or NULL if no such
- window exists.
-
- WinSetOwner Sets a window's owner window. Note that you can set the
- handle of the owner window to NULL, meaning it has no owner.
-
- WinSetParent Sets a window's parent window. This allows you to change
- object windows to regular windows, descendant windows of top-level windows
- to top-level windows, and vice versa.
-
- 4.5.4 Functions for Moving, Sizing, and Changing
-
- The following functions can be used to move and change the position of a
- window:
-
- WinGetMaxPosition Obtains a window's maximized size and position. A
- window's maximized size is the size of its parent window plus an
- adjustment outward in all four directions equal to the size of its border.
- The adjustment is made because maximized windows do not show their border.
-
- WinGetMinPosition Obtains an icon location for a minimized window. The
- function searches for an icon area, starting at the given point and
- continuing with subsequent positions until the next available icon
- position is found.
-
- WinIsWindowVisible Determines whether a window is visible.
-
- WinQueryWindowPos Determines a window's current size and position.
-
- WinQueryWindowRect Determines a window's bounding rectangle, relative to
- its parent window. You can determine the window's size and position from
- the bounding rectangle.
-
- WinSetWindowPos Sets a window's size, position, and Z order. Position is
- specified in window coordinates relative to the parent window's lower-left
- corner. Size is specified in device units. Z order is relative to a
- window's sibling windows.
-
- WinSetMultWindowPos Sets the size, position, and Z order for an array of
- windows. This function and the WinSetWindowPos function are the same
- except for the number of windows each can affect.
-
- WinShowWindow Makes a window visible or invisible.
-
- 4.5.5 Messages for Moving, Sizing, and Changing
-
- The following messages are received by a window procedure when the
- corresponding window is moved or changes size or visibility:
-
- WM_ADJUSTWINDOWPOS Sent to a window about to be moved or sized. This
- message allows the window to adjust the new size and position before they
- take effect. This message is sent, by default, during calls to the
- WinCreateWindow, WinSetWindowPos, and WinSetMultWindowPos functions.
-
- WM_CALCVALIDRECTS Sent from the WinSetWindowPos and WinSetMultWindowPos
- functions when a window is about to be resized. Both these functions
- determine if there is a rectangular area of the window that can be
- preserved across the size change. If such a valid rectangle exists, its
- bitmap data can be simply and quickly copied to the new window image.
- Handlers of this message can specify the coordinates of the valid
- rectangle to be preserved, as well as determine where the valid rectangle
- will be placed within the resized window.
-
- WM_MOVE Sent by the system when a window with CS_MOVENOTIFY style changes
- its absolute (relative to the screen) position. The window's new position
- can be obtained by calling the WinQueryWindowPos function.
-
- WM_SHOW Sent by the system after a window's WS_VISIBLE style bit has
- changed. An mp1 value of TRUE indicates an invisible window has become
- visible. An mp1 value of FALSE indicates a visible window has become
- invisible. The default window procedure takes no action on this message.
-
- WM_SIZE Sent after a window has changed size, but before any repainting
- has been performed. Resizing or repositioning of child windows resulting
- from the size change usually occurs during the processing of this message.
- This message is not sent when a window is created.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 5 Messages and Message Queues
-
- 5.1 Introduction
- 5.2 About Messages and Message Queues
- 5.2.1 Messages
- 5.2.2 Message Queues
- 5.2.3 Message Loop
- 5.2.4 Messages and Window Procedures
- 5.2.5 Application Messages
- 5.2.6 System-Defined Messages
- 5.2.7 Application-Defined Messages
- 5.2.8 Semaphore Messages
- 5.2.9 Message Priorities
- 5.2.10 Message Filtering
- 5.3 Using Messages in an Application
- 5.3.1 Creating a Message Queue and Message Loop
- 5.3.2 Examining the Message Queue
- 5.3.3 Posting a Message to a Window
- 5.3.4 Sending a Message to a Window
- 5.3.5 Broadcasting a Message
- 5.3.6 Using Message Macros
- 5.4 Summary
-
- 5.1 Introduction
-
- This chapter describes creating and using messages and message queues in
- MS OS/2 Presentation Manager applications. You should also be familiar
- with the following topics:
-
- ■ Windows
-
- ■ Window procedures
-
- ■ Threads, processes, and sessions
-
-
- 5.2 About Messages and Message Queues
-
- Unlike traditional applications that take complete control of the
- computer's keyboard, mouse, and screen, Presentation Manager applications
- must share these resources with other applications running at the same
- time. Because all applications run independently, Presentation Manager
- applications rely on MS OS/2 to help them manage shared resources. The
- system manages shared resources by controlling the operation of each
- application, communicating with each application when there is keyboard
- and mouse input or when an application must move and size its windows. The
- system uses messages to communicate with an application and the windows
- belonging to that application.
-
- A message is information, a request for information, or a request for an
- action to be carried out by the application. The system communicates a
- message to an application so that the application can use the information
- or respond to the request. The system communicates in two ways: posting
- and sending.
-
- The system posts a message to an application's message queue if the
- message represents information or a request that does not need immediate
- action. The message queue is an application-created storage area used to
- hold messages. The application can then retrieve and process a message at
- the appropriate time. The system posts a message by copying the message
- data to the message queue.
-
- The system sends a message to an application when it needs an immediate
- response from the application. It sends a message by passing the message
- data as arguments to the window procedure. The window procedure carries
- out the request or lets the system carry out default processing for the
- message.
-
- The following sections describe messages and message queues in detail.
-
- 5.2.1 Messages
-
- All messages contain information that an application uses to carry out
- tasks. There are two types of messages: queue messages and window
- messages. Queue messages are messages stored in a message queue. Window
- messages are messages sent to a window procedure. Although these message
- types have very different formats, the information they contain is nearly
- identical.
-
- Every message contains a message identifier. The message identifier is an
- integer value that determines whether the message is information or a
- request. When an application processes a message, it uses the message
- identifier to determine what to do.
-
- Every message contains a window handle. The window handle identifies the
- window for which the message is intended. The window handle is important
- because most message queues and window procedures serve more than one
- window. The window handle ensures that the application processes the
- message for the appropriate window.
-
- Messages contain two message parameters. A message parameter is a 32-bit
- value that specifies data or the location of data to be used in processing
- the message. The meaning and value of a message parameter depends on the
- message. Message parameters can be pointers to structures containing
- additional data, integer values, packed bit flags, and so on. Some
- messages do not use message parameters and typically set the parameters to
- zero. An application always checks the message identifier to determine how
- to interpret the message parameters.
-
- Queue messages also contain the message time and mouse position. The
- message time specifies the system time, in milliseconds, when the message
- was created. The mouse position specifies the location of the mouse
- pointer, in screen coordinates, when the message was created.
-
- A queue message is a QMSG data structure that contains six fields
- representing the window handle, message identifier, two message
- parameters, message time, and mouse position. The time and position are
- provided because most queue messages are input messages, representing
- keyboard or mouse input from the user. The time and position help the
- application identify the context of the message. The system posts a queue
- message by filling the QMSG structure and copying it to a message queue.
-
- A window message consists of the window handle, the message identifier,
- and two message parameters. A window message does not include the message
- time and mouse position because most window messages are requests to carry
- out a task that is not related to the current time or mouse-pointer
- position. The system sends a window procedure by passing these values as
- individual arguments to a window procedure.
-
- 5.2.2 Message Queues
-
- Every Presentation Manager application needs a message queue. A message
- queue is the only means an application has to receive input from the
- keyboard or mouse. Only applications that create message queues can create
- windows.
-
- A message queue is internal storage reserved by the application for
- receiving and holding posted messages. An application creates a message
- queue by using the WinCreateMsgQueue function. This function returns a
- handle the application can use to access the message queue. After an
- application creates a message queue, the system posts messages intended
- for windows in the application to that queue. The application can retrieve
- queue messages by specifying the message-queue handle in a call to the
- WinGetMsg function. It can examine messages without retrieving them by
- using the WinPeekMsg function. When an application no longer needs the
- message queue, it can destroy it by using the WinDestroyMsgQueue function.
-
- Message queues serve all windows created by the application. This means a
- queue may hold messages for several windows. Most messages specify the
- windows to which they belong, so the application can easily apply a
- message to the appropriate window. Messages that do not specify a window
- apply to the entire application.
-
- An application that has more than one thread can create more than one
- message queue. The system allows one message queue for each thread. A
- message queue created by an application thread belongs to that thread and
- has no connection to other queues in that application. When an application
- creates a window in a given thread, the system associates the window with
- the message queue in that thread. The system then posts all subsequent
- messages intended for the window to that queue.
-
- Although multiple messages queues are possible, most Presentation Manager
- applications use threads sparingly and so use only one message queue.
-
- Since several windows typically use a message queue, it is important that
- the message queue be large enough to hold all possible messages that may
- be posted to it. An application can set the size of the message queue when
- it creates the queue by specifying the maximum number of messages the
- queue can hold.
-
- To minimize the queue size, several types of posted messages are not
- actually stored in a message queue. Instead, the system keeps a record in
- the queue of the message being posted and combines any information
- contained in the message with information from previous messages. Timer,
- semaphore, and paint messages are handled in this way. For example, if
- more than one WM_PAINT message is posted, the system combines the update
- regions for each into a single update region. Although there is no actual
- message in the queue, the system constructs one WM_PAINT message with the
- single update region when an application uses the WinGetMsg function.
-
- Mouse and keyboard input messages are also not stored in the message
- queue. These are stored in the system message queue. The system message
- queue is a system-owned queue that receives and holds messages for all
- mouse and keyboard input. The system does not copy these messages to
- application message queues. Instead, the WinGetMsg function searches the
- system queue for input messages belonging to the application when there
- are no other higher-priority messages in the application's message queue.
- The system message queue is usually large enough to hold all input
- messages, even if the user is typing or moving the mouse very quickly. If
- the system queue does run out of room, the system ignores the most recent
- keyboard input (usually beeping to indicate it is ignored) and collects
- mouse motions into a single motion.
-
- Every message queue has a corresponding data structure. The data structure
- specifies the identifiers of the process and thread that own the message
- queue and gives a count of the maximum number of messages the queue can
- receive. An application can retrieve the data structure by using the
- WinQueryQueueInfo function.
-
- A message queue also has a current status. The status specifies whether
- any messages are available in the queue. An application can retrieve the
- queue status by using the WinQueryQueueStatus function. Since this
- function is very fast, applications typically use it to check for messages
- rather than using the WinPeekMsg function, which inspects the thread's
- message queue.
-
- 5.2.3 Message Loop
-
- Every application with a message queue is responsible for retrieving the
- messages from that queue. An application can do this by using a message
- loop. A message loop is a program loop, usually in the application's main
- function, that retrieves messages from the message queue and dispatches
- them to the appropriate windows. The message loop consists of two function
- calls: one to the WinGetMsg function, the other to the WinDispatchMsg
- function. The message loop has the following form:
-
- while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
- WinDispatchMsg(hab, &qmsg);
-
- An application starts the message loop after creating the message queue
- and at least one application window. Once started, the message loop
- continues to retrieve messages from the message queue and to dispatch
- (send) them to the appropriate windows. The WinDispatchMsg function sends
- each message to the window specified by the window handle in the message.
-
- Only one message loop is needed for a message queue, even if the queue
- contains messages for more than one window. Each queue message is a QMSG
- structure that contains the handle of the window to which the message
- belongs, so the WinDispatchMsg function always dispatches the message to
- the proper window. The WinGetMsg function retrieves messages from the
- queue in first-in, first-out (FIFO) order, so the messages are dispatched
- to windows in the same order they were put in the queue.
-
- If there are no messages in the queue, the system temporarily stops
- processing the WinGetMsg function until a message arrives. This means that
- CPU time slices that would otherwise be spent waiting for a message can be
- given to the applications (or threads) that do have messages in their
- queues.
-
- The message loop continues to retrieve and send messages until the
- WinGetMsg function retrieves a WM_QUIT message. This message causes the
- function to return FALSE, terminating the loop. In most cases, terminating
- the message loop is the first step in terminating the application. An
- application can terminate its own loop by posting the WM_QUIT message in
- its own queue.
-
- An application can modify its message loop in a variety of ways. For
- example, it can retrieve messages from the queue without dispatching them
- to a window. This is useful for applications that post messages that do
- not specify a window (these messages apply to the application rather than
- to a specific window; they have NULL window handles). An application can
- also direct the WinGetMsg function to search for specific messages,
- leaving other messages in the queue. This is useful for applications that
- temporarily need to bypass the usual first-in, first-out order of the
- message queue.
-
- 5.2.4 Messages and Window Procedures
-
- When the system needs an immediate response from an application, it sends
- a message to a window procedure. A window procedure is a function that
- receives and processes all input and requests for action sent to the
- window by the system. Every window class has a window procedure and every
- window created using that class uses the window procedure to respond to
- messages.
-
- The system sends a message to the window procedure by passing the message
- data as arguments to the window procedure. The window procedure carries
- out an appropriate action for the given request. Most window procedures
- check the message identifier, then use the information specified by the
- message parameters to carry out the request. When it has completed
- processing the message, the window procedure returns a message result.
- Each message has a particular set of possible return values. The window
- procedure must return the appropriate value for the processing it carried
- out.
-
- A window procedure cannot ignore a message. If it does not process a
- message, it must pass the message back to the system for default
- processing. The window procedure can do this by calling the
- WinDefWindowProc function. This function carries out a default action and
- returns the message result. The window procedure must return this value as
- its own message result.
-
- A window procedure commonly processes messages for several windows. It
- uses the window handle specified in the message to identify the
- appropriate window. Most window procedures process a few types of messages
- and pass the others on to the system by calling the WinDefWindowProc
- function.
-
- 5.2.5 Application Messages
-
- Any application can post and send messages. Like the system, an
- application posts a message by copying it to a message queue. It sends a
- message by passing the message data as arguments to a window procedure. An
- application can post a message by using the WinPostMsg function. It can
- send a message by using the WinSendMsg function.
-
- Typically, an application posts a message to notify a specific window to
- carry out a task. The WinPostMsg function creates a QMSG structure for
- each message and copies the message to the message queue corresponding to
- the given window. The application's message loop eventually retrieves the
- message and dispatches it to the appropriate window procedure. One message
- commonly posted is WM_QUIT. This message terminates the application by
- terminating the message loop.
-
- Typically, an application sends a message to notify a specific window
- procedure to immediately carry out a task. The WinSendMsg function passes
- the message to the window procedure corresponding to the given window. The
- function waits until the window procedure completes processing and then
- returns the message result. It is very common for parent and child windows
- to communicate by sending messages to each other. For example, a parent
- window that has an entry-field control (as its child window) can set the
- text of the control by sending the child window a message. The control can
- notify the parent window of changes to the text (carried out by the user)
- by sending messages back to the parent window.
-
- Occasionally, an application may need to send or post a message to all
- windows in the system. For example, if the application changes a system
- value, it must notify all windows about the change by sending a
- WM_SYSVALUECHANGED message. An application can send or post messages to
- any number of windows by using the WinBroadcastMsg function. The options
- in WinBroadcastMsg determine whether the message is sent or posted and
- specify the number of windows to receive the message.
-
- If an application has more than one thread, any thread in the application
- can post messages to a message queue, even if that thread has no message
- queue of its own. However, only threads that have a message queue can send
- messages. Posting or sending messages between threads is relatively
- uncommon. One reason for this is that it is costly in terms of system
- performance to send a message. If you do post messages between threads, it
- is likely to be for semaphore messages. Semaphore messages permit window
- procedures to jointly manage a shared resource.
-
- An application can post a message without specifying a window. If the
- application supplies a NULL window handle when it calls the WinPostMsg
- function, the function posts the message that is in the message queue of
- the thread calling the function. Because the message has no window handle,
- the message loop processes the message. This is one way to create messages
- that apply to the entire application instead of to a specific window.
-
- A window procedure can determine whether it is processing a message sent
- by another thread by using the WinInSendMsg function. This is useful when
- message processing depends on the origin of the message.
-
- A common programming error is to assume that the WinPostMsg function
- always posts a message. This is not true when the message queue is full.
- An application should check the return value of the function to see if the
- message has been posted. In general, if an application intends to post
- many messages to the queue, it should set the message queue to an
- appropriate size when it creates the queue. The default message-queue size
- is ten messages.
-
- 5.2.6 System-Defined Messages
-
- There are many system-defined messages. The system uses these messages to
- control the operation of applications and to provide input and other
- information for applications to process. The system sends or posts a
- system-defined message when it communicates with an application. An
- application can also send or post system-defined messages. Applications
- typically use these messages to control the operation of control windows
- created using the preregistered window classes.
-
- Each system message has a unique message identifier and a corresponding
- symbolic constant. The symbolic constant, defined in MS OS/2 header files,
- typically states the purpose of the message. For example, the WM_PAINT
- constant represents the paint message. The paint message requests a window
- to paint its contents.
-
- The symbolic constants also specify the message category. System-defined
- messages can belong to several categories; the prefix identifies the type
- of window that can interpret and process the messages. The following list
- gives the prefixes and related message categories:
-
- Prefix Message category
- ──────────────────────────────────────────────────────────────────────────
- BM Button-control
-
- EM Entry-field control
-
- LM List-box control
-
- MM Menu
-
- SBM Scroll-bar control
-
- SM Static control
-
- TBM Title-bar control
-
- WM General window
- ──────────────────────────────────────────────────────────────────────────
-
- General window messages cover a wide range of information and requests and
- include mouse and keyboard-input messages, menu and dialog-input messages,
- window-creation and window-management messages, and dynamic-data-exchange
- (DDE) messages.
-
- 5.2.7 Application-Defined Messages
-
- An application can create its own messages to use in its own windows. If
- an application creates messages, the window procedure that receives the
- message must interpret the message and provide appropriate processing.
-
- MS OS/2 reserves the message-identifier values in the range 0x0000 through
- (WM_USER-1) for system-defined messages. Applications cannot use these
- values for private messages. Values in the range WM_USER through 0xBFFF
- are available for message identifiers defined by an application for use in
- that application. Values in the range 0xC000 through 0xFFFF are reserved
- for message identifiers defined by an application using the atom-manager
- registration for use in any application.
-
- 5.2.8 Semaphore Messages
-
- The semaphore messages are a way of signaling the end of an event through
- the message queue. Applications use these messages like they use MS OS/2
- semaphore functions to coordinate events by passing signals. Semaphore
- messages are often used in conjunction with MS OS/2 semaphores.
-
- There are four semaphore messages: WM_SEM1, WM_SEM2, WM_SEM3, and WM_SEM4.
- An application posts one of the semaphore messages to signal the end of
- the given event. The window that is waiting for the given event receives
- the semaphore message when the message loop retrieves and dispatches the
- message.
-
- Each semaphore message includes a bit flag that can be used to uniquely
- identify 32 possible semaphores for each semaphore message. The
- application passes the bit flag (with the appropriate bit set) as a
- message parameter with the message. The window procedure that receives the
- message then uses the bit flag to identify the semaphore.
-
- To save space in a message queue, the system does not store semaphore
- messages in the message queue. Instead, it sets a record in the queue,
- indicating the semaphore message has been received, and then combines the
- bit flag for the message with the bit flags from previous messages. When
- the window procedure eventually receives the message, the bit flag
- specifies each semaphore message posted since the last message was
- retrieved.
-
- 5.2.9 Message Priorities
-
- The WinGetMsg function retrieves messages from the message queue based on
- message priority. The function retrieves messages with higher priority
- first. If it finds more than one message at a particular priority level,
- it retrieves the oldest message first. Messages have the following
- priority:
-
- Priority Message
- ──────────────────────────────────────────────────────────────────────────
- 1 WM_SEM1
-
- 2 Messages posted using WinPostMsg
-
- 3 Input messages from the keyboard or mouse
-
- 4 WM_SEM2
-
- 5 WM_PAINT
-
- 6 WM_SEM3
-
- 7 WM_TIMER
-
- 8 WM_SEM4
- ──────────────────────────────────────────────────────────────────────────
-
- 5.2.10 Message Filtering
-
- Applications can choose specific messages to retrieve from the message
- queue (ignoring other messages) by specifying a message filter with the
- WinGetMsg or WinPeekMsg function. The message filter is a range of message
- identifiers (specified by a first and last identifier), a window handle,
- or both. The functions use the message filter to select the messages to
- retrieve from the queue. Message filtering is useful if an application
- needs to search ahead in the message queue for messages that have a lower
- priority or that arrived in the queue later than other less important
- messages.
-
- Any application that filters messages must ensure that a message
- satisfying the message filter can be posted. For example, filtering for a
- WM_CHAR message in a window that does not have the input focus prevents
- the WinGetMsg function from returning. Some messages, such as WM_COMMAND,
- are generated from other messages; filtering for them may also prevent
- WinGetMsg from returning.
-
- The WM_BUTTONCLICKFIRST and WM_BUTTONCLICKLAST, WM_MOUSEFIRST and
- WM_MOUSELAST, and WM_DDE_FIRST and WM_DDE_LAST constants can be used to
- filter button, mouse, and DDE messages.
-
-
- 5.3 Using Messages in an Application
-
- This section explains how to use the message and message-queue functions
- to create and manage message queues and to post and send messages between
- windows.
-
- 5.3.1 Creating a Message Queue and Message Loop
-
- Your application needs a message queue and message loop to process
- messages for windows. You create a message queue by using the
- WinCreateMsgQueue function. You create a message loop by using the
- WinGetMsg and WinDispatchMsg functions. You must create and show at least
- one window after creating the queue but before starting the message loop.
- The window is required because it is the only way the user can supply
- input to the message queue. The following code fragment shows how to
- create a message queue and a message loop:
-
- HAB hab; /* anchor-block handle */
- HMQ hmq; /* message-queue handle */
- QMSG qmsg; /* queue-message structure */
-
- VOID cdecl main()
- {
- hab = WinInitialize(NULL);
- hmq = WinCreateMsgQueue(hab, DEFAULT_QUEUE_SIZE);
-
- /*
- * Use WinRegisterClass to register your window class.
- * Use WinCreateStdWindow to create your window.
- */
-
- while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
- WinDispatchMsg(hab, &qmsg);
-
- /* Use WinDestroyWindow to destroy your window. */
-
- WinDestroyMsgQueue(hmq);
- WinTerminate(hab);
- }
-
- Both the WinGetMsg and WinDispatchMsg functions take a pointer to a QMSG
- structure as a parameter. If a message is available, WinGetMsg copies it
- to the QMSG structure; WinDispatchMsg then uses the fields of the
- structure as arguments for the window procedure.
-
- Occasionally, you may need to process the message before dispatching it.
- This can occur, for example, if a window procedure posts a message to the
- queue for which a NULL window handle has been specified. Because the
- WinDispatchMsg function needs a window handle to dispatch the message, the
- message loop must process the message before dispatching it. The following
- code fragment shows how the message loop might process messages that have
- NULL window handles:
-
- while (WinGetMsg(hab, &qmsg, NULL, 0, 0)) {
- If (qmsg.hwnd == NULL) {
- .
- . /* Process the message. */
- .
- }
- else
- WinDispatchMsg(hab, &qmsg);
- }
-
- 5.3.2 Examining the Message Queue
-
- You can examine the contents of the message queue by using the WinPeekMsg
- or WinQueryQueueStatus function. It is useful to examine the queue if you
- start a lengthy operation that additional user input can affect, or if you
- need to look ahead in the queue to anticipate a response to user input.
-
- You can use the WinPeekMsg function to check for specific messages in the
- message queue. The function is useful for extracting messages for a
- specific window from the queue. The function returns immediately if there
- is no message in the queue. This function can be used in a loop without
- requiring the loop to wait for a message to arrive. The following code
- segment checks the queue for WM_CHAR messages:
-
- if (WinPeekMsg(hab, &qmsg, NULL, WM_CHAR, WM_CHAR, PM_NOREMOVE))
-
- You can also use the WinQueryQueueStatus function to check for messages in
- the queue. This function is very fast and returns information about the
- kinds of messages available in the queue and which messages have been
- recently posted. Most applications use this function in program loops that
- need to be as fast as possible.
-
- If you have a very long operation to carry out, you should consider
- creating a separate thread for the operation. Despite the MS OS/2
- multitasking features, any application thread having a message queue that
- does not periodically relinquish control by calling the WinGetMsg or
- WinWaitMsg function risks monopolizing the CPU and seriously degrading
- system performance.
-
- 5.3.3 Posting a Message to a Window
-
- You can use the WinPostMsg function to post a message to a window. The
- message goes to the window's message queue. For example, the following
- code fragment posts the WM_QUIT message:
-
- if (!WinPostMsg(hwnd, WM_QUIT, 0L, 0L))
-
- /* Message was not posted. */
-
- The function returns FALSE if the queue was full and the message could not
- be posted.
-
- 5.3.4 Sending a Message to a Window
-
- You can use the WinSendMsg function to send a message directly to a
- window. Applications typically use this function to send messages to child
- windows. For example, the following code fragment directs a button control
- to draw a check mark by sending the BM_SETCHECK message to the control:
-
- WinSendMsg(hwndButton, BM_SETCHECK, MPFROMSHORT(1), 0L);
-
- WinSendMsg calls the window's window procedure and waits for that
- procedure to handle the message and return a result. A message can be sent
- to any window in the system; all that is required is a handle to the
- window. The message is not stored in the message queue. The thread making
- the call must have a message queue.
-
- 5.3.5 Broadcasting a Message
-
- You can send messages to multiple windows by using the WinBroadcastMsg
- function. This function is useful after an application changes a system
- value, for broadcasting the WM_SYSVALUECHANGED message. The following code
- fragment shows how to broadcast this message to all frame windows in all
- applications:
-
- WinBroadcastMsg(
- hwnd, /* window handle */
- WM_SYSVALUECHANGED, /* message ID */
- 0L, /* no message parameters */
- 0L,
- BMSG_FRAMEONLY | BMSG_POSTQUEUE); /* all frame windows */
-
- You can broadcast messages to all windows, to just frame windows, or to
- just the windows in your application.
-
- 5.3.6 Using Message Macros
-
- The MS OS/2 include files define several macros that help create and
- interpret message parameters.
-
- One set of macros helps you construct message parameters. Macros are
- useful for sending and posting messages. For example, the following code
- fragment uses the MPFROMSHORT macro to convert a 16-bit integer into the
- 32-bit message parameter:
-
- WinSendMsg(hwndButton, BM_SETCHECK, MPFROMSHORT(1), 0L);
-
- A second set of macros helps you extract values from a message parameter.
- They are useful for handling messages in a window procedure. The following
- code fragment illustrates this:
-
- case WM_FOCUSCHANGE:
- fsFocusChange = SHORT2FROMMP(mp2);
- if (SHORT1FROMMP(mp2))
- hwndLoseFocus = HWNDFROMMP(mp1);
-
- A third set of macros helps you construct a message result. They are
- useful for returning message results in a window procedure. This is
- illustrated by the following code fragment:
-
- return (MRFROM2SHORT(1, 2));
-
-
- 5.4 Summary
-
- The following are the functions and the message you can use to create and
- use message queues and messages:
-
- WinBroadcastMsg Sends or posts messages to one or more windows or posts
- messages to all message queues.
-
- WinCallMsgFilter Calls a message-filter hook procedure, passing it a
- message and a message-filter control code.
-
- WinCreateMsgQueue Creates a message queue for the current thread and
- returns a handle to the queue.
-
- WinDefDlgProc Carries out default processing for messages sent to a
- dialog window.
-
- WinDefWindowProc Carries out default processing for messages sent to a
- window.
-
- WinDestroyMsgQueue Destroys a particular message queue. This function
- must be called before terminating a thread that has a message queue.
-
- WinDispatchMsg Sends a message to a specified window.
-
- WinGetMsg Retrieves the next message from a message queue, removing that
- message from the queue. This function does not return until a message is
- available.
-
- WinInSendMsg Determines whether the current thread is processing a
- message sent from another thread. WinMsgMuxSemWait Waits for one of a
- list of semaphores to clear. This function is similar to the DosMuxSemWait
- function, except that the thread can continue to process messages sent to
- it from other threads.
-
- WinMsgSemWait Waits for a semaphore to clear. This function is similar to
- the DosSemWait function, except that a thread can continue to process
- messages sent to it from other threads.
-
- WinPeekMsg Copies the next message from a message queue without removing
- it from the queue. This function returns immediately, whether or not a
- message is available.
-
- WinPostMsg Posts a message to the message queue for a specified window.
- After placing the message in the queue, the function returns immediately.
-
- WinPostQueueMsg Posts a message in a specified message queue in the
- system. The function returns immediately after placing the message in the
- queue.
-
- WinQueryMsgPos Retrieves the mouse-pointer position (in screen
- coordinates) that was stored with a posted message.
-
- WinQueryMsgTime Retrieves the system time (milliseconds since the system
- was booted) that the message was posted.
-
- WinQueryQueueInfo Retrieves information about a message queue.
-
- WinQueryQueueStatus Retrieves status information about a message queue.
-
- WinSendDlgItemMsg Sends a message to a control window that belongs to the
- specified dialog window.
-
- WinSendMsg Sends a message directly to the window procedure of a
- specified window. The function does not return until the message has been
- processed by the window procedure.
-
- WinTranslateAccel Translates a WM_CHAR message to a WM_COMMAND message if
- there is an entry for the specific character in the accelerator table.
-
- WinWaitMsg Waits until a particular type of message appears in a message
- queue.
-
- WM_QUIT Marks the end of message processing for a message queue. This
- message causes the WinGetMsg function to return FALSE.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 6 Window Classes
-
- 6.1 Introduction
- 6.2 About Window Classes
- 6.2.1 Custom Window Classes
- 6.2.2 Class Styles
- 6.2.3 Window Procedures
- 6.2.4 Public Window Classes
- 6.2.5 Preregistered Window Classes
- 6.2.6 Custom Public Classes
- 6.2.7 Class Data
- 6.3 Using Window Classes
- 6.3.1 Registering a Private Window Class
- 6.3.2 Registering an Imported Window Procedure
- 6.4 Summary
-
- 6.1 Introduction
-
- This chapter describes how applications create and use window classes. You
- should also be familiar with the following topics:
-
- ■ Windows
-
- ■ Window procedures
-
- ■ Messages and message queues
-
- ■ The os2.ini file
-
-
- 6.2 About Window Classes
-
- A window class determines the window styles and window procedure given to
- windows of that class when they are created. Every window created by an
- application is a member of a window class. Each window class has an
- associated window procedure that it shares with all windows of that same
- class. The window procedure handles messages for all windows of that class
- and therefore defines the behavior and appearance of the window.
-
- When an application creates a window, it must specify a window class. The
- WinCreateWindow function requires that the class be given explicitly.
- Other window-creation functions use specific classes by default. In all
- cases, a window class must be registered before it can be used to create
- windows. An application can register its own (private) window classes or
- use pregistered, public window classes.
-
- 6.2.1 Custom Window Classes
-
- A custom (or private) window class is any window class registered by an
- application. The application defines the window procedure, class style,
- and window data size for the class and then registers the class by using
- the WinRegisterClass function. The window class is available to the
- application, but only to that application. Classes created in this way are
- private and cannot be shared by other applications. When the application
- terminates, the system removes any data associated with the private window
- class and invalidates the class name.
-
- An application can register its own window classes at any time. Typically,
- an application registers window classes as part of its initialization, but
- this is not required. The only restriction is that no window of a
- particular class can be created until that class is registered by the
- application.
-
- When an application registers a window class, it must supply the following
- information:
-
- ■ Class name
-
- ■ Class styles
-
- ■ Window procedure
-
- ■ Window data size
-
- The class name identifies the window class. The application uses the class
- name when creating a window, specifying the class to use. The class name
- can be a character string or an integer value. The class name must be
- unique. The system checks to see if a public class or a class already
- registered by the application has the same name. If the class name is not
- unique, an error is returned.
-
- The class style is one or more values that tell the system what initial
- window styles to give a window created with this class. Some class styles
- (for example, CS_SYNCPAINT) cause a new window to be given the
- corresponding window style when it is created. Styles such as
- CS_MOVENOTIFY direct the system to send messages to the window procedure
- when it ordinarily would not.
-
- The window procedure is a function that receives and processes all
- messages sent to the window by the system. It is the chief component of
- the window class because it explicitly defines the appearance and behavior
- of each window created with the class. The window procedure can be part of
- the application or part of a dynamic-link library. In either case, it must
- be an exported function. When a window procedure is in a dynamic-link
- library rather than in the application, the application must import the
- window procedure by using an import library when linking, using the
- IMPORTS statement in the application's module-definition file, or using
- the DosLoadModule and DosGetProcAddr functions to retrieve the function
- address.
-
- The window data size is a value that specifies the number of extra bytes
- to allocate for each window data structure. The system creates a window
- data structure for each window. The extra bytes can be used by an
- application to store additional information about a particular window.
-
- Once created, a window-class data structure cannot be changed. However, it
- is relatively easy to change the window styles and window procedure of a
- window created with that class. An application cannot deregister a window
- class. Window classes remain registered and available until the
- application terminates.
-
- An application that registers a window class can also support its own set
- of window styles for windows of that class. Standard window styles──for
- example, WS_VISIBLE and WS_SYNCPAINT──still apply to these windows.
- However, since a window style is a 32-bit integer and only the high 16
- bits are used for the standard window styles, an application can use the
- low 16 bits for styles unique to the custom window.
-
- MS OS/2 has unique window styles for all preregistered window classes.
- Styles such as FS_BORDER and BS_PUSHBUTTON are processed by the window
- procedure for the corresponding class and not by the system. This means
- that an application can build the support for its own window styles into
- the window procedure for its custom class. Using a window style designed
- for one window class will not work with another window class.
-
- If more than one instance of an application is running at the same time,
- the window classes in one instance are not available to any other
- instance. This means a second instance must register the classes for
- itself. If an instance of an application terminates, the window classes
- for any other instance of that application remain unchanged.
-
- 6.2.2 Class Styles
-
- Each window class has one or more class styles. A class style tells the
- system what initial window style to give a window created with that class.
- An application sets the class styles for a window class when it registers
- the class. The styles cannot be changed.
-
- When you register a window class, you can specify one or more class
- styles, combining them as necessary by using the bitwise OR operator.
-
- An application can examine the class style for any window class by using
- the WinQueryClassInfo function. There are ten class styles, as listed
- below:
-
- ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- CS_CLIPCHILDREN Sets the WS_CLIPCHILDREN style for windows created with
- this class.
-
- CS_CLIPSIBLINGS Sets the WS_CLIPSIBLINGS style for windows created with
- this class.
-
- CS_PARENTCLIP Sets the WS_PARENTCLIP style for windows created with
- this class.
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- this class.
-
- CS_SAVEBITS Sets the WS_SAVEBITS style for windows created with
- this class.
-
- CS_SYNCPAINT Sets the WS_SAVEBITS style for windows created with
- this class.
-
- CS_FRAME Identifies windows created with this class as frame
- windows.
-
- CS_PUBLIC Creates a public window class.
-
- CS_HITTEST Directs the system to send WM_HITTEST messages to
- windows of this class whenever the mouse pointer moves
- in the window.
-
- CS_SIZEREDRAW Directs the system to invalidate the entire window
- whenever the size of the window changes.
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- whenever the size of the window changes.
-
- CS_MOVENOTIFY Directs the system to send WM_MOVE messages to the
- window whenever the window is moved.
- ──────────────────────────────────────────────────────────────────────────
-
-
- 6.2.3 Window Procedures
-
- The window procedure for a window class handles the messages sent to
- windows of that class. One window procedure is shared by all windows of a
- class, so applications must ensure that no conflicts arise when two
- windows of the same class attempt to access the same global data. In other
- words, the window procedure must protect global data and other shared
- resources.
-
- 6.2.4 Public Window Classes
-
- Although MS OS/2 allows an application to register its own window classes,
- most applications rarely register more than one window class. This window
- class supports the client window in the application's main window. For all
- other windows, the application generally uses public window classes.
- Public window classes support frame windows, controls, menus, and dialog
- windows.
-
- Public window classes are available to all applications. An application
- does not need to register a public window class to use it. The window
- procedure for a public window class always resides in a dynamic-link
- library and is accessible to all applications. An application does not
- need to import the window procedure to use a public window class.
-
- 6.2.5 Preregistered Window Classes
-
- MS OS/2 provides several preregistered, public window classes.
- Applications can use these public window classes to create frame windows,
- dialog windows, menus, push buttons, entry fields, and other controls. The
- window procedures for these classes are predefined so the application does
- not register the class before using it.
-
- An application uses a preregistered, public window class by specifying its
- class in a call to the WinCreateWindow function. The class names for the
- preregistered, public window classes are integer values represented by the
- following constant names:
-
- ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
- Class name Description
- ──────────────────────────────────────────────────────────────────────────
- WC_FRAME Creates a frame window. Has class styles CS_FRAME,
- CS_HITTEST, CS_SYNCPAINT, CS_PUBLIC, and
- CS_CLIPSIBLINGS.
-
- WC_BUTTON Creates a button control. Has class styles
- CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, and
- CS_PUBLIC.
-
- WC_ENTRYFIELD Creates a text-entry control field. Has class styles
- CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, and
- CS_PUBLIC.
-
- WC_LISTBOX Creates a list box. Has class styles CS_PARENTCLIP,
- CS_SYNCPAINT, and CS_PUBLIC.
- Class name Description
- ──────────────────────────────────────────────────────────────────────────
- CS_SYNCPAINT, and CS_PUBLIC.
-
- WC_MENU Creates a menu. Has class styles CS_SYNCPAINT,
- CS_SIZEREDRAW, and CS_PUBLIC.
-
- WC_SCROLLBAR Creates a scroll bar. Has class styles CS_HITTEST,
- CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, and
- CS_PUBLIC.
-
- WC_STATIC Creates a static control. Has class styles
- CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, CS_HITTEST,
- and CS_PUBLIC.
-
- WC_TITLEBAR Creates a title bar. Has class styles CS_HITTEST,
- CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, and
- CS_PUBLIC.
- ──────────────────────────────────────────────────────────────────────────
-
-
- Each preregistered, public window class also supports several window
- styles that an application can use to customize a window. For example, a
- window created with the WC_BUTTON class can have any one of four different
- behaviors and appearances. The application specifies the style (and the
- behavior and appearance of the window) in the call to the WinCreateWindow
- function. For a list of the available styles and more detailed information
- on each of the preregistered, public window classes, see Chapter 10,
- "Control Windows."
-
- An application must not use the preregistered, public window-class names
- when it registers its own window classes.
-
- 6.2.6 Custom Public Classes
-
- An application can create its own public window class, but this must be
- done in a special manner at system initialization. Only the shell can
- register a public window class and only when the system starts.
- Registering a public window class requires a special load entry in the
- os2.ini file that instructs the shell to load a dynamic-link library whose
- initialization routine registers the window class. Public window classes
- must be registered by using the WinRegisterClass function and must have
- the class style CS_PUBLIC. A public window class registered in this way
- can have the same name as an existing public window class, but this
- replaces the original window class.
-
- If a dynamic-link library replaces a public window class, it can also save
- the previous window-procedure address and use it to subclass the original
- window class. The dynamic-link library retrieves the original
- window-procedure address by using the WinQueryClassInfo function. The new
- window procedure then passes unprocessed messages to the original window
- procedure. All windows created using this revised public window class will
- automatically be subclassed.
-
- When subclassing a public window class, the window data size cannot be
- smaller than the original window data size. All public window classes
- defined by MS OS/2 use four extra bytes for storing a pointer to custom
- window data. This size is not guaranteed for public window classes defined
- by dynamic-link modules not belonging to MS OS/2.
-
- 6.2.7 Class Data
-
- An application can examine a registered window class by using the
- WinQueryClassInfo function. This is useful for checking the class styles
- of a public window class. An application can also retrieve the name of the
- class for a given window by using the WinQueryClassName function. Using
- the window class name, you can then call the WinQueryClassInfo function to
- retrieve the window class data.
-
- The WinQueryClassName function retrieves the name of the window class. If
- the window is one of the preregistered, public window classes, the window
- class name returned is in the form #nnnnn, where nnnnn is up to five
- digits representing the value of the window class name constant.
-
- The WinQueryClassInfo function retrieves information about a window class.
- It copies the class style, window-procedure address, and window data size
- to a CLASSINFO data structure. The CLASSINFO structure has the following
- form:
-
- typedef struct _CLASSINFO { /* clsi */
- ULONG flClassStyle;
- PFNWP pfnWindowProc;
- USHORT cbWindowData;
- } CLASSINFO;
-
-
- 6.3 Using Window Classes
-
- The following sections explain how to register and use window classes in
- your applications.
-
- 6.3.1 Registering a Private Window Class
-
- You can register a private window class at any time by using the
- WinRegisterClass function. You must define the window procedure in your
- application, choose a unique name, and set the window class styles for the
- class. The following code fragment shows how to register the window class
- name "MyPrivateName".
-
- WinRegisterClass(hab, /* anchor-block handle */
- "MyPrivateName", /* class name */
- MyWindowProc, /* far pointer to procedure */
- CS_SIZEREDRAW, /* class style */
- 0); /* window data */
-
- 6.3.2 Registering an Imported Window Procedure
-
- You do not have to limit window procedures to your application's code
- segments. You can also register a window procedure that is imported from a
- dynamic-link library. You can do this in several ways. The easiest way is
- to import the window-procedure name by using either the IMPORTS statement
- in the application's module-definition file or by linking with an import
- library that contains an import record for the function.
-
-
- 6.4 Summary
-
- An application can use the following functions to register and use window
- classes:
-
- WinQueryClassInfo Obtains information about a window class. The class is
- specified by name. The function fills a CLASSINFO data structure. This
- gives you the long word of the window-class style, a pointer to its window
- procedure, and the number of additional words stored as part of the class.
-
- WinQueryClassName Obtains a window class name for a given window. If the
- window class is one of the preregistered, public classes, the class name
- returned is in the form #nnnnn, where nnnnn is up to five digits
- representing the value of the window class name constant.
-
- WinRegisterClass Registers a window class.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 7 Window Procedures
-
- 7.1 Introduction
- 7.2 About Window Procedures
- 7.2.1 Structure of a Window Procedure
- 7.2.1.1 Calling Convention
- 7.2.1.2 Arguments
- 7.2.1.3 Return Value
- 7.2.2 Default Window Procedure
- 7.3 Using a Window Procedure
- 7.3.1 Associating a Window Procedure and Classes
- 7.3.2 Processing a Default Window Procedure
- 7.4 Summary
- 7.4.1 Window-Procedure Syntax
- 7.4.2 Messages Processed by the Default Window Procedure
-
- 7.1 Introduction
-
- This chapter describes window procedures and the default window procedure.
- You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Window classes
-
- ■ Window messages and message queues
-
- ■ Dialog windows and dialog procedures
-
-
- 7.2 About Window Procedures
-
- Every window in MS OS/2 is associated with a window procedure that
- controls all aspects of the window: its appearance, how it responds to
- state changes, and how it processes user input.
-
- Each window class has an associated window procedure, and all windows of
- that class use the same window procedure. For example, the system defines
- a window procedure for the frame window class, and all frame windows use
- that window procedure.
-
- Applications typically define at least one new window class and an
- associated window procedure. The application can then create many
- instances of windows with that class, all of which use the same window
- procedure. Note that this means that the same piece of code may be called
- from several sources simultaneously. Therefore, care must be used when
- modifying shared resources from a window procedure.
-
- Dialog procedures have the same structure and function as window
- procedures. All material referring to window procedures in this chapter
- also applies to dialog procedures. The only real difference between a
- dialog procedure and a window procedure is the recommended default
- procedure and what messages are handled.
-
- The rest of this chapter shows how to write a window procedure and
- associate it with a window class.
-
- 7.2.1 Structure of a Window Procedure
-
- All window procedures share a common syntax and structure. Because all
- messages must use the same calling syntax, the arguments and return value
- for window procedures are interpreted differently depending on the message
- being handled. The following sections describe the syntax and structure of
- a window procedure.
-
- 7.2.1.1 Calling Convention
-
- From a programmer's point of view, a window procedure is a function that
- takes four arguments and returns a long word. The function must use Pascal
- calling conventions; that is, the arguments are pushed on the stack from
- left to right in the function definition and the function must clear the
- arguments from the stack before returning. This is different from the
- normal C-language calling convention, so the Microsoft C Optimizing
- Compiler provides the pascal keyword for defining functions that use the
- Pascal calling convention.
-
- You should use the EXPENTRY macro when defining window procedures to
- ensure that the functions are declared appropriately.
-
- Finally, you must ensure that the data-segment register is properly set up
- on entry to the window procedure. When the system calls the window
- procedure, it passes the proper data segment in the ax register. If you
- are programming in Microsoft C, use the _loadds keyword in your
- window-procedure definitions. This causes the compiler to insert the
- proper prolog and epilog code in your window procedures so that the data
- segment is initialized and restored properly. If you are programming in
- assembly language, you should load the ds register from ax on entry and
- restore the ds register on exit. If you are using another development
- environment, consult the relevant documentation for the appropriate
- compiler switch.
-
- Because a window procedure can be called recursively, it is probably best
- to minimize the number of local variables used in the window procedure. To
- avoid overusing local variables and possible stack overflow in deep
- recursion, you should call other functions outside your window procedure
- to process individual messages.
-
- 7.2.1.2 Arguments
-
- A window procedure takes four arguments: The first is a window handle; the
- second is a USHORT message designator; and the last two arguments are
- declared with the MPARAM data type, which is defined in the include files
- as a far pointer to the VOID data type (a generic pointer). The message
- arguments often contain information in both the low and high words of the
- long word. There are several macros defined in the pmwin.h include file
- that make it easier to extract bytes or integers from the fbMPARAM value.
- These macros include SHORT1FROMMP, which extracts the low-order word from
- an MPARAM value.
-
- The window-procedure arguments are described in the following list:
-
- Argument Description
- ──────────────────────────────────────────────────────────────────────────
- hwnd Window handle of the window receiving the message.
-
- msg Message identifier. The message will generally correspond to one
- of the predefined constants (for example, WM_CREATE) defined in
- the system include files. This argument can also be equal to an
- application-defined message identifier. Application-defined
- messages must be greater than WM_USER. If a window procedure
- does not process a message, it is strongly recommended that it
- pass the message to the WinDefWindowProc function. This allows
- the default processing for the message to occur.
-
- mp1 Message parameter. Its interpretation depends on the particular
- message.
-
- mp2 Message parameter. Its interpretation depends on the particular
- message.
- ──────────────────────────────────────────────────────────────────────────
-
- 7.2.1.3 Return Value
-
- The return value of a window procedure is defined as an MRESULT type. This
- is defined in the include files as a far pointer to a VOID data type. The
- actual interpretation of the return value depends on the particular
- message. Consult the description of each message to determine the
- appropriate return value.
-
- 7.2.2 Default Window Procedure
-
- All windows in MS OS/2 share certain fundamental behavior. This basic
- behavior is encapsulated in the WinDefWindowProc function, the default
- window procedure. The default window procedure is provided so you can get
- the minimal functionality for a window by calling WinDefWindowProc.
- Control windows defined by the system can also call WinDefWindowProc for
- default processing.
-
-
- 7.3 Using a Window Procedure
-
- The following code fragments show a sample window procedure. It shows how
- to use the message argument in a switch statement with individual messages
- handled by each case statement. Notice that each case returns a value
- specifically for that message. Consult the description of each message to
- determine the appropriate return value.
-
- The window procedure calls the WinDefWindowProc function for any messages
- that it does not handle itself. WinDefWindowProc performs default
- processing for essential messages sent to windows.
-
- MRESULT CALLBACK MyWindowProc(hwnd, msg, mp1, mp2)
- HWND hwnd;
- USHORT msg;
- MPARAM mp1;
- MPARAM mp2;
- {
- /* local variables */
-
- switch (msg) {
-
- case WM_CREATE:
- /* Initialize private window data. */
-
- return 0L;
-
- case WM_PAINT:
- /* Paint the window. */
-
- return 0L;
-
- case WM_DESTROY:
- /* Clean up private window data. */
-
- return 0L;
-
- default:
- break;
- }
- return (WinDefWindowProc(hwnd, msg, mp1, mp2));
- }
-
- A dialog procedure is exactly like a window procedure except that it
- receives a WM_INITDLG message instead of the WM_CREATE message. A dialog
- procedure should pass all unprocessed messages to the WinDefDlgProc
- function instead of passing them to the WinDefWindowProc function.
-
- It is possible to write a window procedure that passes all messages to
- WinDefWindowProc, but the window will have no personality of its own. At
- the very least, a window procedure should handle the WM_PAINT message to
- draw itself. Typically, it should handle mouse and keyboard messages as
- well. Consult the descriptions of individual messages to determine if your
- window procedure should handle them.
-
- There are times when you may want to create a window that does not change
- the default window behavior. That window's sole purpose is to keep track
- of its child windows. Object windows are often used this way. An easy way
- to create a window that does not change the default window behavior is to
- specify the WinDefWindowProc function as your window procedure when
- registering the window class. The application then does not write a
- separate window procedure for windows of this class.
-
- 7.3.1 Associating a Window Procedure and Classes
-
- A window procedure is associated with a window class by passing a far
- pointer to the window procedure to the WinRegisterClass function. Once
- registered this way, the window procedure will be associated with each new
- window created with that class.
-
- The following code fragment shows how to associate a window procedure with
- a window class:
-
- WinRegisterClass(hab, /* anchor-block handle */
- szClassName, /* class name */
- MyWindowProc, /* far pointer to procedure */
- CS_SIZEREDRAW, /* class style */
- 0); /* window data */
-
- Another useful option is to subclass a window of an existing class. This
- is most often used to add functionality or to alter the behavior of frame
- windows.
-
- To subclass a window, call the WinSubclassWindow function. This function
- returns a pointer to the window procedure for the window. Subclassing
- allows you to process messages using your own window procedure before
- passing unprocessed messages to the original window procedure. In this
- way, you can use the original window procedure instead of WinDefWindowProc
- for default window processing.
-
- 7.3.2 Processing a Default Window Procedure
-
- Typically, you call the WinDefWindowProc function for any messages that
- are not handled in your window procedure. For each message handled you
- should return an explicit value that depends on the particular message.
- For all other messages you should return the WinDefWindowProc function.
- The following code fragment shows how to structure a window procedure to
- call the default window procedure for any unused messages:
-
- switch (usMessage) {
- case WM_PAINT:
- hps = WinBeginPaint(hwnd, NULL, &rect);
- WinFillRect(hps, &rect, CLR_WHITE);
- WinEndPaint(hps);
- return 0L;
- default:
- break;
- }
- return (WinDefWindowProc(hwnd, usMessage, mp1, mp2));
-
- You can also call WinDefWindowProc as part of your own processing of a
- window message. In these cases, you may want to modify the parameters to
- the message before passing it to WinDefWindowProc, or you may want to
- continue with the default processing after performing your own operations.
-
-
- 7.4 Summary
-
- This section gives the window-procedure syntax and lists the messages
- processed by the default window procedure.
-
- 7.4.1 Window-Procedure Syntax
-
- The following shows the syntax for a window procedure:
-
- MRESULT CALLBACK WindowProc(HWND hwnd, USHORT msg,
- MPARAM mp1, MPARAM mp2)
-
- 7.4.2 Messages Processed by the Default Window Procedure
-
- The following messages are handled by the WinDefWindowProc function. For
- each message, the default processing is described; typical reasons for
- overriding the default behavior are also given:
-
- WM_BUTTON1DBLCLK The default window procedure passes this message to the
- owner window. Processing this message allows you to add functionality to
- mouse clicks and to differentiate the three possible mouse buttons.
-
- WM_BUTTON1DOWN The default window procedure activates the window by
- calling the WinSetActiveWindow function. Processing this message allows
- you to add functionality to mouse clicks and to differentiate the three
- possible mouse buttons.
-
- WM_BUTTON1UP The default window procedure passes this message to the
- owner window. Processing this message allows you to add functionality to
- mouse clicks and to differentiate the three possible mouse buttons.
-
- WM_BUTTON2DBLCLK The default window procedure passes this message to the
- owner window. Processing this message allows you to add functionality to
- mouse clicks and to differentiate the three possible mouse buttons.
-
- WM_BUTTON2DOWN The default window procedure activates the window by
- calling the WinSetActiveWindow function. Processing this message allows
- you to add functionality to mouse clicks and to differentiate the three
- possible mouse buttons.
-
- WM_BUTTON2UP The default window procedure passes this message to the
- owner window. Processing this message allows you to add functionality to
- mouse clicks and to differentiate the three possible mouse buttons.
-
- WM_BUTTON3DBLCLK The default window procedure passes this message to the
- owner window. Processing this message allows you to add functionality to
- mouse clicks and to differentiate the three possible mouse buttons.
-
- WM_BUTTON3DOWN The default window procedure activates the window by
- calling the WinSetActiveWindow function. Processing this message allows
- you to add functionality to mouse clicks and to differentiate the three
- possible mouse buttons.
-
- WM_BUTTON3UP The default window procedure passes this message to the
- owner window. Processing this message allows you to add functionality to
- mouse clicks and to differentiate the three possible mouse buttons.
-
- WM_CALCVALIDRECTS The default window procedure returns the long-word
- value. Processing this message allows you to specify the portion of the
- window that is preserved when the window is resized and to specify where
- the preserved area is aligned when the window is redrawn.
-
- WM_CHAR The default window procedure passes this message to the window
- owner. You can process this message to evaluate incoming keyboard events.
- In the case of standard control windows, unused WM_CHAR messages are
- passed to the WinDefWindowProc function and passed up the parent- and
- child-window hierarchy until reaching a frame or dialog window where
- default dialog effects, such as pressing the TAB key to move from control
- to control, are implemented.
-
- WM_CLOSE The default window procedure posts a WM_QUIT message to the
- queue, which causes the message loop to terminate. Processing this message
- allows you to prevent the Close menu item in the System menu from
- terminating the program. This is particularly useful with child frame
- windows in a multiple-document application.
-
- WM_CONTROLHEAP The default window procedure returns the heap handle for
- the heap maintained by the system for the window message queue. You
- process this message if the window maintains a separate heap.
-
- WM_CONTROLPOINTER The default window procedure returns the mouse pointer
- passed in the mp2 parameter, thus allowing the default pointer shape. This
- message is sent to the owner of a control window to allow it to change the
- shape of the mouse pointer when the pointer is over the control window.
- You can return a different mouse-pointer handle to override the mouse
- pointer chosen by the control window. For example, a special control that
- handles its mouse-movement message by sending a WM_CONTROLPOINTER message
- to its owner with its special pointer. The owner window then determines
- what pointer to use. The default window procedure would use the control's
- special pointer.
-
- WM_DDE_INITIATE The default window procedure frees the selector in the
- mp2 parameter and returns FALSE. You should process this message if your
- application supports the dynamic-data-exchange (DDE) protocol.
-
- WM_DDE_INITIATEACK The default window procedure frees the selector in the
- mp2 parameter and returns FALSE. You should process this message if your
- application supports the dynamic-data-exchange (DDE) protocol.
-
- WM_FOCUSCHANGE The default window procedure passes the message to the
- owner window (if one exists) or to the parent window if no owner exists.
- If no owner or parent window exists, the default window procedure does
- nothing. Generally, this message is passed up the parent- and child-window
- hierarchy until it reaches a frame window, where the appropriate
- WM_ACTIVATE, WM_SETSELECTION, and WM_SETFOCUS messages are generated. This
- message is the first indication of a focus change.
-
- WM_HELP The default window procedure passes this message to the parent
- window (if one exists). You process this message to provide
- context-sensitive help.
-
- WM_HITTEST The default window procedure returns HT_ERROR if the window is
- disabled; otherwise, it returns HT_NORMAL. Processing this message to
- return HT_NORMAL for a disabled window allows the disabled window to
- receive mouse messages.
-
- WM_MENUSELECT The default window procedure returns TRUE, which means the
- menu selection should be processed normally. You can process this message
- if you want to perform context-sensitive actions──for example, processing
- explanatory messages, each time a menu item is selected.
-
- WM_MOUSEMOVE The default window procedure sets the mouse pointer to the
- arrow pointer. You normally process this message for mouse tracking after
- a mouse button-down message. This message is also useful for setting the
- mouse-pointer shape, depending on where the mouse is in the window.
-
- WM_PAINT The default window procedure calls the WinBeginPaint and
- WinEndPaint functions to empty the update region for the window. If you do
- not process this message, the window will not be drawn.
-
- WM_QUERYCONVERTPOS The default window procedure returns the cursor size
- and positional data pointed to by the mp1 parameter and returns
- QCP_CONVERT to signify that the RECTL structure passed was properly
- converted.
-
- WM_QUERYFOCUSCHAIN The default window procedure performs the default
- processing of this message, which defines the focus chain for that window.
-
- WM_QUERYFRAMECTLCOUNT The default window procedure passes this message to
- the parent window until it finds a frame window, where it will be
- processed.
-
- WM_QUERYWINDOWPARAMS The default window procedure sets all window
- parameters in the passed structure to zero and returns FALSE to indicate
- that the operation was not successful.
-
- WM_SETWINDOWPARAMS The default window procedure does nothing except
- return FALSE.
-
- WM_TIMER The default window procedure blinks the cursor for the window if
- the timer message has the TID_CURSOR timer ID. You process this message
- only if they create their own timers. Applications should pass a WM_TIMER
- (TID_CURSOR) message to the WinDefWindowProc function even if the
- application processes its own timers.
-
- WM_TRANSLATEACCEL The default window procedure passes this message to the
- parent window (if one exists). This message is usually passed from a child
- window to its parent window until it reaches a frame window, where the
- default frame-window procedure calls the WinTranslateAccel function to
- determine if the key pressed is a valid accelerator key.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 8 Mouse and Keyboard Input
-
- 8.1 Introduction
- 8.2 About Mouse and Keyboard Input
- 8.2.1 The System Message Queue
- 8.2.2 Mouse Capture
- 8.2.3 Keyboard Focus
- 8.2.4 Window Activation
- 8.3 Using the Mouse and Keyboard in an Application
- 8.3.1 Responding to Activation Events
- 8.3.2 Responding to Mouse Messages
- 8.3.2.1 Responding to Button Clicks
- 8.3.2.2 Responding to Mouse Movement
- 8.3.3 Changing the Mouse Capture
- 8.3.4 Keyboard Messages
- 8.3.5 Responding to Keyboard Messages
- 8.3.5.1 Key-Down or Key-Up Events
- 8.3.5.2 Repeat-Count Events
- 8.3.5.3 Character Codes
- 8.3.5.4 Virtual-Key Codes
- 8.3.5.5 Scan Codes
- 8.3.5.6 Accelerator-Table Entries
- 8.3.6 Changing the Keyboard Focus
- 8.4 Summary
- 8.4.1 Functions
- 8.4.2 Messages
- 8.4.2.1 Focus Change and Activation Messages
- 8.4.2.2 Mouse Messages
- 8.4.2.3 Keyboard Message
-
- 8.1 Introduction
-
- This chapter describes how to use mouse and keyboard input in your
- applications. You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Window messages and message queues
-
- ■ Accelerator tables
-
-
- 8.2 About Mouse and Keyboard Input
-
- MS OS/2 Presentation Manager applications should support input from both
- the mouse and keyboard. The mouse can have either one, two, or three
- buttons. Only one window at a time can receive mouse input and only one
- window at a time can receive keyboard input. These windows are not
- necessarily the same, although they can be.
-
- 8.2.1 The System Message Queue
-
- All mouse and keyboard input is routed through a single system message
- queue. The system takes input events, such as keys being pressed or mouse
- movements, out of the system queue and routes them to the appropriate
- application. Generally, mouse input is directed to the application that
- owns the window in which the mouse-pointer event occurs. An application
- can route all mouse input, regardless of mouse position, to a particular
- window by setting the mouse capture window. Keyboard input is sent to the
- application that owns the "keyboard focus" window. Keyboard focus and
- mouse capture are discussed more fully later in this chapter.
-
- The system takes messages out of the system message queue and places them
- in the appropriate application message queue. An application receives
- input messages from its own queue by calling the WinGetMsg or WinPeekMsg
- function.
-
- Mouse and keyboard events in the system queue are strictly ordered so that
- an input event cannot be processed until all previous input events have
- been fully processed. This is because the destination window of an input
- event is not known until all previous input has been processed.
-
- For example, if a user types a command in one window, uses the mouse to
- activate another window, and then types another command in the second
- window, the destination of the second keyboard command depends on how the
- mouse click is handled. An application might not activate its window in
- response to the mouse click. The second keyboard event goes to the second
- window only if that window becomes active as a result of the mouse click,
- which also depends on how the application processes the mouse click.
-
- Because the input queue is strictly ordered and events cannot be processed
- until all previous input has been processed, it is very important that
- applications process input events quickly to avoid slowing user
- interactions with the system.
-
- 8.2.2 Mouse Capture
-
- Generally, a mouse message goes to the window under the mouse pointer at
- the time the event is read from the system queue. Applications can change
- this by setting the mouse capture window, in which case all mouse input is
- sent to the mouse capture window until the mouse capture is released or
- set to another window. Mouse capture is useful if a window should receive
- all mouse input even when the mouse pointer moves outside the window. For
- example, it is common to track the mouse-pointer position after a mouse
- button-down event, following the mouse pointer until a mouse button-up
- event is received. If you do not set the mouse capture to a particular
- window and the user moves the mouse pointer outside the window and
- releases the mouse button, your application will not receive the mouse
- button-up message. If you set the mouse capture to a particular window
- while tracking the mouse pointer, your application will receive the mouse
- button-up message even if the mouse moves outside the window.
-
- 8.2.3 Keyboard Focus
-
- Only one window at a time receives keyboard input. The window receiving
- the keyboard input is called the keyboard-focus window. Applications can
- allow the system to set the keyboard-focus window by default as windows
- are activated and deactivated, or an application can specifically set the
- keyboard focus to a specific window. If there is no keyboard-focus window
- specified, the system sends keyboard input to the currently active frame
- window.
-
- 8.2.4 Window Activation
-
- Because there can be many windows belonging to many applications on the
- screen at the same time, MS OS/2 provides a way to arbitrate input among
- windows and applications. There is at most one active application at any
- time in the Presentation Manager screen group. The active application
- usually has only one active frame window, although it is possible to have
- more than one active frame window. For example, an application with a
- multiple-document interface can have several child frame windows.
-
- The activation state of a window is important when an application responds
- to mouse clicks. It is also important because activation and keyboard
- focus are closely related window attributes.
-
- The WinQueryActiveWindow function returns the currently active frame
- window. Note that a client window is never returned by this function.
- Activation of the client window is an attribute of frame windows.
-
-
- 8.3 Using the Mouse and Keyboard in an Application
-
- An application that uses the mouse and keyboard for input must respond to
- activation, mouse, and keyboard events. The following sections describe
- how to handle these three related topics.
-
- 8.3.1 Responding to Activation Events
-
- A client window receives a WM_ACTIVATE message when its parent frame
- window is being activated or deactivated. The activation or deactivation
- message is usually accompanied by messages to set or lose the keyboard
- focus. Therefore, applications should not use the WM_ACTIVATE message to
- change the keyboard focus.
-
- The low word of the first message parameter is TRUE if the window is
- activated, and FALSE if the window is deactivated.
-
- One use for the WM_ACTIVATE message is to toggle the state of an
- application's private variable that tells whether a window is active or
- not, as shown in the following code fragment:
-
- case WM_ACTIVATE:
- fActivated = (BOOL) mp1;
- return(0L);
-
- It is important to know the activation state of a window in order to
- correctly handle mouse-button clicks.
-
- 8.3.2 Responding to Mouse Messages
-
- Mouse messages occur when a user presses or releases one of the mouse
- buttons (a click) and when the mouse is moved. All mouse messages contain
- the x- and y-coordinates of the mouse-pointer hot spot (relative to the
- window coordinates of the window receiving the message) at the time the
- event occurs.
-
- The system sends a WM_HITTEST message to the window that is about to
- receive a mouse message. The window can determine if it should actually
- receive the mouse message or not. The default processing of this message
- in the WinDefWindowProc function is to return HT_NORMAL if the window is
- enabled and HT_ERROR if the window is disabled. If the return value is
- HT_ERROR, the system does not send the mouse message to the window. Most
- applications pass WM_HITTEST messages on to the WinDefWindowProc function
- by default so disabled windows do not receive mouse messages. Windows that
- specifically respond to WM_HITTEST messages can change this default
- behavior.
-
- Because windows process WM_HITTEST and mouse messages, an application can
- ignore hit-test code in a mouse message unless the application returns
- special values for hit-test code. One possible use for hit-test code is to
- react differently to a mouse click in a disabled window.
-
- The contents of the mouse-message arguments (mp1 and mp2) are listed
- below:
-
- ■ The x-position is in low word of mp1.
-
- ■ The y-position is in high word of mp1.
-
- ■ The hit-test code is in low word of mp2.
-
- 8.3.2.1 Responding to Button Clicks
-
- Applications typically respond to mouse button-down events differently
- depending on whether the window is currently active. The first button-down
- event in an inactive window should activate a window. A subsequent
- button-down event in an active window produces an application-specific
- action.
-
- Typically, an application processes mouse clicks in the client window of a
- standard frame window. Because the activated/deactivated status of a
- window is a frame-window characteristic, the system does not provide an
- easy way to determine if the client window is active. That is, the window
- handle returned by the WinQueryActiveWindow function is the active
- frame-window handle rather than the client window owned by the frame.
-
- The following are two typical methods for determining if a client is an
- active frame window:
-
- ■ Call the WinQueryActiveWindow function and compare the window handle it
- returns with the frame window that contains the client window, as shown
- in the following code fragment:
-
- fActivated = (WinQueryWindow(hwndClient, QW_PARENT, FALSE) ==
- WinQueryActiveWindow(HWND_DESKTOP, FALSE))
-
- ■ Maintain a private variable for the client window that is set and
- cleared when processing WM_ACTIVATE messages. Each time the frame
- window is activated, the client window receives a WM_ACTIVATE message
- with the low word of the first parameter equal to TRUE. When the frame
- window is deactivated, the client window receives a WM_ACTIVATE message
- with a FALSE activation indicator. The following code fragment shows
- how to use activation messages to toggle a private-status variable:
-
- case WM_ACTIVATE:
- fActivated = (BOOL) mp1;
- return (0L);
-
- Depending on the method used to determine if a client window is active, a
- mouse button-down message is passed to the WinDefWindowProc function if
- the window is not active at the time of the message. The default
- processing activates the window and its frame.
-
- A common problem for an application processing WM_BUTTON1DOWN or similar
- messages is the failure to activate or set the window focus. If the window
- processes character messages, the window procedure should call the
- WinSetFocus function to make sure the window receives the input focus and
- is activated. If the window does not need the keyboard focus, an
- application should call the WinSetActiveWindow function.
-
- 8.3.2.2 Responding to Mouse Movement
-
- The system sends mouse-move messages to the window under the mouse pointer
- or the current mouse-capture window, if any, whenever the mouse pointer
- moves. This is useful for tracking the mouse pointer and changing its
- shape based on its location in a window. For example, the mouse pointer
- changes shape when it passes over the size border of a standard frame
- window.
-
- All standard control windows use mouse-move messages to set the
- mouse-pointer shape. If your application handles WM_MOUSEMOVE messages in
- some situations but not others, unused messages should be passed to the
- WinDefWindowProc function to change the shape of the mouse pointer.
-
- 8.3.3 Changing the Mouse Capture
-
- Mouse messages are usually routed to the window under the mouse pointer.
- Applications can call the WinSetCapture function to process all mouse
- messages by a specified window. This is particularly useful when an
- application is tracking the mouse pointer after a button-down message.
-
- For example, in a paint application that uses a button-down message to
- start a drawing operation, the application tracks the mouse using
- mouse-move messages until a button-up message is received. If a user drags
- the mouse pointer outside the window and releases the button, the
- button-up message will not go to the original window unless the
- application has called the WinSetCapture function for that window.
-
- Some applications must receive a button-up message to match a button-down
- message. When processing a button-down message, these applications call
- the WinSetCapture function to set the capture to their own window, and
- then they call the WinSetCapture function with a NULL window handle to
- release the mouse capture when processing a matching button-up message.
-
- 8.3.4 Keyboard Messages
-
- All keyboard messages come to a window as WM_CHAR messages. The system
- reads the keyboard and collects keyboard events in the system queue. It
- then routes these messages to the appropriate windows depending on the
- current keyboard-focus window at the time the message is sent. WM_CHAR
- messages are sent to the window that has the keyboard focus. If no window
- has the keyboard focus, then WM_CHAR messages are posted to the active
- frame-window queue. The following are two typical situations where
- applications receive WM_CHAR messages:
-
- ■ An application has a client window or custom control window, each of
- which can have the keyboard focus. If a window procedure for the client
- or control window does not process characters, it should pass them to
- its owner window, which can be accomplished by passing them through to
- the WinDefWindowProc function. This is especially true for
- dialog-control items, as this is how the TAB and direction-key control
- processing is implemented in the user interface.
-
- ■ An application window owns a control window that handles some, but not
- all WM_CHAR messages. This is common in dialog windows. If a control
- window that has the focus in a dialog window cannot process a WM_CHAR
- message, it can call the WinDefWindowProc function to send the message
- to its owner, which is usually a dialog-frame window. The application
- dialog procedure then receives the WM_CHAR message. This is also the
- case when an application client window owns a control window.
-
- 8.3.5 Responding to Keyboard Messages
-
- A WM_CHAR message may represent a key-down or key-up transition. It may
- contain a character code, a virtual-key code, or a scan code. This message
- also contains information about the state of the SHIFT, CONTROL, and ALT
- keys.
-
- Each time a user presses a key, at least two WM_CHAR messages are
- generated: one when the key is pressed down, and one when the key is
- released. If the key is held down long enough to trigger the keyboard
- repeat, multiple WM_CHAR key-down messages are generated.
-
- If the keyboard repeats faster than the application can retrieve the
- events from the event queue, the system combines repeating character
- events into one WM_CHAR event representing multiple-key events for the
- same key. WM_CHAR messages contain a count byte indicating the number of
- keystrokes represented by the message. Generally, this byte is set to 1,
- but it should be checked every time a WM_CHAR message is processed to
- avoid missing keystrokes.
-
- A control may ignore the repeat count; for example, it may ignore the
- count on direction keys. If the system is slow, it may be more aesthetic
- to have a cursor move slowly than to see it jump 40 characters.
-
- Applications decode WM_CHAR messages by examing individual bits in the
- flag word contained in the low word of the first argument passed with
- every WM_CHAR message. These bits may be set in various combinations. For
- example, a WM_CHAR message can have the KC_KEYDOWN, KC_CHAR, KC_SCANCODE,
- and KC_SHIFT attribute bits all set at the same time.
-
- The mp1 and mp2 parameters that are part of the message contain different
- information depending on the nature of the keyboard event, as follows:
-
- ■ The flag word is in low word of mp1.
-
- ■ The repeat-key count is in low byte of high word of mp1.
-
- ■ The scan code is in high byte of high word of mp1.
-
- ■ The character code (ASCII) is in low word of mp2.
-
- ■ The virtual-key code is in high word of mp2.
-
- An application window procedure should return TRUE if it processes a
- particular WM_CHAR message, or FALSE otherwise. Typically, applications
- respond to key-down events and ignore key-up events.
-
- The following sections describe the different types of WM_CHAR messages.
- Generally, decoding these messages consists of layers of conditional
- statements to eliminate and discriminate the different combinations of
- attributes that can occur in a keyboard message.
-
- 8.3.5.1 Key-Down or Key-Up Events
-
- Generally, the first attribute that an application checks in a WM_CHAR
- message is the key-down or key-up events. The distinction between a
- key-down and a key-up event is found by examining the KC_KEYUP bit of the
- low word of the first message parameter. If this flag bit is set, then the
- message is from a key-up event. If the bit is clear, then the message is
- from a key-down event. The following code fragment shows how to decode a
- message for this information:
-
- case WM_CHAR:
- fs = SHORT1FROMMP(mp1);
-
- if ((fs & KC_KEYUP))
-
- /* this is a key-up event */
-
- else
-
- /* this is a key-down event */
-
- return TRUE;
-
- 8.3.5.2 Repeat-Count Events
-
- Applications should always check the key repeat-count part of a WM_CHAR
- message to see if the message represents more than one keystroke. The
- count is greater than one if the keyboard is sending characters to the
- system queue faster than the application can retrieve them. If the system
- queue fills up, the system combines consecutive keyboard events for each
- key in a single WM_CHAR message with the repeat count set to the number of
- combined events. The repeat count is in the low byte of the high word of
- the first message parameter.
-
- 8.3.5.3 Character Codes
-
- The most typical use of WM_CHAR messages is to extract a character code
- from the message and display the character on the screen. When the KC_CHAR
- bit is set in the WM_CHAR message, the low word of the second message
- parameter contains a character code based on the current code page.
- Generally, this value is a glyph code (typically an ASCII code) for the
- character for the key that was pressed.
-
- The following code fragment shows how to respond to a character message:
-
- fs = SHORT1FROMMP(mp1);
-
- if (fs & KC_CHAR) {
-
- /* CHAR is in SHORT1FROMMP(mp2) */
-
- /* handle the key character */
-
- return(TRUE);
- }
-
- Note that if the KC_CHAR bit is not set, the SHORT1FROMMP(mp2) parameter
- may still contain useful information. If either the ALT or CTRL key, or
- both, are down, the KC_CHAR bit will not be set when the user presses
- another key. For example, pressing the a key when the ALT key is down, the
- low word of mp2 will contain a 0x0041, the KC_ALT bit will be set, and the
- KC_CHAR bit will be clear. If the translation does not generate any valid
- characters, the char field is set to zero.
-
- 8.3.5.4 Virtual-Key Codes
-
- WM_CHAR messages often contain virtual-key codes that correspond to
- various function keys and direction keys on a typical keyboard. These keys
- do not correspond to any particular glyph code but are used to initiate
- operations. When the KC_VIRTUALKEY bit is set in flag word of a WM_CHAR
- message, the high word of the second message parameter contains a
- virtual-key code for the key.
-
- Note that some keys, such as the ENTER key, have both a valid character
- code and a virtual-key code. WM_CHAR messages for these keys will contain
- character codes for newline characters (ASCII 11) and virtual-key codes
- (VK_ENTER).
-
- The following code fragment shows how to decode a WM_CHAR message
- containing a valid virtual-key code:
-
- fs = SHORT1FROMMP(mp1);
-
- if (fs & KC_VIRTUALKEY) {
-
- /* virtual key is in SHORT2FROMMP(mp2) */
-
- switch (SHORT2FROMMP(mp2)) {
- case VK_TAB:
-
- /* handle the TAB key */
-
- return (TRUE);
-
- case VK_LEFT:
-
- /* handle the LEFT key */
-
- return (TRUE);
-
- case VK_UP:
-
- /* handle the UP key */
-
- return (TRUE);
-
- case VK_RIGHT:
-
- /* handle the RIGHT key */
-
- return (TRUE);
-
- case VK_DOWN:
-
- /* handle the DOWN key */
-
- return (TRUE);
- .
- .
- .
- default:
- return (FALSE);
- }
- }
-
- 8.3.5.5 Scan Codes
-
- A third possible value in a WM_CHAR message is the scan code for the key
- pressed. The scan code represents the value generated by the keyboard
- hardware when a key is pressed. An application can use the scan code to
- identify the physical key pressed, as opposed to the character code
- represented by the same key. The byte-length value for the scan code is in
- the high byte of the high word of the first message parameter.
-
- All WM_CHAR messages that are generated by the keyboard have valid scan
- codes. WM_CHAR messages that are posted by other applications may or may
- not have valid scan codes. The following code fragment shows how to
- extract a scan code from a WM_CHAR message:
-
- fs = SHORT1FROMMP(mp1);
-
- if (fs & KC_SCANCODE) {
-
- /* scan code is in HIBYTE(HIWORD(mp1)) */
-
- return (TRUE);
- }
-
- 8.3.5.6 Accelerator-Table Entries
-
- The system checks all incoming keyboard messages to see if they match any
- existing accelerator-table entries, either in the system queue or in the
- application-message queue. The translation first checks the accelerator
- table associated with the active frame window, and if no match is found,
- it uses the accelerator table associated with the message queues. If the
- keyboard event corresponds to an accelerator-table entry, the WM_CHAR
- message changes to a WM_COMMAND, WM_SYSCOMMAND, or WM_HELP message,
- depending on the attributes of the accelerator table. The original WM_CHAR
- message is not processed by the application.
-
- Accelerator tables should be used to implement keyboard shortcuts in
- applications rather than translating command keystrokes. For example, if
- an application uses the F2 key to save a document, a keyboard accelerator
- entry for the F2 virtual key should be created so that it generates a
- WM_COMMAND message rather than a WM_CHAR message.
-
- 8.3.6 Changing the Keyboard Focus
-
- Applications can change the keyboard focus window by calling the
- WinSetFocus function for the new focus window.
-
- The WinSetFocus function causes the following events to occur:
-
- ■ If a window currently has the focus, it receives a WM_SETFOCUS message
- indicating the loss of focus.
-
- ■ If a window currently has the focus, it receives a WM_SETSELECTION
- message indicating that it should deselect the current selection.
-
- ■ If changing focus causes a change in the active window and there is a
- currently active window, a WM_ACTIVATE message is sent to the active
- window indicating the loss of active status.
-
- ■ A new active window, new focus window, and the active application are
- established.
-
- ■ If the active window is changing, a WM_ACTIVATE message is sent to the
- new main window indicating the acquisition of active status.
-
- ■ The new focus window is sent a WM_SETSELECTION message indicating that
- it should select the current selection.
-
- ■ The new focus window is sent a WM_SETFOCUS message indicating the
- acquisition of focus.
-
- Using the WinQueryActiveWindow or WinQueryFocus function while processing
- the WinSetFocus function causes the previous active and focus windows to
- be returned until new active and focus windows are established. In other
- words, even though WM_SETFOCUS and WM_ACTIVATE messages with the fFocus
- parameter equal to FALSE may have been sent to the previous windows, those
- windows are considered active and have the focus until the system
- establishes new active and focus windows.
-
- If the WinSetFocus function is called during the WM_ACTIVATE message
- processing, a WM_SETFOCUS message with the fFocus parameter equal to FALSE
- is not sent because no window has the focus.
-
-
- 8.4 Summary
-
- The following sections describe the functions and messages associated with
- activation and keyboard/mouse input.
-
- 8.4.1 Functions
-
- The following are the functions associated with activation, keyboard, and
- mouse input:
-
- WinEnablePhysInput Enables or disables mouse and keyboard input,
- depending on the fEnable argument. Because this call affects the system
- queue, it is important that any application that disables input should
- enable it again as soon as possible.
-
- WinFocusChange A version of the WinSetFocus function that allows more
- control over messages generated for the old and new focus windows. For
- example, if an application sets the focus to a new window without
- deselecting text in the old focus window, this function should be used.
-
- WinGetKeyState Used to determine whether a specified virtual key is up,
- down, or toggled. A key, such as the CAPSLOCK key, is toggled if it has
- been pressed an odd number of times. This function can also be used to
- obtain the state of the mouse buttons that use the VK_BUTTON1, VK_BUTTON2,
- and VK_BUTTON3 virtual key codes.
-
- WinGetPhysKeyState Returns information about the asynchronous (interrupt
- level) state of a specified virtual key. This function returns the
- physical state of the key; it is not synchronized to the processing of
- input and is not affected by calls to the WinSetKeyboardStateTable
- function.
-
- WinIsPhysInputEnabled Returns the status, on or off, of mouse and
- keyboard input.
-
- WinQueryCapture Returns the window handle of the window currently holding
- the mouse capture. If the fLock argument is TRUE, the window is returned
- locked and remains locked until it is unlocked by calling the
- WinLockWindow function with fLock set to FALSE.
-
- WinQueryFocus Returns the keyboard focus window, or NULL if no focus
- window exists. If the fLock argument is TRUE, the window is returned
- locked and remains locked until it is unlocked by calling the
- WinLockWindow function with fLock set to FALSE.
-
- WinSetCapture Sends all mouse messages to a specified window. Specifying
- a NULL window handle releases the mouse capture so that mouse input is
- sent to the window beneath the mouse pointer.
-
- WinSetFocus Sets the focus window to the specified window, or to no
- window if a NULL window is specified for the hwndSetFocus argument. This
- function can cause activation and deactivation messages to go to the
- current and new focus windows. The window losing focus receives
- WM_SETFOCUS(FALSE)and WM_SETSELECTION(FALSE) messages. The frame window
- losing the focus receives a WM_ACTIVATE(FALSE) message, and by default
- passes it to its FID_CLIENT window. The frame window receiving the focus
- receives a WM_ACTIVATE(TRUE) message, which it passes to its FID_CLIENTp
- window by default. The window receiving the focus receives the
- WM_SETSELECTION(TRUE), and WM_SETFOCUS(TRUE) messages.
-
- WinSetKeyboardStateTable This function receives or sets the
- keyboard-state table. To change the state of one virtual key, call the
- WinSetKeyboardStateTable function with the fSet argument set to FALSE to
- copy the current state table into a 256-byte table (pointed to by the
- pKeyStateTable argument). It is then possible to modify a virtual-key
- entry in the table and call the WinSetKeyboardStateTable function using
- the same table and fSet argument set to TRUE. This call does not change
- the physical state of the keyboard. It affects the result of subsequent
- calls to the WinGetKeyState function, but not the result of calls to the
- WinGetPhysKeyState function.
-
- 8.4.2 Messages
-
- The following sections describe the messages associated with focus change,
- activation, the mouse, and the keyboard.
-
- 8.4.2.1 Focus Change and Activation Messages
-
- The following messages are associated with focus change and activation:
-
- WM_ACTIVATE Sent to a window when it is activated or deactivated. This
- function can be used for tracking the activation state of a client window.
-
- WM_FOCUSCHANGE Sent to a window when the focus is changing. Most
- applications pass this message to the WinDefWindowProc function, which
- sends it to the parent frame window. The frame window uses this message to
- generate appropriate WM_ACTIVATE, WM_SETFOCUS, and WM_SETSELECTION
- messages for the old and new focus windows.
-
- WM_QUERYFOCUSCHAIN Used to define the focus chain (that is, to keep from
- hard wiring the focus chain to the parent-window relationship).
-
- WM_SETFOCUS Sent to a window when it is losing or receiving the keyboard
- focus. A typical response is to display a text-insertion cursor when
- receiving the focus and hide the cursor when losing the focus.
-
- WM_SETSELECTION Sent to a window when it is receiving or losing the
- keyboard focus. A typical response is to highlight the currently selected
- text when receiving the focus and unhighlight the selection when losing
- the focus.
-
- 8.4.2.2 Mouse Messages
-
- The following messages are associated with mouse events:
-
- WM_BUTTON1DBLCLK Sent to the window under the mouse pointer or the
- current mouse capture window, if any, when the user clicks the first mouse
- button twice in a system-specified time limit. The amount of time between
- clicks necessary to make the action a double-click is a system parameter
- that a user can set using Control Panel. The application receives a
- WM_BUTTON1DOWN and WM_BUTTON1UP message for the first click of a
- double-click.
-
- WM_BUTTON1DOWN Sent to the window under the mouse pointer or the current
- mouse capture window, if any, when the user presses the first mouse
- button.
-
- WM_BUTTON1UP Sent to the window under the mouse pointer or the current
- mouse capture window, if any, when the user releases the first mouse
- button.
-
- WM_BUTTON2DBLCLK Like WM_BUTTON1DBLCLK but for the second mouse button.
-
- WM_BUTTON2DOWN Like WM_BUTTON1DOWN but for the second mouse button.
-
- WM_BUTTON2UP Like WM_BUTTON1UP but for the second mouse button.
-
- WM_BUTTON3DBLCLK Like WM_BUTTON1DBLCLK but for the third mouse button.
-
- WM_BUTTON3DOWN Like WM_BUTTON1DOWN but for the third mouse button.
-
- WM_BUTTON3UP Like WM_BUTTON1UP but for the third mouse button.
-
- WM_HITTEST This message occurs when an application requests a message by
- calling the WinPeekMsg or WinGetMsg function. If the message represents a
- mouse event, it is sent to the the window under the mouse pointer or to
- the current capture window, if any, to determine whether the message is
- destined for the window. The default window procedure returns HT_ERROR if
- the window is disabled; otherwise, it returns HT_NORMAL. The handling of
- this message determines whether a disabled window can process mouse
- clicks.
-
- WM_MOUSEMOVE Sent to the window under the mouse pointer or the window
- with the mouse capture, if any, when the mouse pointer moves. The system
- generates this message only as often as the application requests new
- messages. The distance the mouse pointer moves before this message is
- posted depends on how fast the application executes its message loops.
-
- 8.4.2.3 Keyboard Message
-
- The following message is associated with keyboard events:
-
- WM_CHAR Posted to the current focus window whenever there is a keyboard
- event. The message contains a flag word that indicates the composition of
- the message. The following list of flag values can be used to test the
- flag word to determine the nature of a message:
-
- ╓┌─┌─────────────────┌───────────────────────────────────────────────────────╖
- Flag Meaning
- ──────────────────────────────────────────────────────────────────────────
- KC_ALT The ALT key was down when this message was generated.
-
- KC_CHAR The message contains a valid character code for a key.
- Typically, this code is an ASCII code.
-
- KC_COMPOSITE In combination with the KC_CHAR flag this flag bit means
- that the character code is a combination of the key that
- was pressed and the previous dead key. This is used to
- create characters with diacritical marks.
-
- KC_CTRL The CONTROL key was down when this message was
- generated.
-
- KC_DEADKEY In combination with a KC_CHAR flag this flag bit means
- that the character code represents a dead-key glyph
- (such as an accent). An application displays the
- Flag Meaning
- ──────────────────────────────────────────────────────────────────────────
- (such as an accent). An application displays the
- dead-key glyph and does not advance the cursor.
- Typically, the next WM_CHAR message is a KC_COMPOSITE
- message containing the character associated with the
- dead-key character.
-
- KC_INVALIDCHAR The current character is not valid for the current
- translation tables.
-
- KC_INVALIDCOMP The current character is not valid in combination with
- the previous dead key.
-
- KC_KEYUP The message was generated when the user released the
- key. If this flag bit is clear, the message was
- generated when the user pressed the key. Use this bit to
- determine key-down and key-up events.
-
- KC_LONEKEY No other key was pressed while this key was down.
- Typically used to indicate that the user pressed the ALT
- Flag Meaning
- ──────────────────────────────────────────────────────────────────────────
- Typically used to indicate that the user pressed the ALT
- key by itself.
-
- KC_PREVDOWN In combination with a KC_VIRTUALKEY flag this flag bit
- means that the virtual key was previously down. If this
- flag bit is clear, the virtual key was previously up.
-
- KC_SCANCODE The message contains a valid raw scan code generated by
- the keyboard when the key is pressed. The scan code is
- used by the system to identify the character code in the
- current code page, therefore, most applications do not
- need the scan code unless they cannot identify the key
- that was pressed. WM_CHAR messages generated by actual
- user keyboard input generally have a valid scan code,
- but WM_CHAR messages posted to the queue by other
- applications might not contain a scan code.
-
- KC_SHIFT The SHIFT key was down when this message was generated.
-
- Flag Meaning
- ──────────────────────────────────────────────────────────────────────────
- KC_TOGGLE The KC_TOGGLE bit toggles "on" and "off" every time the
- key is pressed. For example, it is set "on" every odd
- number of presses and "off" every even number of
- presses. This is important for keys like NUMLOCK, which
- have an on or off state.
-
- KC_VIRTUALKEY The message contains a valid virtual-key code for a key.
- Virtual keys typically correspond to function keys.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 9 Frame Windows
-
- 9.1 Introduction
- 9.2 About Frame Windows
- 9.2.1 Main Window
- 9.2.2 Frame Controls
- 9.2.3 Client Window
- 9.2.4 Sizing Border and Minimize and Maximize Buttons
- 9.2.5 Frame-Control Identifiers
- 9.2.6 Frame-Window Creation
- 9.2.7 Frame-Control Flags
- 9.2.8 Frame-Window Styles
- 9.2.9 Frame-Window Resources
- 9.2.10 Frame-Window Class Data
- 9.2.11 Frame-Window Data
- 9.2.12 Frame-Window Operation
- 9.2.13 Nonstandard Frame Windows
- 9.2.14 Default Frame-Window Behavior
- 9.3 Using Frame Windows
- 9.3.1 Creating a Main Window
- 9.3.2 Retrieving Frame Handles
- 9.4 Summary
- 9.4.1 Functions
- 9.4.2 Messages
-
- 9.1 Introduction
-
- This chapter describes creating and using frame windows in Presentation
- Manager applications. You should also be familiar with the following
- topics:
-
- ■ Standard user-interface guidelines
-
- ■ Windows
-
- ■ Window relationships
-
- ■ Control windows
-
- ■ Messages and message queues
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
-
- 9.2 About Frame Windows
-
- A frame window is the basic window used by most Presentation Manager
- applications. A frame window provides a base for the application's main
- window, dialog windows, and message boxes. Although applications rarely
- use frame windows alone, applications nearly always start with a frame
- window to create a composite window that consists of the frame window,
- several frame controls, and a client window. The frame window coordinates
- the actions of the other windows, allowing the composite window to act as
- if it were a single unit.
-
- A frame window is a window of the preregistered, public-window class
- WC_FRAME. The frame-window class, like the preregistered control classes,
- defines the appearance and behavior of the frame window. The appearance
- and behavior of a frame window are designed to match the standard
- user-interface guidelines for MS OS/2 Presentation Manager applications,
- including applications that use the multiple-document interface. This
- means that applications that use frame windows have a quick and efficient
- way to create the "standard" windows recommended by the user-interface
- guidelines.
-
- Although frame windows are an important part of dialog windows, dialog
- windows are not described in this chapter. For a complete description of
- dialog windows, see Chapter 19, "Dialog Windows."
-
- 9.2.1 Main Window
-
- An application's main window is typically made up of a frame window with
- control windows such as a title bar, System menu, menu bar, and scroll
- bar. The main window also typically includes a client window.
-
- The frame window is sometimes under other windows. Although it is not
- visible, it provides the standard services the user expects from the
- window──for example, moving, sizing, minimizing, and maximizing. The frame
- window receives input from the control windows (called frame controls). It
- sends messages to the frame controls and to the client window to tell what
- action is needed next.
-
- 9.2.2 Frame Controls
-
- When an application creates a frame window, it can specify that one or
- more control windows be created as child windows of the frame window. A
- frame window can have a title-bar, System-menu, menu, and scroll-bar
- controls. Each is a unique window created from a preregistered
- control-window class.
-
- These frame controls provide a particular aspect of the user interface for
- a "standard" application window. A title bar appears at the top of the
- window and displays the application and/or window title. A System menu
- appears at the left end of the title bar. It contains the commands used to
- move, size, and close the window. A menu appears below the title bar and
- contains the commands the user can choose to carry out work with the
- application. The scroll bars appear at the right edge and bottom of the
- frame window. These let the user scroll the contents of the client window.
-
- Although all frame controls are optional, most, if not all, application
- main windows use the title-bar and System-menu controls. These provide the
- minimum functionality for a window that meets the user-interface
- guidelines.
-
- Each frame control is a child window of the frame window. Each frame
- control is owned by the frame window. That is, the frame window is the
- owner as well as the parent window for each frame control. Because the
- main role of a frame window is to coordinate the activities of other
- windows, ownership of the frame controls is very important. Ownership
- gives the frame controls a way to send notification messages to the frame
- window. Notification messages tell the frame window what the user does
- with the frame control.
-
- For example, a user can move a window by clicking the title bar and then
- dragging the window to a new position using a mouse. The title bar
- responds to the click by sending a message to the frame window notifying
- it of the user's request to move the window. The frame window can then
- track the mouse motion and move the frame window and all its child windows
- to the new position.
-
- An application can add frame controls to a frame window by specifying the
- FCF_TITLEBAR, FCF_SYSMENU, FCF_MENU, FCF_VERTSCROLL, and FCF_HORZSCROLL
- styles. Frame controls are described in separate chapters. For a general
- discussion of controls, see Chapter 10, "Control Windows."
-
- 9.2.3 Client Window
-
- Every main window has a client window. The client window is the part of
- the main window where the application displays output and receives mouse
- and keyboard input. What an application displays in the client window, how
- it displays it, and how it interprets input to the window is controlled
- entirely by the application.
-
- An application creates the client window when it creates the frame window.
- The client window is specific to the application; it is nearly always
- created by using a private window class (a class registered by the
- application). Like frame controls, the client window is a child window and
- an owned window of the frame window. This means, for example, that the
- client window moves when the frame window moves, that the client window is
- clipped to the frame-window size, and that the client window is destroyed
- when the frame window is destroyed.
-
- The relationship between the frame window and the client window allows the
- frame window to pass messages from other frame controls to the client
- window and vice versa. For example, a scroll-bar control notifies the
- frame window when the user requests scrolling; the frame window then sends
- a message to the client window. The client window requests that the frame
- window change the window title; the frame window sends a message to the
- title-bar control.
-
- 9.2.4 Sizing Border and Minimize and Maximize Buttons
-
- Although the sizing border and minimize and maximize buttons are not frame
- controls, they act very much like controls for the frame window. However,
- they are different than frame controls because the frame window draws and
- maintains these items; frame controls draw and maintain themselves.
-
- The sizing border, enclosing the frame window, lets the user change the
- size of the window by using a mouse. The minimize button, at the right end
- of the title bar, lets the user shrink the frame window to an icon. The
- maximize button, next to the minimize button, lets the user enlarge the
- window so that it fills the screen. An application can add these items to
- a frame window by using the FCF_SIZEBORDER, FCF_MAXBUTTON, and
- FCF_MINBUTTON (or the FCF_MINMAX) styles. (The FCF_MINMAX style adds both
- a minimize and a maximize button.)
-
- 9.2.5 Frame-Control Identifiers
-
- A frame window uses a set of standard constants to identify the frame
- controls and the client window. The frame-control identifiers all begin
- with the prefix FID_ and can be used in functions such as WinWindowFromID
- to uniquely identify a given control or the client window. The frame
- controls also use these identifiers in notification messages they send to
- the frame window. The following are the frame-control identifiers:
-
- ■ FID_CLIENT
-
- ■ FID_HORZSCROLL
-
- ■ FID_MENU
-
- ■ FID_MINMAX
-
- ■ FID_SYSMENU
-
- ■ FID_TITLEBAR
-
- ■ FID_VERTSCROLL
-
- 9.2.6 Frame-Window Creation
-
- An application can create a frame window by using the WinCreateWindow
- function and specifying the WC_FRAME window class. This creates the frame
- window but does not add the frame controls and client window that
- accompany most frame windows in applications. To add these additional
- windows, the application can continue to call the WinCreateWindow
- function, specifying the original frame window as the parent and owner
- window for each frame control and for the client window. Or the
- application can call WinCreateStdWindow, which automatically carries out
- the individual calls to WinCreateWindow.
-
- Frame windows are also used to create dialog windows. In this case, the
- frame window contains control windows but no client window. An application
- can create a dialog window by using the WinLoadDlg or WinCreateDlg
- function. These functions require an appropriate dialog template from the
- application's resources on disk or from memory. The dialog template
- specifies the styles and dimensions for the frame window and the control
- windows that make up the dialog window.
-
- 9.2.7 Frame-Control Flags
-
- An application can specify both the frame-window style and the frame
- controls for a frame window by using the frame-control flags with the
- WinCreateStdWindow function. The following are the frame-control flags:
-
- ╓┌─┌─────────────────────────┌───────────────────────────────────────────────╖
- Flag Description
- ──────────────────────────────────────────────────────────────────────────
- FCF_TITLEBAR Creates a title bar.
-
- FCF_SYSMENU Creates a System menu.
-
- FCF_MENU Creates a menu. This flag loads a menu from the
- application's resources on disk.
-
- FCF_MINBUTTON Creates a minimize button.
-
- FCF_MAXBUTTON Creates a maximize button.
-
- FCF_MINMAX Creates both a minimize and a maximize button.
-
- FCF_VERTSCROLL Creates a vertical scroll bar.
-
- FCF_HORZSCROLL Creates a horizontal scroll bar.
- Flag Description
- ──────────────────────────────────────────────────────────────────────────
- FCF_HORZSCROLL Creates a horizontal scroll bar.
-
- FCF_SIZEBORDER Creates a sizing border. A sizing border lets
- the user adjust the size of the window.
-
- FCF_BORDER Creates a border. Use this flag for windows that
- must not change size.
-
- FCF_DLGBORDER Creates a dialog border. Use this flag for
- dialog windows.
-
- FCF_SHELLPOSITION Directs the frame window to request an initial
- size and position from Start Programs.
-
- FCF_TASKLIST Adds the window title to the switch list of Task
- Manager. If the process creating a frame window
- already has an entry in the switch list, the
- window title is appended to the previous entry.
-
- Flag Description
- ──────────────────────────────────────────────────────────────────────────
- FCF_NOBYTEALIGN Enables the frame window to be moved to any
- position on the screen. If this flag is not
- given, a frame window always adjusts its
- position so that the x-coordinate of its left
- edge is a multiple of 8. Using this flag affects
- how quickly the system can draw the frame
- window.
-
- FCF_NOMOVEWITHOWNER Enables the frame window to maintain its
- position even if its owner window moves. This
- applies only to frame windows that are not child
- windows of the owner. If this flag is not given,
- the frame window moves when the owner window
- moves.
-
- FCF_ICON Loads an icon from the application's resources
- on disk. The icon is used whenever the frame
- window is minimized.
- Flag Description
- ──────────────────────────────────────────────────────────────────────────
- window is minimized.
-
- FCF_ACCELTABLE Loads an accelerator table from the
- application's resources on disk. The accelerator
- table is used for all keyboard input to the
- frame window.
-
- FCF_SYSMODAL Creates a system-modal frame window. Setting
- this flag is the same as using the
- WinSetSysModalWindow function.
-
- FCF_SCREENALIGN Aligns the initial position of the frame window
- relative to the screen origin instead of to the
- parent window.
-
- FCF_MOUSEALIGN Aligns the initial position of the frame window
- relative to the mouse position instead of to the
- parent window. An application can use this flag
- to position the default button in a dialog
- Flag Description
- ──────────────────────────────────────────────────────────────────────────
- to position the default button in a dialog
- window under the mouse pointer.
-
- FCF_STANDARD Combines the FCF_TITLEBAR FCF_SYSMENU, FCF_MENU,
- FCF_SIZEBORDER, FCF_MINMAX, FCF_ICON,
- FCF_ACCELTABLE, FCF_SHELLPOSITION, and
- FCF_TASKLIST styles.
- ──────────────────────────────────────────────────────────────────────────
-
-
- When the WinCreateStdWindow function is called without any of these flags
- set, the standard window is created invisible, behind all its sibling
- windows, in Z order, with a width and height of zero, positioned at the
- lower-left of its parent window. When WinCreateStdWindow returns, you can
- call WinSetWindowPos to change the window's size, x- and y-positions,
- Z-order position, and visibility.
-
- When WinCreateStdWindow is called with the FCF_SHELLPOSITION frame-control
- flag, the window is created in front of its sibling windows, in Z order,
- with a standard size and x- and y-positions obtained from the shell
- program.
-
- 9.2.8 Frame-Window Styles
-
- The frame-window class, like other preregistered window classes, provides
- many class-specific window styles that applications can use to adapt the
- appearance and behavior of a frame window. The frame-window styles,
- specified as constants starting with the FS_ prefix, can be combined with
- the standard window styles when creating a frame window. The following are
- the frame-window styles:
-
- ╓┌─┌──────────────────────┌──────────────────────────────────────────────────╖
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- FS_ACCELTABLE Loads an accelerator table from the application's
- resources on disk. The frame window uses the
- accelerator table to translate keyboard input.
-
- FS_BORDER Creates a single-line border. Use this style when
- the window must not change size.
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- the window must not change size.
-
- FS_SIZEBORDER Creates a sizing border. Use this style to let the
- user adjust the size of the window.
-
- FS_DLGBORDER Creates a double-line dialog border. Use this style
- for dialog windows.
-
- FS_ICON Loads an icon from the application's resources on
- disk. The frame window draws the icon when the
- window is minimized.
-
- FS_SCREENALIGN Aligns the initial position of the frame window
- relative to the screen origin instead of to the
- parent window.
-
- FS_MOUSEALIGN Aligns the initial position of the frame window
- relative to the mouse position instead of to the
- parent window. An application can use this style to
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- parent window. An application can use this style to
- position the default button in a dialog window
- under the mouse pointer.
-
- FS_NOBYTEALIGN Enables the frame window to be moved to any
- position on the screen. If this style is not given,
- a frame window always adjusts its position so that
- the x-coordinate of its left edge is a multiple of
- 8. Using this style affects how quickly the system
- can draw the frame window.
-
- FS_NOMOVEWITHOWNER Enables the frame window to keep its position even
- if its owner window moves. This applies only to
- frame windows that are not child windows of the
- owner window. If this style is not given, the frame
- window moves when the owner window moves.
-
- FS_SHELLPOSITION Directs the frame window to request an initial size
- and position from Start Programs.
- Style Description
- ──────────────────────────────────────────────────────────────────────────
- and position from Start Programs.
-
- FS_SYSMODAL Creates a system-modal window. Using this style is
- the same as calling the WinSetSysModalWindow
- function for the frame window.
-
- FS_TASKLIST Adds the window title to the switch list of Task
- Manager. If the process creating a frame window
- already has an entry in the switch list, the window
- title is appended to the previous entry.
-
- FS_STANDARD Combines the FS_ICON, FS_ACCELTABLE,
- FS_SHELLPOSITION, and FS_TASKLIST styles.
- ──────────────────────────────────────────────────────────────────────────
-
-
- The FS_ window styles are rarely used. Although the constants are useful
- for creating a frame window without also creating frame controls, most
- applications use frame controls and therefore use the JFCF_ constants to
- specify the frame-window styles. For each FS_ constant there is an
- equivalent FCF_ constant For more information, see the following section.
-
- 9.2.9 Frame-Window Resources
-
- If the FCF_MENU, FCF_ICON, FCF_ACCELTABLE, FCF_STANDARD, FS_ICON,
- FS_ACCELTABLE, or FS_STANDARD style is specified when creating the frame
- window, the application must provide the appropriate resources to support
- these styles. Depending on the style, a frame window may attempt to load
- one or more resources from the application's resources on disk.
-
- You can use Resource Compiler to add icon and accelerator-table resources
- to the application's executable file. Each resource must have a resource
- identifier that matches the resource identifier specified in the
- FRAMECDATA structure passed to the WinCreateWindow function or in the
- idResources parameter of the WinCreateStdWindow function.
-
- The following list gives the frame-control flags and styles that require
- resources and describes what the resource should be:
-
- Style Resource
- ──────────────────────────────────────────────────────────────────────────
- FCF_ICON Requires an icon resource. The frame window draws the
- FS_ICON icon whenever the window is minimized.
-
- FCF_MENU Requires a menu-template resource. A frame window uses
- the menu template to create a menu containing the
- commands and menus specified by the resource.
-
- FCF_ACCELTABLE Requires an accelerator-table resource. The frame
- FS_ACCELTABLE window uses the accelerator table to translate WM_CHAR
- messages to WM_COMMAND, WM_SYSCOMMAND, or WM_HELP
- messages.
-
- FCF_STANDARD Requires a menu template, an accelerator table, and an
- FS_STANDARD icon resource.
- ──────────────────────────────────────────────────────────────────────────
-
- The application must specify the module containing the resources
- (typically the application's executable file) when it creates the frame
- window. The resources must have the same resource identifier and the
- application must supply this identifier when creating the window.
-
- 9.2.10 Frame-Window Class Data
-
- An application can specify class-specific data for a frame window by
- passing a FRAMECDATA structure to the WinCreateWindow function. The
- class-specific data contains the frame-control flags, resource-module
- handle, and resource identifier to be used when creating the frame window.
-
- Frame-control flags specify what controls to create for the frame window
- and what window styles to apply to the frame window. The frame-control
- flags are the same flags (FCF_) used in the WinCreateStdWindow function.
- The resource-module handle and the resource identifier specify where to
- find resources for the frame window.
-
- Supplying class-specific data with WinCreateWindow is similar to using the
- WinCreateStdWindow function without creating a client window.
-
- 9.2.11 Frame-Window Data
-
- Frame-window data specifies the state of the frame window at a given time.
- An application can retrieve the frame-window data by calling the
- WinQueryWindowUShort function. A frame window has the following state
- flags:
-
- ╓┌─┌───────────────────────┌─────────────────────────────────────────────────╖
- Flag Description
- ──────────────────────────────────────────────────────────────────────────
- FF_ACTIVE The frame window is activated.
-
- FF_DLGDISMISSED A frame window that is a dialog window has been
- dismissed by a call to the WinDismissDlg function.
-
- FF_FLASHHILITE The frame window is flashing and its flash state
- is TRUE.
-
- FF_FLASHWINDOW The frame window flashes as the result of a call
- to the WinFlashWindow function or a WM_FLASHWINDOW
- message.
-
- FF_NOACTIVATESWP The system should do no Z ordering on this frame
- window.
-
- Flag Description
- ──────────────────────────────────────────────────────────────────────────
- FF_OWNERHIDDEN The frame window's owner window is hidden or
- minimized so the frame window is also hidden.
-
- FF_OWNERDISABLED For a frame window that is a dialog window, this
- flag indicates whether the owner window was
- enabled or disabled when the dialog window was
- loaded.
-
- FF_SELECTED The frame window has selection turned on.
-
- FI_FRAME The window is a frame window.
-
- FI_OWNERHIDE The frame window should be hidden or shown as a
- result of its owner window being hidden, shown,
- minimized, or maximized.
-
- FI_ACTIVATEOK The window can be activated.
-
- Flag Description
- ──────────────────────────────────────────────────────────────────────────
- FI_NOMOVEWITHOWNER The window should move when its owner window
- moves.
- ──────────────────────────────────────────────────────────────────────────
-
-
- 9.2.12 Frame-Window Operation
-
- The frame window maintains the size, position, and visibility of itself,
- its frame controls, and its client window. It responds to user requests to
- move, size, minimize, maximize, and redraw the window. It also responds to
- requests to close (destroy) the window and to change the focus and
- activation.
-
- When moving or sizing a frame window, all owned windows maintain their
- position relative to owner window's upper-left corner.
-
- Whenever the frame window redraws itself (for example, after moving or
- sizing), it draws the frame controls first, then lets the application draw
- the client window. This order ensures that the rapidly drawn frame
- controls are drawn before the relatively slowly drawn client window.
-
- The order in which the frame controls are drawn depends on the Z-order
- position of the controls. Because the frame controls are sibling windows,
- the Z-order position of one is relative to the others. The following list
- specifies the Z-order position of the frame controls (from top to bottom):
-
- FID_SYSMENU
- FID_TITLEBAR
- FID_MENU
- FID_VERTSCROLL
- FID_HORZSCROLL
- FID_CLIENT
-
- Although an application can change the Z-order position of any window,
- changing the relative positions of frame controls is not recommended.
-
- When a frame window receives a request to minimize the window, it locates
- an available icon space in the lower part of the screen, hides all frame
- controls and the client window, and draws its icon. If the frame window
- has no icon (that is, the window was created without the FCF_ICON style),
- the frame window hides all but the client window. The client window must
- then draw the minimized window. An application can determine the size of a
- minimized frame window by calling WinQueryWindowUShort and specifying the
- QWS_XMINIMIZE and QWS_YMINIMIZE indexes.
-
- When a frame window is maximized, it grows to the size of its parent
- window, plus an additional amount on each of its four sides equal to the
- width of its sizing border. Because a window is always clipped to its
- parent window, a maximized standard frame window does not show its sizing
- border.
-
- Frame controls owned by a frame window or windows owned by child windows
- of a frame window are automatically destroyed when the frame window
- processes the WM_DESTROY message.
-
- 9.2.13 Nonstandard Frame Windows
-
- Although most applications use frame windows to create main window and
- dialog windows, they are not limited to frame windows. Applications can
- create nonstandard frame windows and still use the standard frame
- controls, such as the title bar and System menu, within the nonstandard
- windows. One reason for creating nonstandard frame windows is to expand
- the capability of the frame window to support special features such as the
- multiple-document interface.
-
- There are two ways to create nonstandard frame windows: subclass a frame
- window or create a private frame-window class. An application that
- subclasses a frame window can intercept the messages sent to the window
- and process them in new ways. An application that creates private
- frame-window classes essentially rewrites the frame-window procedure. In
- either case, the application gains much more control over the placement of
- frame controls in the frame window by creating nonstandard frame windows.
-
- The messages WM_FORMATFRAME, WM_UPDATEFRAME, and WM_CALCVALIDRECTS control
- the arrangement of frame controls for applications that subclass. By
- intercepting these messages, an application can rearrange the placement of
- frame controls in a frame window.
-
- For applications that create private frame-window classes, the
- WinCreateFrameControls, WinCalcFrameRect, and WinFormatFrame functions
- provide much the same capability as frame windows to maintain the size and
- position of frame controls.
-
- 9.2.14 Default Frame-Window Behavior
-
- This section describes all the messages specifically handled by the
- predefined frame-window class.
-
- ╓┌─┌─────────────────────────┌───────────────────────────────────────────────╖
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_ACTIVATE Sent to a title bar or sizing border so its
- highlight state matches the frame window's
- activation state.
-
- WM_BUTTON1DOWN If the frame window is minimized, captures the
- mouse. If the window is not minimized, activates
- the window.
-
- WM_BUTTON2DOWN Activates the frame window.
-
- WM_BUTTON3DOWN Activates the frame window.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_BUTTON3DOWN Activates the frame window.
-
- WM_BUTTON1UP Processes messages from minimized window frames.
-
- WM_BUTTON2UP Not processed.
-
- WM_BUTTON3UP Not processed.
-
- WM_BUTTON1DBLCLK If the frame window is minimized, posts a
- WM_SYSCOMMAND message to itself. Otherwise,
- activates the frame window and any control
- clicked.
-
- WM_BUTTON2DBLCLK Not processed.
-
- WM_BUTTON3DBLCLK Not processed.
-
- WM_HITTEST If the frame control is minimized, returns
- HT_ERROR if the window is disabled; otherwise,
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- HT_ERROR if the window is disabled; otherwise,
- returns TF_MOVE.
-
- WM_CALCVALIDRECTS If there is no client window or the client
- window has the style CS_SIZEREDRAW, returns
- CVR_REDRAW to invalidate the entire window.
-
- WM_CLOSE If there is a client window, passes this message
- to it; otherwise, this message returns
- WinDefWindowProc.
-
- WM_CONTROLHEAP Attempts to allocate a heap for the frame
- controls. Returns a handle if successful;
- otherwise, returns NULL.
-
- WM_CREATE Creates specified frame controls by calling
- WinCreateFrameControls. Also creates any
- accelerator tables, loads icons, and adds itself
- to the switch list in Task Manager. These
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- to the switch list in Task Manager. These
- actions depend on the frame window and
- frame-control styles specified for the window.
-
- WM_DESTROY If the focus is held by a child window of the
- frame window, sets the focus to the frame
- window's parent window. Destroys any windows
- owned by the frame window. Destroys any child
- windows. Frees any control heaps. Destroys any
- icon created with the FS_ICON style. Destroys
- any accelerator table created with the
- FS_ACCELTABLE style.
-
- WM_ENABLE Returns WinDefWindowProc.
-
- WM_ERASEBACKGROUND Sent by the frame window to itself during
- WM_PAINT processing. Returns TRUE, signaling
- that the window should erase the client-window
- area.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- area.
-
- WM_FORMATFRAME Calls WinFormatFrame and WinSetMultWindowPos to
- format and position the frame controls.
-
- WM_MINMAXFRAME If there is a client window, passes a message to
- it; otherwise, passes a message via the
- WinDefWindowProc function.
-
- WM_MOUSEMOVE Determines the correct mouse pointer to use and
- returns WinDefWindowProc.
-
- WM_PAINT If the frame window is minimized, sends
- WM_QUERYICON and WM_ERASEBACKGROUND messages to
- itself and draws the icon. Otherwise, paints
- all of its controls, sends a WM_ERASEBACKGROUND
- message to the client window, and paints the
- client window.
-
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_QUERYTRACKINFO Obtains the default tracking information.
-
- WM_SHOW Returns WinDefWindowProc.
-
- WM_SIZE Sends a WM_FORMATFRAME message to itself.
-
- WM_SYSCOMMAND If the mouse is captured, ignores the system
- command. Otherwise, uses one of the following
- commands: SC_RESTORE, SC_SIZE, SC_MOVE,
- SC_CLOSE, SC_TASKMANAGER, SC_NEXT, SC_NEXTFRAME,
- SC_SYSMENU, SC_APPMENU.
-
- WM_UPDATEFRAME Calls WinFormatFrame to format the frame
- controls.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- 9.3 Using Frame Windows
-
- The following sections detail creating and using frame windows in your
- Presentation Manager applications.
-
- 9.3.1 Creating a Main Window
-
- You can create a main window by using the WinCreateStdWindow function. The
- following code fragment creates a typical main window: a frame window that
- has a System menu, title bar, menu, vertical and horizontal scroll bars,
- minimize and maximize buttons, and a sizing border:
-
- /* Create a main window. */
-
- ULONG flFrameControlFlags =
- FCF_SYSMENU | FCF_TITLEBAR | FCF_SIZEBORDER |
- FCF_MENU | FCF_MINMAX | FCF_HORZSCROLL |
- FCF_VERTSCROLL;
-
- hwndFrame = WinCreateStdWindow(
- HWND_DESKTOP, /* frame-window parent */
- 0L, /* no window styles */
- &flFrameControlFlags, /* frame-control flags */
- "MyClass", /* client-window class */
- "Main Window", /* window title */
- 0L, /* no client-window styles */
- NULL, /* app module has resources */
- 1, /* resource ID */
- &hwndClient); /* client-window handle */
-
- You can also create a "standard" main window for an application by
- creating a frame window with the FCF_STANDARD style. You create the frame
- window using the WinCreateStdWindow function. The following code fragment
- creates the window:
-
- /* Set the frame-control flags. */
-
- ULONG flFrameControlFlags = FCF_STANDARD;
-
- hwndFrame = WinCreateStdWindow (HWND_DESKTOP, ..., &hwndClient);
-
- Another way to create a main window and its frame controls is by calling
- the WinCreateWindow function to create the frame window and the frame
- controls and then calling WinCreateWindow to create the client window. One
- advantage of this approach is that you can specify an initial size and
- position of the frame window when you create it. The following code
- fragment illustrates this:
-
- FRAMECDATA fcdata;
-
- fcdata.cb = sizeof(fcdata);
- fcdata.flCreateFlags = FCF_STANDARD;
- fcdata.hmodResources = NULL;
- fcdata.idResources = idFrame;
-
- hwndFrame = WinCreateWindow(
- HWND_DESKTOP, /* frame-window parent */
- WC_FRAME, /* frame-window class */
- "Main Window", /* window title */
- 0L, /* initially invisible */
- 0, 0, 0, 0, /* size and position = 0 */
- NULL, /* no owner */
- HWND_TOP, /* top Z-order position */
- idFrame, /* frame-window ID */
- &fcdata, /* pointer to class-specific data */
- NULL); /* no presentation parameters */
-
- hwndClient = WinCreateWindow(
- hwndFrame, /* client-window parent */
- "My Class", /* client-window class */
- NULL, /* no title for client window */
- 0L, /* initially invisible */
- 0, 0, 0, 0, /* size and position = 0 */
- hwndFrame, /* owner is frame window */
- HWND_BOTTOM, /* bottom Z-order position */
- FID_CLIENT, /* standard client-window ID */
- NULL, /* no class-specific data */
- NULL); /* no presentation parameters */
-
- /* ... continue initialization ... */
-
- WinShowWindow(hwndFrame, TRUE);
-
- 9.3.2 Retrieving Frame Handles
-
- You can easily retrieve a frame-control handle by using the
- WinWindowFromID function. The following code fragment retrieves the
- control handle of the title bar:
-
- hwndTitleBar = WinWindowFromID(hwndFrame, FID_TITLEBAR);
-
- Given a frame-control handle, you can retrieve its parent frame-window
- handle by using the WinQueryWindow function:
-
- hwndFrame = WinQueryWindow(hwndTitleBar, QW_PARENT, FALSE);
-
- By using identifiers to identify frame controls rather than window
- classes, you can create your own controls to replace the predefined
- controls.
-
-
- 9.4 Summary
-
- The following sections list the messages and functions you can use to
- create and use frame windows.
-
- 9.4.1 Functions
-
- The following functions are used to create and use frame windows:
-
- WinCreateStdWindow Creates a standard frame window.
-
- WinCreateWindow Creates a standard frame window.
-
- WinCreateFrameControls Creates standard frame controls for a given
- window.
-
- WinFormatFrame Calculates the size and position of frame controls within
- a frame window. This function is typically used by applications that
- require a nonstandard frame-window layout.
-
- WinCalcFrameRect Determines the size of a frame window or its client
- window.
-
- WinGetMinPosition Obtains a frame window's minimized position.
-
- WinGetMaxPosition Obtains a frame window's maximized position.
-
- WinFlashWindow Starts or stops frame-window flashing.
-
- 9.4.2 Messages
-
- The following messages are used to create and use frame windows:
-
- WM_ERASEBACKGROUND Sent to the client window when the background needs to
- be redrawn.
-
- WM_FLASHWINDOW Sent to a frame window as a result of a call to the
- WinFlashWindow function.
-
- WM_FORMATFRAME Sent to a frame window to calculate the sizes and
- positions of its component windows.
-
- WM_MINMAXFRAME Sent to a frame window when it is about to be minimized,
- maximized, or restored.
-
- WM_NEXTMENU Sent to the owner window (the frame window) to obtain the
- next or previous menu window.
-
- WM_QUERYACCELTABLE Sent to a frame window to obtain the accelerator-table
- handle.
-
- WM_QUERYBORDERSIZE Sent to the frame window to determine the size of the
- window border.
-
- WM_QUERYFRAMECTLCOUNT Sent to the frame window to determine the maximum
- number of frame controls that can exist for a frame window.
-
- WM_QUERYFRAMEINFO Sent to determine the following things about the frame
- window: whether the window is a frame window; whether the window can be
- activated; whether the window should move as a result of its owner being
- moved; whether the window should be hidden or shown as a result of its
- owner window being hidden, shown, minimized, or maximized.
-
- WM_QUERYICON Sent to the frame window to obtain the icon handle.
-
- WM_QUERYTRACKINFO Sent to the window procedure of the owner (the frame
- window) of a title-bar control at the start of track-move processing.
-
- WM_SETACCELTABLE Sent to the frame window to set the accelerator-table
- handle.
-
- WM_SETICON Sent to the frame window to set the icon the frame-window uses
- when it is minimized.
-
- WM_TRACKFRAME Sent to the frame window to start the tracking operation
- for a frame window.
-
- WM_TRANSLATEACCEL Sent to the focus window (the frame window) to allow
- for accelerator-translation of the WM_CHAR message.
-
- WM_UPDATEFRAME Sent after frame controls have controls have been added or
- removed from the frame window to notify the frame window to update the
- appearance of the window.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 10 Control Windows
-
- 10.1 Introduction
- 10.2 About Control Windows
- 10.2.1 Control-Window Features
- 10.3 Using Control Windows in an Application
- 10.4 Creating a Custom Control Window
- 10.5 Summary
- 10.5.1 Predefined Control-Window Classes
- 10.5.2 Messages Sent to a Control Window
- 10.5.3 Messages from a Control Window to an Owner Window
-
- 10.1 Introduction
-
- This chapter describes the functions that allow you to use control windows
- in your applications. You should also be familiar with the following
- topics:
-
- ■ Standard user-interface guidelines
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Window Frames and creating standard frame windows
-
- ■ Window messages and message queues
-
-
- 10.2 About Control Windows
-
- Control windows are predefined window classes that applications use for
- input and output. Control windows are typically used as part of a dialog
- window and are defined in the dialog template. Applications can also
- create control windows by calling the WinCreateWindow function with the
- appropriate window-class specification. The following control-window
- classes are predefined in MS OS/2:
-
- ╓┌─┌─────────────┌───────────────────────────────────────────────────────────╖
- Control Description
- ──────────────────────────────────────────────────────────────────────────
- Button Buttons or boxes that the user selects by clicking or using
- the keyboard. Several button types are available, including
- push buttons, radio buttons, and check boxes.
-
- Control Description
- ──────────────────────────────────────────────────────────────────────────
- Entry field A single line of text that the user can edit.
-
- Static Text, icons, or bitmaps that do not respond to user input.
-
- List box A window containing a list of items, usually text strings,
- from which the user may scroll and make selections.
-
- Menu A list of items, either text or bitmaps. The items in a menu
- may be displayed horizontally across the top of a frame
- window, as in a menu bar, or vertically, in a menu. Menus
- typically provide the command interface for an application.
-
- Scroll bar A bar that allows a user to scroll the contents of a window.
- Scroll-bar controls contain directional arrows and an
- absolute-position indicator called the slider.
-
- Title bar A title or caption displayed across the top of a frame
- window. They can be used by a user to move the window, by
- Control Description
- ──────────────────────────────────────────────────────────────────────────
- window. They can be used by a user to move the window, by
- dragging the title-bar control.
- ──────────────────────────────────────────────────────────────────────────
-
-
- 10.2.1 Control-Window Features
-
- Control windows are always owned by other windows, usually dialog windows
- or application frame windows. The ownership relationship is important
- because a control window sends notification messages to its owner whenever
- an action occurs in the control window. A control-window position is also
- expressed in the coordinate space of its owner.
-
- Control windows are like other predefined window classes in that they
- respond to standard window management messages and functions, such as the
- WinSetWindowText and WinShowWindow functions.
-
- Control windows are usually painted synchronously. This means that a
- control window is redrawn as soon as any part of it becomes invalid.
-
- All control windows have a window ID. This ID is set either in a dialog
- template or when the control is created by the WinCreateWindow function.
- The ID is used when the control window sends notification messages to its
- owner. Care must be taken to make sure that the control ID for a
- particular window is not duplicated. Note that the control-window ID
- should not be the same as the command ID associated with individual menu
- items.
-
- All control-window classes have a set of specific messages that they send
- and receive. The summary at the end of this chapter lists the messages
- that all control windows have in common.
-
-
- 10.3 Using Control Windows in an Application
-
- Control windows can be used in dialog windows and standard-frame or client
- windows.
-
- To use a control window in a dialog window, an application defines the
- control. A dialog template typically includes several control windows as
- part of the dialog template in its resource file. Then, when the dialog
- resource is loaded and displayed, control windows are automatically
- displayed as part of the dialog window. The application can then send
- messages to the control window to change its state. The dialog-window
- procedure defined by an application receives notification messages from
- the control window. The nature of these messages depends on the specific
- type of control window.
-
- To use a control window in a non-dialog window, an application must call
- the WinCreateWindow function using the appropriate window-class
- specification. An application usually specifies one of its client windows
- as the owner of the control window. Therefore, the client-window procedure
- receives notification messages from the control window. In some cases
- where a control is owned by the frame window (such as a menu control), the
- notification messages to the frame are passed on to the client window.
-
-
- 10.4 Creating a Custom Control Window
-
- MS OS/2 provides several predefined control-window classes. You can create
- custom-control windows to fit specific purposes in an application by doing
- the following:
-
- ■ Using the user-drawn buttons, list boxes, and menus
-
- ■ Subclassing an existing control-window class
-
- ■ Registering and implementing a window class from scratch
-
- Buttons, list boxes, and menus have an optional style designation that
- marks them as "user-drawn." This means that the owner window of the
- control with this style receives a message whenever the control must be
- drawn. (If the owner window is a frame window, it sends owner-drawn
- messages to its client windows, which should be handled by the
- client-window procedure.) This allows you to alter the appearance of a
- control window. For buttons, the owner-drawn style affects the drawing of
- the entire control. For menus and list boxes, the owner draws the
- individual items within the control, and the system draws the external
- outline of the control.
-
- Subclassing an existing control window is an easy way to make custom
- controls. When you subclass an existing control window, you only alter
- those behaviors you want to change, letting all other messages through to
- the original control-window procedure.
-
- The techniques for defining a custom control window are the same as those
- used in creating a client-window class. However, if you are creating your
- own custom-control window class, be sure it can send and receive the
- messages listed in Section 10.5.
-
- If you create a custom control-window class by subclassing a control class
- or by creating a window class from scratch, you can use its class name in
- the dialog template just like a predefined window-class constant. For
- example, if you define and register a window class called "MyControlClass"
- in an application, you can define a dialog window containing a control
- window using the following resource definition:
-
- DLGTEMPLATE IDD_CUSTOM_TEST
- BEGIN
- DIALOG "", IDD_CUSTOM_TEST, 1, 1, 126, 130, FS_DLGBORDER, 0
- BEGIN
- CONTROL "This is Text", IDD_TITLE,
- 37, 107, 56, 12,
- WC_STATIC,
- SS_TEXT | DT_CENTER | DT_TOP | DT_WORDBREAK
- | WS_VISIBLE
- CONTROL "Custom Control", IDD_CUSTOM,
- 33, 68, 64, 13,
- "MyControlClass",
- WS_VISIBLE
- CONTROL "Okay", DID_OK,
- 57, 10, 24, 14,
- WC_BUTTON,
- BS_PUSHBUTTON | BS_DEFAULT | WS_TABSTOP | WS_VISIBLE
- END
- END
-
-
- 10.5 Summary
-
- The following sections describe the predefined control-window classes and
- the messages common to all control windows.
-
- 10.5.1 Predefined Control-Window Classes
-
- These the predefined control-window classes in MS OS/2:
-
- WC_BUTTON A button control, including push buttons, radio buttons, and
- check boxes.
-
- WC_ENTRYFIELD An entry-field control that allows single-line text
- editing.
-
- WC_STATIC A static control that displays text, icons, or bitmap data.
-
- WC_LISTBOX A list box that displays a list of items that can be scrolled.
-
- WC_MENU A menu, including a menu bar and menus.
-
- WC_SCROLLBAR A scroll bar that allows a user to scroll the contents of a
- window.
-
- WC_TITLEBAR The title of a window at the top of the frame that allows a
- user to reposition a window on screen.
-
- 10.5.2 Messages Sent to a Control Window
-
- All types of control windows receive the following messages:
-
- WM_ADJUSTWINDOWPOS Sent to the control window by the WinSetWindowPos
- function to allow the control to modify its position. The message contains
- a pointer to an SWP structure that specifies the new control size and
- position. The control can modify the data in the SWP structure before the
- control is actually displayed or moved. For example, the dimensions of an
- entry-field control define the limits of the area that can be edited (not
- the border). The entry-field control modifies the fields of the SWP
- structure, specifying the size and position, including the border.
- List-box controls also modify their size and position, including any
- borders, and they can adjust their height to display all list items.
-
- WM_QUERYDLGCODE Sent to the control window by the system to determine the
- kinds of messages the control processes. The control window returns a
- dialog code that is a combination of bit flags describing the messages the
- control responds to.
-
- 10.5.3 Messages from a Control Window to an Owner Window
-
- The following are messages sent from a control window to an owner window:
-
- WM_COMMAND Posted to the owner-message queue by menus and buttons. The
- owner window receives this message when the user selects a push button or
- chooses a menu item. This message also includes information about its
- source.
-
- WM_CONTROL Sent (with the WinSendMsg function) to the owner of the
- control window. This message includes the control-window ID and other
- information specific to the type of control and nature of the message.
-
- WM_CONTROLHEAP Sent by the control to its owner window when it needs a
- handle to a heap to allocate memory. For example, entry-field controls
- allocate memory to hold text associated with a control window. Generally,
- an application ignores this message, passing it on to the default window
- procedure that returns a handle to a heap.
-
- WM_CONTROLPOINTER Sent to an owner window when the mouse pointer moves
- over the control window. The owner sets the mouse pointer to a different
- shape, if desired. The control passes an HPOINTER to a mouse pointer as
- part of this message. The owner can alter the default pointer shape by
- passing a different HPOINTER back. Applications that use the default
- should pass the same HPOINTER back as the result of this message or just
- pass the message on to the WinDefWindowProc function.
-
- WM_HELP Posted by controls with the appropriate style. This message is
- like the WM_COMMAND message. The owner window receives this message and
- responds with help information, depending on the context information
- included in the message.
-
- WM_SYSCOMMAND Posted by controls with the appropriate style. This message
- is like the WM_COMMAND message. It is not passed from a frame window to a
- client window. Generally, the only control sending this message is the
- system menu in a frame window.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 11 Title-Bar Controls
-
- 11.1 Introduction
- 11.2 About Title Bars
- 11.3 Using Title-Bar Controls in Applications
- 11.3.1 Altering Dragging Action
- 11.4 Default Title-Bar Behavior
- 11.5 Summary
-
- 11.1 Introduction
-
- This chapter describes creating and using title-bar control windows. The
- title-bar control window is part of a standard frame window. You should
- also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Standard frame windows
-
- ■ Window messages and message queues
-
-
- 11.2 About Title Bars
-
- A standard frame window is made up of several overlapping control windows
- that give the window its distinctive look and behavior. This chapter
- discusses one of these control windows: the title bar. Menus and scroll
- bars, the other control-window types that can be part of a frame window,
- are discussed in other chapters in this manual. Figure 11.1 shows a
- standard frame window with its title bar:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 11.1 can be found in Section 11.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 11.1 Frame Window with Title Bar
-
- The title bar in a standard frame window performs four functions. First,
- it displays the title of the window across the top of the frame. Second,
- it changes its highlight appearance to show whether the frame window is
- active or not. Normally, the topmost window in a screen display is the
- active window. Third, the title bar responds to the user──for example,
- when the user drags the frame window to a new location on the screen.
- Finally, the title bar flashes (as a result of the WinFlashWindow
- function).
-
- Title-bar control windows, like all control windows, must be owned by
- another window. Title-bar controls are owned by the frame window. A
- title-bar control sends messages to its owner when the control receives
- user input.
-
-
- 11.3 Using Title-Bar Controls in Applications
-
- Typically, you need not be too concerned with the title-bar control. The
- default behavior of the title-bar control follows the standard
- user-interface guidelines. Most applications allow the title-bar control
- to operate according to these guidelines.
-
- To include a title-bar control in a standard frame window, the application
- must compare (by using the OR operator) constants representing each
- control type and pass the resulting value to the WinCreateStdWindow
- function. The following code fragment shows the creation of a standard
- frame window with a title bar, a minimum/maximum control, a size border, a
- System menu, and an application menu. (The System menu and application
- menu are considered frame controls. For more information about frame
- controls, see Chapter 9, "Frame Windows.")
-
- ULONG lControlStyle = FCF_TITLEBAR | FCF_SIZEBORDER | FCF_MINMAX |
- FCF_SYSMENU | FCF_MENU;
-
- hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
- WS_VISIBLE | FS_ACCELTABLE,
- &lControlStyle,
- szClassName,
- szClassName,
- 0L, NULL,
- ID_MENU_RESOURCE,
- &hwndClient);
-
- Once the frame controls are in place in the frame window, most
- applications can ignore them. The system handles the frame controls. In
- some cases, the application may take control of the title bar by sending
- messages to the title-bar control window.
-
- To get the window handle of a title-bar control in a frame window, the
- application calls the WinWindowFromID function with the frame-window
- handle and a constant identifying the title-bar control, as shown in the
- following code:
-
- hwndTitleBar = WinWindowFromID(hwndFrame, FID_TITLEBAR);
-
- To change the text of a title bar, the application sets the window text of
- the frame window by calling the WinSetWindowText function. The frame
- window passes the message to the title bar. This changes the title-bar
- text.
-
- 11.3.1 Altering Dragging Action
-
- When the user clicks in the title-bar control, the title bar sends its
- owner (the frame window) a WM_TRACKFRAME message. The frame window also
- sends a WM_QUERYTRACKINFO message to itself to fill in a TRACKINFO
- structure that defines the tracking parameters and boundaries. To modify
- the default behavior, you must subclass the frame window and intercept the
- message WM_QUERYTRACKINFO and modify the TRACKINFO structure. If you
- return TRUE for the WM_QUERYTRACKINFO message, the tracking information
- proceeds according to the information in the TRACKINFO structure. If you
- return FALSE, no tracking occurs.
-
-
- 11.4 Default Title-Bar Behavior
-
- This section describes all the messages specifically handled by the
- predefined title-bar control class.
-
- ╓┌─┌──────────────────────────┌──────────────────────────────────────────────╖
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_CREATE Sets the window text for the control. Returns
- FALSE if creation succeeds.
-
- WM_DESTROY Frees the window text for the control.
-
- WM_QUERYWINDOWPARAMS Returns the requested window parameters.
-
- WM_SETWINDOWPARAMS Sets the specified window parameters.
-
- WM_PAINT Draws the title bar.
-
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_HITTEST Always returns HT_NORMAL, so the title bar does
- not beep when it is disabled (it is disabled
- when the frame window is maximized).
-
- WM_BUTTON1DOWN Sends the WM_TRACKFRAME message to the owner
- (typically a frame window) to start tracking.
-
- WM_BUTTON1DBLCLK Restores the window if the owner window is
- minimized or maximized. If the window is
- neither, maximizes the window.
-
- WM_ADJUSTWINDOWPOS Returns FALSE. Process this message to prevent
- the WinDefWindowProc function from sending the
- size and show messages.
-
- WM_QUERYDLGCODE Returns the predefined constant DLGC_STATIC. A
- user cannot use the TAB key to move to this
- window in a dialog box.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- window in a dialog box.
-
- TBM_QUERYHILITE Returns the highlight state of the title bar.
-
- TBM_SETHILITE Sets the highlight state of the title bar,
- repainting it if the state is changing.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- 11.5 Summary
-
- The following messages are associated with frame-control windows:
-
- TBM_SETHILITE Sets the highlight state of the title bar to TRUE or FALSE.
- The system usually sends this message to a title bar to show whether or
- not the frame window containing the title bar is active.
-
- TBM_QUERYHILITE Returns the highlight state (TRUE or FALSE) for a
- title-bar control window.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 12 Button Controls
-
- 12.1 Introduction
- 12.2 About Button Controls
- 12.3 Using Button Controls in an Application
- 12.3.1 Buttons in a Dialog Window
- 12.3.2 Buttons in a Client Window
- 12.3.3 Responding to a Button-Notification Message
- 12.3.4 Changing the Button State
- 12.3.5 Owner-Drawn Buttons
- 12.4 Default Button Behavior
- 12.5 Summary
- 12.5.1 Button Styles
- 12.5.2 Messages Sent to Button Controls
- 12.5.3 Messages Sent from Buttons to Owner Windows
-
- 12.1 Introduction
-
- This chapter describes how to use button-control windows in your
- applications. You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Window messages and message queues
-
-
- 12.2 About Button Controls
-
- A button control is a window that represents a button that a user can
- select using the mouse or keyboard. Buttons can appear by themselves or in
- groups, and can appear with or without label text. A user can select a
- button by clicking it with the mouse or pressing the ENTER key when the
- button window has the keyboard focus. Buttons typically change appearance
- when selected.
-
- There are four main types of buttons: push buttons, radio buttons, check
- boxes, and three-state check boxes. The appearance and behavior of button
- controls is determined by the style of the button. Figure 12.1 shows the
- different types of button controls.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 12.1 can be found in Section 12.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 12.1 Button Types
-
- Radio buttons, check boxes, and three-state check boxes are used to
- control attributes of an operation. Push buttons are used to initiate
- operations. For example, a user might indicate paper size, print quality,
- and printer type in a print-command dialog window containing an array of
- radio buttons and check boxes. Once the user sets each option, a push
- button can be used to tell an application that printing should begin (or
- be canceled). The application queries the state of each radio button and
- check box to determine the printing parameters.
-
- Push buttons are rounded-corner rectangular windows containing text
- strings. Push buttons become highlighted when they are selected by a user.
- They return to an unhighlighted state when the user releases the mouse
- button or the SPACEBAR. Push buttons are typically used to start or stop
- operations. A push button posts a WM_COMMAND message to its owner window.
-
- Radio buttons are windows with text displayed to the right of a small,
- circular indicator. A radio button toggles between selected and
- unselected, each time the user selects it. The button retains the state
- until the next selection. Radio buttons usually appear in groups with only
- one button selected at a time. Radio buttons are appropriate where an
- exclusive choice is required from a group of related options. A radio
- button sends a WM_CONTROL message to its owner window.
-
- Check boxes are similar to radio buttons except that they are used by
- themselves instead of in groups. They also toggle on or off application
- features. A check box sends a WM_CONTROL message to its owner window.
-
- Three-state check boxes are similar to check boxes except that they can be
- displayed in halftone as well as selected or unselected. A three-state
- check box sends a WM_CONTROL message to its owner window.
-
- In addition to the four predefined button-control types, an application
- can create buttons that appear defined by the owner window. Buttons using
- this style send BN_PAINT messages to their owner windows when they must be
- drawn or highlighted.
-
- Button-control windows are always owned by other windows, typically by an
- application client window or a dialog window. A button control posts
- WM_COMMAND messages or sends WM_CONTROL notification messages to its owner
- when a user selects the button. Owner windows can also send messages to
- button controls to query or set states.
-
-
- 12.3 Using Button Controls in an Application
-
- The most common way to use button controls is in a dialog window. An
- application defines one or more button controls in the dialog template in
- the resource file, and processes button messages in the dialog-window
- procedure.
-
- Buttons can be associated in groups in dialog windows. A user can move
- from one button in a group to another button in the same group by pressing
- the direction keys. The TAB key moves from one group to the next. Groups
- are established by setting the WS_GROUP style bit for the first member of
- each group in the dialog template.
-
- You can also use button controls in standard client windows. For these
- windows, create a button-control window by calling the WinCreateWindow
- function with a window class of WC_BUTTON. Specify the client window as
- the owner of the button window. The owner window receives messages from
- buttons and can send messages to the buttons to alter their control state.
- The control state includes highlighting control text, button position, and
- the enabled/disabled state.
-
- Applications can create custom buttons that appear to be controlled by the
- application. The BS_USERBUTTON style, used in conjunction with other
- button styles, creates a button that notifies the application whenever the
- button must be drawn, allowing the application to draw the button.
-
- 12.3.1 Buttons in a Dialog Window
-
- Buttons are typically used in dialog windows. An application can define
- buttons as part of a dialog-template resource file, as shown in the
- following sample Resource Compiler source-code fragment:
-
- DLGTEMPLATE IDD_BUTTON
- BEGIN
- DIALOG "", 2, 64, 9, 235, 130
- BEGIN
- AUTORADIOBUTTON "R~adio1", ID_RADIO1, 15, 20, 40, 12, WS_GROUP
- AUTORADIOBUTTON "Ra~dio2", ID_RADIO2, 15, 40, 40, 12
- AUTORADIOBUTTON "Rad~io3", ID_RADIO3, 15, 60, 40, 12
- AUTORADIOBUTTON "R~adio4", ID_RADIO4,15, 80, 40, 12
-
- PUSHBUTTON "Button 1", ID_PUSH1, 100, 50, 14, WS_GROUP
- PUSHBUTTON "Button 2", ID_PUSH2, 75, 100, 50, 14, WS_GROUP
- PUSHBUTTON "Button 3", ID_PUSH3, 130, 100, 60, 14, WS_GROUP
-
- CHECKBOX "Check Box 1", ID_CHECK1, 150, 20, 58, 12, WS_GROUP
- CHECKBOX "no toggle", ID_CHECK2, 150, 40, 58, 12
-
- AUTOCHECKBOX "Check Box 3", ID_CHECK3, 150, 60, 58, 12, WS_GROUP
- DEFPUSHBUTTON "OK", DID_OK, 75, 26, 46, 20, WS_GROUP
- END
- END
-
- Each button item in a dialog window has an ID (for example, ID_RADIO1)
- that allows an application to identify the source of the WM_COMMAND and
- WM_CONTROL messages. The ID is also used to retrieve the button-window
- handle using the WinWindowFromID function.
-
- The dialog template also specifies the text for each button, which is
- displayed in a rectangular box. If the button text is too long to fit in
- the button, it is clipped to the rectangle. For radio buttons and check
- boxes, text is displayed to the right of the button. A user selects the
- button by clicking either the button or the text itself.
-
- The WS_GROUP attribute identifies the beginning of each new group of
- buttons. In the example above, the first four auto-radio buttons are in
- the same group, the following push buttons are in their own group, and the
- following two check boxes are in their own group. The auto-radio buttons
- in the first group can only be selected one at a time. An application must
- see that only one check box in a group is selected at a time. The group
- can wrap around from the end of the item list to the beginning.
-
- Notice the DEFPUSHBUTTON style with the DID_OK identification number in
- the code fragment above. It is customary to include an OK button with this
- ID in most dialog windows to provide a uniform user interface. The
- DEFPUSHBUTTON style draws a thick border around a button and allows a user
- to select the button by pressing the ENTER key.
-
- The dialog-window procedure for a dialog window containing buttons must
- respond to WM_COMMAND and WM_CONTROL messages. A common strategy is to use
- auto-radio buttons and auto-check boxes to allow a user to set a list of
- attributes for a command, and execute it by choosing the OK button. In
- this case, the dialog-window procedure ignores all WM_CONTROL messages
- that come from auto-radio buttons and auto-check boxes. These controls
- select and deselect themselves. When the dialog-window procedure receives
- a WM_COMMAND message for the OK button, it should query the auto-radio
- buttons and auto-check boxes to determine which options have been selected
- before proceeding with the operation.
-
- 12.3.2 Buttons in a Client Window
-
- Applications can also use buttons in non-dialog windows. An application
- can create a button window using an application client window as the
- owner, as shown in the following code fragment:
-
- /* Create a button window. */
-
- hwndButton = WinCreateWindow(hwndClient, /* parent */
- WC_BUTTON, /* class */
- "Test Button", /* text */
- WS_VISIBLE | BS_PUSHBUTTON, /* style */
- 10, 10, /* x, y */
- 60, 70, /* cx, cy */
- hwndClient, /* owner */
- HWND_TOP, /* behind */
- ID_PBWINDOW, /* ID */
- NULL, /* control data */
- NULL); /* parameters */
-
- Once created in the client window, the button posts a WM_COMMAND message,
- or sends a WM_CONTROL message to the client-window procedure. The window
- procedure should examine the message ID to determine the button that sent
- the message.
-
- Applications that have client-window buttons may move and size the buttons
- when the window receives a WM_SIZE message. This message indicates that
- the window is changing size. Buttons can be moved and sized using the
- WinSetWindowPos function. You can obtain a window handle for a button by
- calling the WinWindowFromID function using the parent window and the
- window ID for each button.
-
- 12.3.3 Responding to a Button-Notification Message
-
- A button control sends a message to its owner window when a user selects
- the button, by either using the mouse or the keyboard. Buttons created
- with the BS_PUSHBUTTON or BS_USERBUTTON styles generate a WM_COMMAND
- message each time they are selected (this can be altered by specifying the
- BS_HELP or BS_SYSCOMMAND style when the button is created). All other
- button styles generate WM_CONTROL messages when selected.
-
- A push button is automatically highlighted when a user selects it using
- the mouse. The button tracks the mouse until the user releases the mouse
- button. The highlight is turned off if the mouse moves outside the button
- boundaries. The push button does not generate any messages to its owner
- window until the user releases the mouse button, and then only if the
- mouse button is released inside the push-button boundary. When the owner
- window receives a WM_COMMAND message from a push button, the low word of
- the first parameter in the message contains the button window ID, as
- specified in the dialog template or when the button was created.
-
- You should avoid duplicating IDs in menu commands and buttons because they
- both send IDs to owner windows as WM_COMMAND messages. However,
- it is possible to tell whether a WM_COMMAND message came from a menu
- or a push button by looking for the value CMDSRC_PUSHBUTTON or CMDSRC_MENU
- in the low word of the second parameter of the message.
-
- Button types other than push buttons generate WM_CONTROL messages when
- selected. Applications can examine the low word of the first parameter in
- the message to find the button ID and the high word of the first parameter
- to determine the notification code for the control message. The
- notification code tells the application whether the control message
- originated from the user clicking or double clicking, or if the button
- needs to be drawn.
-
- When a check box or radio button is selected, it sends a WM_CONTROL
- message with a notification BN_CLICKED code to the owner window. The owner
- window responds by sending a message back to the button to toggle its
- state.
-
- In the case of auto-check boxes and auto-radio buttons, an application
- need not respond because these buttons toggle themselves in response to
- the mouse. The application still receives WM_CONTROL messages each time
- the button is selected. Most applications that use this default for radio
- buttons and check boxes should also use the automatic versions of these
- buttons and ignore any WM_COMMAND messages.
-
- 12.3.4 Changing the Button State
-
- An application can query and set the highlight and checked state of its
- buttons by sending messages to button windows. The window handle for a
- button can be obtained by calling the fbWinWindowFromID function using the
- parent window and the window ID of the button. In the case of a dialog
- window, the parent would be the dialog window and the ID would be the
- button item ID from the dialog template.
-
- Button-window text is stored as window text, and is accessible by using
- the WinSetWindowText and WinQueryWindowText functions. The size, position,
- and visibility of a button are set using standard window functions.
-
- 12.3.5 Owner-Drawn Buttons
-
- An application can create custom buttons by using the BS_USERBUTTON
- style in combination with other styles. For example, an application can
- create a custom auto-radio button that works like an auto-radio button but
- whose appearance is controlled by the application. The owner window
- receives WM_CONTROL messages for these buttons whenever they must be
- drawn, highlighted, or disabled.
-
- When a button must be drawn, the owner window receives a WM_CONTROL
- message with the low word of the first parameter equal to BN_PAINT. The
- second parameter is a pointer to a USERBUTTON structure that contains
- necessary information the application needs to draw the button. The
- USERBUTTON structure is shown below.
-
- typedef struct _USERBUTTON {
- HWND hwnd;
- HPS hps;
- USHORT fsState;
- USHORT fsStateOld;
- } USERBUTTON;
-
- An application uses the hwnd field in this structure to find the bounding
- rectangle for the button. The hps field is used as a presentation space
- for any drawing. The high byte of the fsState field contains flags that
- tell an application how to draw the button: highlighted, unhighlighted, or
- disabled. The high byte of the fsStateOld field contains flags describing
- the current highlighted, unhighlighted, or disabled state of the button.
-
-
- 12.4 Default Button Behavior
-
- This section describes the messages specifically handled by the predefined
- button-control window class.
-
- ╓┌─┌──────────────────────────┌──────────────────────────────────────────────╖
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_CREATE Validates the requested button style and sets
- the window text.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- the window text.
-
- WM_DESTROY Frees the memory containing the window text.
-
- WM_PAINT Draws the button according to its style and
- current state.
-
- WM_SETFOCUS Creates a cursor if receiving the focus,
- destroys the cursor if losing the focus.
-
- WM_BUTTON1DOWN Sets mouse capture for the button window.
-
- WM_MOUSEMOVE Sets the default mouse pointer. If the button
- has the mouse capture, the button highlight
- state changes as the mouse pointer moves in and
- out of button area.
-
- WM_BUTTON1UP If the button has mouse capture, releases the
- mouse capture and sends notification message to
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- mouse capture and sends notification message to
- the owner window if the mouse pointer is inside
- the button when the mouse button is released.
- If the button is a BS_PUSHBUTTON, a WM_COMMAND
- message is posted, otherwise a WM_CONTROL
- message with the BN_CLICKED code is sent.
-
- WM_BUTTON1DBLCLK Marks the button, sending a BN_DBLCLICKED
- notification code when the button-up message
- arrives.
-
- WM_CHAR Sets mouse capture when the SPACEBAR is
- pressed, releases capture when the SPACEBAR is
- released. Passes other key messages to the
- default window procedure.
-
- WM_QUERYDLGCODE Returns DLGC_BUTTON combined using the OR
- operator with the appropriate bits to designate
- the particular button type.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- the particular button type.
-
- WM_QUERYWINDOWPARAMS Returns the requested window parameters.
-
- WM_SETWINDOWPARAMS Sets the requested window parameters and
- redraws the button, including the cursor, if
- the window has the focus.
-
- WM_ENABLE Draws the button.
-
- WM_MATCHMNEMONIC Returns TRUE if mp1 matches a button mnemonic.
-
- BM_QUERYCHECKINDEX Returns the zero-based index to the selected
- item in the same group as the button. Returns
- -1 if no button in the group is selected or if
- the button receiving the message is not a radio
- button or auto-radio button.
-
- BM_CLICK Sends a WM_BUTTON1DOWN and WM_BUTTON1UP message
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- BM_CLICK Sends a WM_BUTTON1DOWN and WM_BUTTON1UP message
- to itself to simulate a user-button selection.
-
- BM_QUERYCHECK Returns the checked state of the button.
-
- BM_SETCHECK Sets the checked state of the button, returns
- the previous checked state.
-
- BM_QUERYHILITE Returns the highlight state of the button.
-
- BM_SETHILITE Sets the highlight state of the button, returns
- the previous highlight state.
-
- BM_SETDEFAULT Sets the default button state, redraws the
- button.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- 12.5 Summary
-
- The following section lists the available styles for buttons and the
- messages associated with button controls.
-
- 12.5.1 Button Styles
-
- The following are available button styles:
-
- BS_3STATE Similar to a check box, except that it toggles between
- selected, unselected, and halftone states. The owner window receives a
- WM_CONTOL message and changes the state of the three-state check box when
- it is selected.
-
- BS_AUTO3STATE Similar to a three-state check box, except it changes its
- state when selected.
-
- BS_AUTOCHECKBOX Similar to a check box, except that it automatically
- changes its state when selected. An auto-check box sends a WM_CONTROL
- message to its owner window.
-
- BS_AUTORADIOBUTTON Similar to a radio button, except that it
- automatically responds to a selection by changing its state and the state
- of all other radio buttons in its group.
-
- BS_CHECKBOX A check box is a small square window that is empty when it is
- unselected, and contains an "x" when selected. Check-box text is dis-
- played to the right of the check box. The owner window is notified with a
- WM_CONTROL message when the check box is selected and is responsible for
- changing the check-box state.
-
- BS_DEFAULT A button with this style is outlined with a heavy black
- border. A user can select this button by pressing the ENTER key. This is
- useful for allowing a user to quickly select the most likely option, the
- default option, by pressing the ENTER key.
-
- BS_HELP A button with this style posts a WM_HELP message when selected.
-
- BS_NOBORDER A button with this style is drawn without a border.
-
- BS_NOPOINTERFOCUS A button with this style does not receive the focus
- when selected.
-
- BS_PUSHBUTTON A push button. The button posts a WM_COMMAND message to the
- owner window when selected.
-
- BS_RADIOBUTTON Similar to a check box, except that it is used in
- groups of mutually exclusive choices. The owner window is notified with a
- WM_CONTROL message when a radio button is selected, and changes the
- state of the selected radio button and all other buttons in the group.
-
- BS_SYSCOMMAND A button with this style posts a WM_SYSCOMMAND message when
- selected.
-
- BS_USERBUTTON An application-defined button. This style, used in
- conjunction with other styles, allows the owner window to draw the button
- control in a highlighted, unhighlighted, enabled, or disabled state. The
- owner window receives a BN_PAINT message when the button must be drawn.
-
- 12.5.2 Messages Sent to Button Controls
-
- The following messages are sent to button controls:
-
- BM_CLICK The button responds as if it were selected using the mouse or
- the keyboard. This is useful when simulating a user selection for a
- particular button.
-
- BM_QUERYCHECK Sent to a check box and radio button. Returns 0 if the
- button is unselected, 1 if the button state is selected, and 2 if the
- button state is indeterminate (for example, the grayed state for
- three-state buttons).
-
- BM_QUERYCHECKINDEX The button responds to this message by setting the
- result to the zero-based index of the selected radio button in the same
- group as the sender. Returns -1 if no button in the group is selected or
- the receiver is not a radio button, or if the radio button has no parent
- window.
-
- BM_QUERYHILITE For push buttons, returns TRUE if the button is currently
- highlighted, FALSE otherwise. Returns FALSE if the button receiving the
- message is not a push button.
-
- BM_SETCHECK Sets the state to unselected, selected, or indeterminate (for
- three-state buttons) for check boxes and radio buttons. If the button
- receiving the message also has the style BS_USERBUTTON, a WM_CONTROL
- message is sent to the button owner telling it to select or unselect the
- button.
-
- BM_SETDEFAULT Sets or removes the BS_DEFAULT style bit in the receiving
- button.
-
- BM_SETHILITE Sent to a push button. Sets the state of the button to
- highlighted or unhighlighted, depending on the parameters supplied with
- the message. If the button receiving the message has the BS_USERBUTTON
- style, a WM_CONTROL message is sent to the button owner telling it to
- highlight or unhighlight the button.
-
- 12.5.3 Messages Sent from Buttons to Owner Windows
-
- The following messages are sent from buttons to their owner windows:
-
- WM_COMMAND Posted from a push button to its owner window when a user
- selects the button. Additional parameters in the message indicate whether
- the selection was done using the mouse or the keyboard, although
- applications generally do not track how the button was selected.
-
- WM_CONTROL Sent from a button control to its owner to indicate that a
- user has selected the button or when the owner must draw the button.
- Included in the message is one of the following notification codes:
-
- Code Description
- ──────────────────────────────────────────────────────────────────────────
- BN_CLICKED A user selected the button.
-
- BN_DBLCLICKED A user double-clicked the button.
-
- BN_PAINT Sent from a BS_USERBUTTON button to the owner window
- instructing it to draw the button control. The
- WM_CONTROL message contains a pointer to a USERBUTTON
- structure.
- ──────────────────────────────────────────────────────────────────────────
-
- WM_HELP Posted instead of the WM_COMMAND message from a push button to
- its owner window when the button has the BS_HELP style.
-
- WM_SYSCOMMAND Posted instead of the WM_COMMAND message from a push button
- to its owner window when the button has the style BS_SYSCOMMAND.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 13 Entry-Field Controls
-
- 13.1 Introduction
- 13.2 About Entry-Field Controls
- 13.3 Using Entry-Field Controls in an Application
- 13.3.1 Entry-Field Controls in a Dialog Window
- 13.3.2 Entry-Field Controls in a Client Window
- 13.3.3 Responding to a Message from an Entry-Field Control
- 13.3.4 Changing the State of an Entry-Field Control
- 13.3.5 Communicating with the System Clipboard
- 13.4 Default Entry-Field Behavior
- 13.5 Summary
- 13.5.1 Entry-Field Control Styles
- 13.5.2 Messages Sent to Entry-Field Controls
- 13.5.3 Messages Sent from an Entry-Field to an Owner Window
-
- 13.1 Introduction
-
- This chapter describes the functions that allow you to use entry-field
- control windows in your applications. You should also be familiar with the
- following topics:
-
- ■ Standard user-interface guidelines
-
- ■ System clipboard
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Basic concepts of window messages and the message queue
-
-
- 13.2 About Entry-Field Controls
-
- An entry-field control is a rectangular window that displays a single line
- of text a user can edit. When the entry-field control has the focus, it
- displays a flashing bar to mark the current insertion point. It also
- allows a user to select text by dragging the mouse or by using the
- keyboard. Entry-field controls allow applications to provide
- standard-interface text editing to users for short selections.
-
- Users can select a range of text in an entry-field control. Many
- text-editing operations on the contents of an entry-field control affect
- the current selection rather than the entire text.
-
- Entry-field controls are typically used in dialog windows, although they
- may be used in non-dialog windows as well. Entry-field control windows are
- always owned by other windows. The entry-field control window sends
- notification messages to its owner when it gains or loses the focus, or
- when its contents change or are scrolled.
-
- Entry-field control windows have style bits that determine whether the
- text is left, center, or right-justified in the window, and whether the
- text automatically scrolls horizontally, showing the current insertion
- point. Style bits also control whether entry-fields have borders. These
- styles are set when the control is created.
-
-
- 13.3 Using Entry-Field Controls in an Application
-
- Entry-field controls can be used in dialog windows and regular client
- windows. As part of a dialog window, the entry-field control is defined as
- part of the dialog template in the application resource file. In a client
- window, the application creates a window with the window class
- WC_ENTRYFIELD.
-
- Once created, the contents, font, and selection range of the entry-field
- control can be changed by sending appropriate messages to the entry-field
- control window. Entry-field controls hold up to 32 characters by default,
- but applications can expand or reduce this limit, depending on memory
- limits, once the control is created. Applications can query the current
- contents or the current selection in an entry-field control.
-
- Applications can also transfer text and data between the entry-field
- control and the system clipboard by using cut, copy, clear, and paste
- operations. This facility is useful for moving text from an entry-field
- control to another window or process.
-
- 13.3.1 Entry-Field Controls in a Dialog Window
-
- Entry-field controls are typically used in dialog windows. The dialog
- window serves as the parent and owner window for the entry-field control.
- The application dialog procedure receives notification messages from
- entry-field controls. Generally, a dialog window includes a button that
- signals that the user wants to carry out an operation. The application
- ignores most notification messages from an entry-field control, allowing
- default text editing to occur. When the user selects the button that
- indicates an operation should begin, the application queries the contents
- of the entry-field control and proceeds with the operation.
-
- To include an entry-field control in a dialog window, include a definition
- for an entry-field control item in the dialog-template definition in the
- resource file. The definition sets up the initial text, window ID, size,
- position, and style of the entry-field control. A sample dialog template
- containing an entry-field control is shown below.
-
- DLGTEMPLATE IDD_SAMPLE
- {
- DIALOG "Sample Dialog", 50, 7, 7, 253, 145, FS_DLGBORDER,0
- {
- DEFPUSHBUTTON "~Ok", DID_OK, 8, 151, 50, 23, WS_GROUP
- ENTRYFIELD "Here is some text", ID_ED1, 42, 46, 68, 15,
- ES_MARGIN | ES_AUTOSCROLL
- }
- }
-
- Once created as part of a dialog window, the entry-field control sends
- notification messages to the dialog window. An application handles these
- messages in its dialog-window procedure.
-
- An application communicates with an entry-field control in a dialog window
- by sending messages to the entry-field control window. The handle of the
- entry-field control window is obtained by calling the WinWindowFromID
- function (using the dialog window as the parent window and the window ID
- for the entry-field control as defined in the dialog template).
-
- 13.3.2 Entry-Field Controls in a Client Window
-
- To have an entry-field control in a non-dialog window, an application
- calls the WinCreateWindow function with the window class WC_ENTRYFIELD. An
- application client window owns the entry-field control. The client-window
- procedure receives notification messages from the entry-field control. The
- following code fragment shows how to create an entry-field control window
- in a client window:
-
- hwndEntryField = WinCreateWindow(hwndClient, /* parent */
- WC_ENTRYFIELD, /* class */
- "initial text contents", /* text */
- WS_VISIBLE | ES_AUTOSCROLL | ES_MARGIN, /* style */
- xPos, yPos, /* x, y */
- xSize, ySize, /* cx, cy */
- hwndClient, /* owner */
- HWND_TOP, /* behind */
- hwndEntryField, /* win ID */
- (PVOID) NULL, /* ctl data */
- (PVOID) NULL); /* reserved */
-
- The entry-field control created in the preceding example has a
- 32-character default limit. An application can change this limit by
- sending an EM_SETTEXTLIMIT message to the control window. The limit can be
- set to a non-default value at creation by supplying a pointer to an
- ENTRYFDATA structure as the ctldata parameter to the WinCreateWindow
- function.
-
- The other fields of the ENTRYFDATA structure can be set to specify the
- selection length and the first visible character at the left edge of the
- control window. Entry-field control attributes can also be changed by
- sending messages to the control after it is created. It is not necessary
- to provide this information in the ENTRYFDATA structure for creation to
- occur.
-
- 13.3.3 Responding to a Message from an Entry-Field Control
-
- An entry-field control communicates with its owner by sending WM_CONTROL
- messages. These messages contain notification codes that specify the exact
- nature of the message. Typically, an application does not respond to
- notification messages from an entry-field control for default
- text-editing. For more specialized uses, an application uses notification
- messages to perform input filtering.
-
- For example, if an application has an entry-field control that is intended
- for entering a number, it can use the EN_CHANGED message to check the
- contents after each new character is entered. This tells a user that an
- inappropriate character has been entered.
-
- On a deeper level, an application can use the EN_SETFOCUS and EN_KILLFOCUS
- messages to toggle the input filtering that occurs before the character
- messages are sent to the entry-field control. An application can use
- conditional code in its main-event loop to filter incoming WM_CHAR
- messages whenever the entry-field control has the focus. By intercepting
- WM_CHAR messages before they are dispatched using the WinDispatchMsg
- function, an application can prevent inappropriate characters from
- reaching the entry-field control. You might also want to apply special
- interpretation to certain keystrokes, such as the ENTER key, as long as
- the entry-field control has the focus.
-
- 13.3.4 Changing the State of an Entry-Field Control
-
- You can set or retrieve text in an entry-field control window by calling
- the WinSetWindowText or WinQueryWindowText function. To retrieve the text
- for the current selection, an application first calls the
- WinQueryWindowText function to retrieve the contents, and then sends an
- EM_QUERYSEL message to retrieve the offsets to the first and last
- character of the text selection. These offsets are used to retrieve
- selected text from the entire text.
-
- Edit fields containing numerical values can be set or queried by calling
- the WinSetDlgItemShort or WinQueryDlgItemShort function and passing the
- entry-field ID and the parent window. The WinSetDlgItemShort function
- converts a signed or unsigned integer into a text string and sets the
- field text with it. The WinQueryDlgItemShort function converts the
- entry-field text to a signed or unsigned integer and returns the value in
- a specified variable.
-
- An application can set or query the selection range, although the
- entry-field control automatically handles selection changes in response to
- user input in keeping with the standard user-interface guidelines.
- However, it can be useful to have an application select the entire text
- prior to cutting or pasting to the system clipboard.
-
- 13.3.5 Communicating with the System Clipboard
-
- Entry-field controls respond to messages designed to simplify transferring
- data to and from the system clipboard. These messages support the standard
- cut, copy, clear, and paste operations defined by the standard
- user-interface guidelines. All clipboard messages for entry-field controls
- use the CF_TEXT clipboard-data format. See the summary section at the end
- of this chapter for a description of each message.
-
-
- 13.4 Default Entry-Field Behavior
-
- This section describes all the messages specifically handled by the
- predefined entry-field control-window class.
-
- ╓┌─┌──────────────────────────┌──────────────────────────────────────────────╖
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_CREATE Validate the requested style and set the window
- text.
-
- WM_DESTROY Free the memory used for the window text.
-
- WM_BUTTON1DOWN Set the mouse capture and keyboard focus to the
- entry-field and prepare to track the mouse
- during WM_MOUSEMOVE messages.
-
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_BUTTON1DBLCLK Set the mouse capture and keyboard focus to the
- entry-field and prepare to track the mouse
- during WM_MOUSEMOVE messages.
-
- WM_BUTTON1UP Release the mouse capture.
-
- WM_BUTTON2DOWN Return TRUE to prevent this message from being
- processed further.
-
- WM_BUTTON3DOWN Return TRUE to prevent this message from being
- processed further.
-
- WM_PAINT Draw the entry-field control and text.
-
- WM_CHAR Handle key events according to the standard
- user-interface guidelines.
-
- WM_SETSELECTION Invert the current selection range.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_SETSELECTION Invert the current selection range.
-
- WM_SETFOCUS If gaining the focus, create a cursor and send
- to the owner window a WM_CONTROL message with
- the EN_SETFOCUS control code. If losing the
- focus, destroy the current cursor and send to
- the owner window a WM_CONTROL message with the
- control code EN_KILLFOCUS.
-
- WM_QUERYDLGCODE Return the predefined constant DLGC_ENTRYFIELD.
-
- WM_QUERYWINDOWPARAMS Return the requested window parameters.
-
- WM_SETWINDOWPARAMS Set the specified window parameters, redraw the
- control, and send to the owner window a
- WM_CONTROL message with the EN_CHANGED control
- code.
-
- WM_MOUSEMOVE If the mouse button is down, track the text
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_MOUSEMOVE If the mouse button is down, track the text
- selection. If the mouse button is up, set the
- mouse pointer to the default arrow shape.
-
- WM_ENABLE Invalidate the entire entry-field control
- window, causing a WM_PAINT message to be sent
- to the control.
-
- WM_TIMER Blink the insertion point if the control has
- the focus. Scroll the text, if necessary, while
- extending a selection to text not visible in
- the window.
-
- WM_ADJUSTWINDOWPOS Change the rectangle for the control size to
- adjust for the margin if the control has the
- ES_MARGIN style.
-
- EM_QUERYFIRSTCHAR Return the offset to the first character
- visible at the left edge of the control window.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- visible at the left edge of the control window.
-
- EM_SETFIRSTCHAR Scrolls the text so that the character at the
- specified offset is the first character visible
- at the left edge of the control window. Returns
- TRUE if successful, or FALSE if it is not.
-
- EM_QUERYCHANGED Returns TRUE if the text has changed since the
- last EM_QUERYCHANGED message.
-
- EM_QUERYSEL Returns a long word that contains the offsets
- for the first and last characters of the
- current selection in the control window.
-
- EM_SETSEL Sets the current selection to the specified
- character offsets.
-
- EM_SETTEXTLIMIT Allocates memory from the control heap for the
- specified maximum number of characters,
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- specified maximum number of characters,
- returning TRUE if it is successful, FALSE if it
- is not. Failure causes a WM_CONTROL message
- with the EM_MEMERROR control code to be sent to
- the owner window.
-
- EM_CUT Copies the current text selection to the system
- clipboard in CF_TEXT format and deletes the
- selection from the control window.
-
- EM_COPY Copies the current text selection to the system
- clipboard in CF_TEXT format.
-
- EM_CLEAR Deletes the current text selection from the
- control window.
-
- EM_PASTE Copies the current contents of the system
- clipboard that have CF_TEXT format, replacing
- the current text selection in the control.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- the current text selection in the control.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- 13.5 Summary
-
- The following sections describe the styles and messages associated with
- entry-field controls.
-
- 13.5.1 Entry-Field Control Styles
-
- The following style constants, specified when the entry-field control is
- created, determine its behavior and appearance:
-
- ES_AUTOSCROLL Scrolls text horizontally to show the current insertion
- point.
-
- ES_CENTER Displays text centered within the control window.
-
- ES_LEFT Displays text on the left within the control window.
-
- ES_MARGIN Paints a wide border around the control window. The border is
- one-half characters wide and one-fourth characters high. Without this
- style, no border is drawn around the control window. The entry-field
- window rectangle is inflated (outset) on all sides by this margin. After
- an ES_MARGIN style entry-field is created, the WinQueryWindowRect function
- returns a larger rectangle, with a different origin than the one specified
- at creation because it now includes this margin. Note this when moving or
- sizing an entry-field control or it will become larger after each move or
- size operation.
-
- ES_RIGHT Displays text on the right within the control window.
-
- 13.5.2 Messages Sent to Entry-Field Controls
-
- This section describes the messages that are specific to entry-field
- controls:
-
- EM_CLEAR Deletes the current selection in the entry-field control.
-
- EM_COPY Sends the current selection to the system clipboard in CF_TEXT
- format.
-
- EM_CUT Sends the current selection to the system clipboard in CF_TEXT
- format and then deletes the selection from the entry-field control.
-
- EM_PASTE Replaces the current selection (or inserts text if the current
- selection is an insertion point) with text from the system clipboard. No
- replacement occurs if the clipboard does not contain any CF_TEXT data.
-
- EM_QUERYCHANGED Returns TRUE if the contents of the entry-field control
- have changed since last receiving a WM_QUERYWINDOWPARAMS or EM_GETCHANGED
- message; it returns FALSE if the contents have not changed.
-
- EM_QUERYFIRSTCHAR Returns the zero-based byte offset of the first
- character visible at the left edge of the control window.
-
- EM_QUERYSEL Returns the offsets for the first and last characters of the
- current selection as the low and high word of the function return value.
-
- EM_SETFIRSTCHAR Displays a character, specified by its zero-based byte
- offset, as the first character visible at the left edge of the control
- window, scrolling the text if necessary.
-
- EM_SETSEL Sets the selection range between the supplied first and last
- character positions. If the first-character position is zero and the
- last-character position is greater than the number of characters in the
- control window, the entire text is selected.
-
- EM_SETTEXTLIMIT Sets the maximum number of characters that the
- entry-field control can hold. It returns TRUE if the operation is
- successful, or FALSE if there was not enough memory.
-
- 13.5.3 Messages Sent from an Entry-Field to an Owner Window
-
- The following section describes messages that an entry-field control sends
- to its owner window:
-
- WM_CONTROL Notifies the owner window of a significant change in the
- control. The low word of the first parameter contains the window ID of the
- entry-field control window. The high word of the first parameter contains
- one of the following notification codes:
-
- Control code Description
- ──────────────────────────────────────────────────────────────────────────
- EN_CHANGE Contents of the entry-field control have changed and
- the change is displayed on screen.
-
- EN_KILLFOCUS Entry-field control loses the keyboard focus.
-
- EN_MEMERROR Entry-field control cannot allocate enough memory to
- perform the requested operation, such as extending the
- text limit.
-
- EN_SCROLL Entry-field control is about to scroll horizontally.
- This happens when a user enters text beyond the edge
- of the entry-field control boundary, requiring the
- text to scroll to continue displaying the insertion
- point.
-
- EN_SETFOCUS Entry-field control receives the keyboard focus.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 14 List-Box Controls
-
- 14.1 Introduction
- 14.2 About List Boxes
- 14.3 Using a List Box in an Application
- 14.3.1 Creating a List-Box Window
- 14.3.2 List Boxes in Dialog Windows
- 14.3.3 Adding and Deleting an Item in a List Box
- 14.3.4 Responding to a User Selection in a List Box
- 14.3.5 Handling Multiple Selections
- 14.3.6 Owner-Drawn List Items
- 14.4 Default List-Box Behavior
- 14.5 Summary
- 14.5.1 List-Box Styles
- 14.5.2 Messages Sent from a List Box to an Owner Window
- 14.5.3 Messages Sent to a List Box
-
- 14.1 Introduction
-
- This chapter describes creating and using list-box control windows in your
- applications. You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Window messages and message queues
-
-
- 14.2 About List Boxes
-
- A list box is a control window containing a list of items. Each item
- contains a text string and a handle. The text string is usually displayed
- in the list-box window. The handle is available to the application to
- reference other data associated with the list item.
-
- A list-box window must be owned by another window. This ownership
- relationship is important because the owner window receives messages from
- the list box when events occur──for example, when a user selects an item
- from the list box. Typically, the owner window is a client window of an
- application frame window or a dialog window. The client-window procedure
- or the dialog-window procedure defined by an application responds to
- messages sent from the list box.
-
- A list box always contains a scroll bar. If the list box contains more
- items than can be displayed in the list-box window, the scroll bar is
- enabled. Otherwise, the scroll bar is disabled. The list box responds to
- clicks in the scroll bar by scrolling the list.
-
- The maximum number of items in a list box is 32,767. This limit on
- list-box items is controlled by the 64K heap-size limit used in storing
- the list-box items.
-
- Figure 14.1 shows a typical list-box control.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 14.1 can be found in Section 14.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 14.1 Typical List-Box Control
-
-
- 14.3 Using a List Box in an Application
-
- An application uses a list-box control to display a list in a window. List
- boxes can be displayed in standard application windows, although they are
- more commonly used in dialog windows. Either way, notification messages
- are sent from the list box to the owner window, allowing the application
- to respond to user actions in the list. In practice, if a list box is
- owned by a dialog window, messages are handled in dialog-window
- procedures. If the list box is owned by a client window, notification
- messages are handled in the client-window procedure.
-
- Once a list box is created, the application controls inserting and
- deleting list items. Items can be inserted at the end of the list,
- automatically sorted into the list, or inserted at a specified index
- position. Applications can turn list drawing on and off to speed up the
- process of inserting numerous items into a list.
-
- The window procedure of the owner window of the list box receives messages
- when a user manipulates the list-box data. Most default list actions (for
- example, highlighting selections and scrolling) are handled automatically
- by the list box itself. The application controls the responses when the
- user chooses an item in the list, either by double-clicking the item or
- pressing ENTER after an item is highlighted. The application is also
- notified whenever the selection changes or when the list is scrolled.
-
- Normally, list items are text strings drawn by a list box. An application
- can also draw and highlight the items in a list. This allows customized
- lists containing graphics or special fonts to be created. When an
- application creates a list box with the LS_OWNERDRAW style, the owner of
- the list box receives a WM_DRAWITEM message for each item that should be
- drawn or highlighted. This is similar to the owner-drawn style for menus,
- but unlike menus, the owner-drawn style applies to the entire list rather
- than to individual items.
-
- 14.3.1 Creating a List-Box Window
-
- List boxes are WC_LISTBOX class windows and are predefined by the system.
- Applications can create list boxes by calling the WinCreateWindow
- function, using WC_LISTBOX as the window-class parameter.
-
- A list box passes notification messages to its owner window, so an
- application uses its client window, rather than the frame window, as the
- owner of the list. The client-window procedure receives the messages sent
- from the list box.
-
- For example, to create a list box that completely fills the client area of
- a frame window, an application would make the client window the owner and
- parent of the list-box window and make the list-box window the same size
- as the client window. This is shown in the following code fragment:
-
- /* How big is the client window? */
-
- WinQueryWindowRect(hwndClient, &rect);
-
- /* Make a list-box window. */
-
- hwndList = WinCreateWindow(hwndClient, /* parent */
- WC_LISTBOX, /* class */
- "", /* name */
- WS_VISIBLE | LS_NOADJUSTPOS, /* style */
- 0, 0, /* x, y */
- rect.xRight, rect.yTop, /* cx, cy */
- hwndClient, /* owner */
- HWND_TOP, /* behind */
- ID_LISTWINDOW, /* ID */
- NULL, /* control data */
- NULL); /* parameters */
-
- Because the list box draws its own border and a frame-window border
- already surrounds the client area of a frame window (because of the
- adjacent frame controls), the effect is a double-thick border around the
- list box. To change this, call the WinInflateRect function to overlap the
- list-box border with the surrounding frame-window border. This results in
- one list-box border.
-
- Notice that the code specifies the list-box window style LS_NOADJUSTPOS.
- This ensures that the list box is created in exactly the size specified.
- If the LS_NOADJUSTPOS style is not specified, the list-box height is
- rounded down, if necessary, to make it a multiple of the item height.
- Allowing a list box to automatically adjust its height is useful for
- preventing partial items from being displayed at the bottom of a list box.
-
- 14.3.2 List Boxes in Dialog Windows
-
- List boxes are most commonly used in dialog windows. A list box in a
- dialog box is a control window, like a push button or an entry field.
- Typically, the application defines a list box as one item in a dialog
- template in the resource-definition file, as shown in the following
- Resource Compiler source-code fragment:
-
- DLGTEMPLATE IDD_OPEN
- BEGIN
- DIALOG "Open...", IDD_OPEN, 35, 35, 150, 135,
- FS_DLGBORDER, FCF_TITLEBAR
- BEGIN
- LISTBOX IDD_FILELIST, 15, 15, 90, 90
- PUSHBUTTON "Drive", IDD_DRIVEBUTTON, 115, 70, 30, 14
- DEFPUSHBUTTON "Open", IDD_OPENBUTTON, 115, 40, 30, 14
- PUSHBUTTON "Cancel", IDD_CANCELBUTTON, 115, 15, 30, 14
- END
- END
-
- Once the dialog resource is defined, the application loads and displays
- the dialog box as it normally would. The application should insert items
- into the list when processing the WM_INITDLG message. The dialog-window
- procedure gets the window handle for the list box by calling the
- WinWindowFromID function using the list-box ID given in the dialog
- template. The following code fragment from a dialog-window procedure
- illustrates this:
-
- case WM_INITDLG:
- hwndList = WinWindowFromID(hwndDialog, IDD_FILELIST);
- .
- . /* Now use hwndList to send LM_INSERTITEM messages. */
- .
- return 0L;
-
- It is very common for a dialog window with a list box to have an OK
- button. The user may select items in the list and then indicate a final
- selection by double-clicking, pressing ENTER, or clicking the OK button.
- When the dialog-window procedure receives a message that the user has
- clicked the OK button, it should query the list box to determine the
- current selection (or selections if the list allows multiple selections)
- and then respond as if it received a WM_CONTROL message with the LN_ENTER
- notification code.
-
- 14.3.3 Adding and Deleting an Item in a List Box
-
- Applications can add or delete items in a list box by sending
- LM_INSERTITEM and LM_DELETEITEM messages to the list-box window. Items in
- a list are specified with a zero-based index (beginning at the top of the
- list). A new list is always created empty. The application must initialize
- the list by inserting items.
-
- The application specifies the text and position for each new item. It can
- specify an absolute-position index or one of the following predefined
- index values:
-
- Value Meaning
- ──────────────────────────────────────────────────────────────────────────
- LIT_END Insert item at end of list.
-
- LIT_SORTASCENDING Insert item alphabetically ascending
- into list.
-
- LIT_SORTDESCENDING Insert item alphabetically descending
- into list.
- ──────────────────────────────────────────────────────────────────────────
-
- The application must send an LM_DELETEITEM message and supply the absolute
- index position of the item when deleting items from a list. The
- LM_DELETEALL message deletes all items in a list.
-
- One way an application can speed up the process of inserting list items is
- to suspend drawing in the list while inserting items. The list is redrawn
- after the insertion process is finished. This is a particularly valuable
- approach when using a sorted insertion process, when inserting one item
- can cause rearrangement of the entire list. List drawing is turned off by
- calling the WinEnableWindowUpdate function with FALSE for the enable
- parameter, and then calling the WinShowWindow function. This forces a
- complete update when insertion is complete. The following code fragment
- illustrates this concept:
-
- /* Disable updates while filling the list. */
-
- WinEnableWindowUpdate(hwndFileList, FALSE);
- .
- . /* Send LM_INSERTITEM messages to insert all new items. */
- .
-
- /* Now cause the window to update and show the new information. */
-
- WinShowWindow(hwndFileList, TRUE);
-
- Note that this optimization is not necessary if adding list items when
- processing a WM_INITDLG message because the list box is not visible and
- the list-box routines are internally optimized.
-
- 14.3.4 Responding to a User Selection in a List Box
-
- The primary notification an application receives when a user chooses an
- item in a list is a WM_CONTROL message with the LN_ENTER control code sent
- to the owner window of the list. The owner window is an application client
- window or a dialog window. Within the window procedure for the owner
- window, the application responds to the LN_ENTER control code by querying
- the list box for the current selection (or selections, in the case of an
- LS_MULTIPLESEL list box).
-
- The LN_ENTER control code notifies the application that the user has
- selected a list item. A WM_CONTROL message with an LN_SELECT control code
- is sent to the list-box owner whenever a selection in a list changes, such
- as when a user moves the mouse pointer up and down a list while pressing
- the mouse button. In this case, items are selected but not yet chosen. An
- application may ignore LN_SELECT control codes when the selection changes,
- responding only when the item is actually chosen. An application might use
- the LN_SELECT control code to display context-dependent information that
- changes rapidly with each selection made by the user.
-
- 14.3.5 Handling Multiple Selections
-
- When a list box has the style LS_MULTIPLESEL, more than one item may be
- selected at a time. An application must use different strategies when
- working with this type of list. For example, when responding to an
- LN_ENTER control code, it is not sufficient to send a single
- LM_QUERYSELECTION message because that message will find only the first
- selection. To find all current selections, an application should continue
- sending LM_QUERYSELECTION messages, using the return index of the previous
- message as the starting index of the next message, until no items are
- returned.
-
- 14.3.6 Owner-Drawn List Items
-
- To draw its own list items, an application must create a list that has the
- style LS_OWNERDRAW. The owner window of the list box must respond to the
- WM_MEASUREITEM and WM_DRAWITEM messages.
-
- When the owner window receives a WM_MEASUREITEM message, it must return
- the height of the list item. All items in a list must have the same height
- (greater than or equal to 1). The WM_MEASUREITEM message is sent only
- once, when the list box is created. You can change the item height by
- sending an LM_SETITEMHEIGHT message to the list-box window.
-
- The owner window receives a WM_DRAWITEM message whenever an item in an
- owner-drawn list should be drawn or highlighted. The owner window returns
- FALSE if the list box must draw the text of the item. The owner window
- returns TRUE if it actually draws the item. This tells the list box not to
- draw the item. This is useful if the owner window alters the appearance of
- certain items, allowing other items to be drawn by the list box.
-
- Although it is quite common for an owner-drawn list to draw items, it is
- less common to override the system-default method of highlighting. (The
- system-default highlighting method inverts the rectangle that contains the
- item.) Do not create your own highlighting unless the system-default
- method is unacceptable to you.
-
- The WM_DRAWITEM message contains a pointer to an OWNERITEM data structure.
- The OWNERITEM data structure contains the window ID for the list box, a
- presentation-space handle, a bounding rectangle for the item, the position
- index for the item, and the application-defined item handle. This
- structure also contains two fields that determine if a message draws,
- highlights, or removes the highlighting from an item. The OWNERITEM data
- structure has the following form:
-
- typedef struct _OWNERITEM {
- HWND hwnd;
- HPS hps;
- USHORT fsState;
- USHORT fsAttribute;
- USHORT fsStateOld;
- USHORT fsAttributeOld;
- RECTL rclItem;
- SHORT idItem;
- ULONG hItem;
- } OWNERITEM;
-
- When the item must be drawn, the owner window receives a WM_DRAWITEM
- message with the fsState field set differently than the fsStateOld field.
- If the owner window draws the item in response to this message, it returns
- TRUE, telling the system not to draw the item. If the owner window returns
- FALSE, the system draws the item using the default list-item drawing
- method.
-
- You can get the text of a list item by sending an LM_QUERYITEMTEXT message
- to the list-box window. You should draw the item using the hps and rclItem
- arguments provided in the OWNERITEM structure.
-
- If the item being drawn is currently selected, then the fsState and
- fsStateOld fields will both be TRUE; they will both be FALSE if the item
- is not currently selected. The window receiving a WM_DRAWITEM message can
- use this information to highlight the selected item at the same time it
- draws the item. If the owner window highlights the item, it should leave
- the fsState and fsStateOld fields equal to each other. If the system
- provides default highlighting for the item (by inverting the item
- rectangle), the owner window should set the fsState field to 1 and the
- fsStateOld field to 0 before returning from the WM_DRAWITEM message.
-
- The owner window also receives a WM_DRAWITEM message when the highlight
- state of a list item changes. For example, when a user clicks an item, the
- highlighting must be removed from the currently selected item and the new
- selection must be highlighted. If these items are owner-drawn, then the
- owner window receives one WM_DRAWITEM message for each unhighlighted item
- and one message for the newly highlighted item. To highlight an item, the
- fsState field must equal TRUE and the fsStateOld field must equal FALSE.
- In this case, the application should highlight the item and return the
- fsState and fsStateOld fields equal to FALSE. This tells the system not to
- highlight the item. The application can also return the fsState and
- fsStateOld fields with two different values (not equal) and the list box
- will highlight the item (the default).
-
- To remove highlighting from an item, the fsState field must equal FALSE
- and the fsStateOld field must equal TRUE. An application can remove the
- highlighting and return both the fsState and fsStateOld fields as FALSE,
- or it can return the fsState field with a value that is not equal to the
- fsStateOld field and the system will remove the highlighting (the
- default).
-
- The following code fragment shows these selection processes:
-
- case WM_DRAWITEM:
-
- /* Test to see if this is drawing or highlighting/unhighlighting. */
-
- if (((POWNERITEM) mp2)->fsState !=
- ((POWNERITEM) mp2)->fsStateOld) {
-
- /* This is either highlighting or unhighlighting. */
-
- if (((POWNERITEM) mp2)->fsState) {
- .
- . /* Highlight the item. */
- .
- } else {
- .
- . /* Remove the highlighting.*/
- .
- }
- /* Set fsState = fsStateOld to tell system you did it. */
-
- ((POWNERITEM) mp2)->fsState =
- ((POWNERITEM) mp2)->fsStateOld = 0;
-
- return (TRUE); /* Tells list box you did the highlighting. */
-
- } else {
- .
- . /* Draw the item. */
- .
-
- /* Check to see if item is selected. */
-
- if (((POWNERITEM) mp2)->fsState) {
- .
- . /* Highlight the item. */
- .
-
- /* Set fsState = fsStateOld to tell system you did it. */
-
- ((POWNERITEM) mp2)->fsState =
- ((POWNERITEM) mp2) ->fsStateOld = 0;
- }
- return (TRUE); /* Tells list box you did the drawing. */
- }
-
-
- 14.4 Default List-Box Behavior
-
- This section lists all the messages handled by the predefined list-box
- window-class procedure.
-
- ╓┌─┌──────────────────────────┌──────────────────────────────────────────────╖
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_CREATE Creates an empty list box with a scroll bar.
-
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_DESTROY Destroys the list and deallocates any memory
- allocated during its existence.
-
- WM_PAINT Draws the list box and its items.
-
- WM_CHAR Processes virtual keys for line and page
- scrolling. Sends an LN_ENTER notification code
- for the ENTER key. Returns TRUE if the key is
- processed; otherwise, passes the message to the
- WinDefWindowProc function.
-
- WM_SETFOCUS If gaining the focus, creates a cursor and
- sends an LN_SETFOCUS notication code to the
- owner window. If losing the focus, destroys the
- cursor and sends an LN_KILLFOCUS notification
- code to the owner window.
-
- WM_ADJUSTWINDOWPOS If the list box has the style LS_NOADJUSTPOS,
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_ADJUSTWINDOWPOS If the list box has the style LS_NOADJUSTPOS,
- makes no changes to the SWP structure and
- returns FALSE. Otherwise, adjusts the height of
- the list box so that a partial item is not
- shown at the bottom of the list. Returns TRUE
- if the SWP structure is changed.
-
- WM_ENABLE Enables the scroll bar if there are more items
- than can be displayed in a list window.
-
- WM_TIMER Uses timers to control automatic scrolling that
- occurs when a user drags the mouse pointer
- outside the window.
-
- WM_BUTTON2DOWN Returns TRUE; the message is ignored.
-
- WM_BUTTON3DOWN Returns TRUE; the message is ignored.
-
- WM_MOUSEMOVE Sets the mouse pointer to the arrow shape and
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_MOUSEMOVE Sets the mouse pointer to the arrow shape and
- returns TRUE to show that the message was
- processed.
-
- WM_VSCROLL Handles scrolling indicated by the list-box
- scroll bar.
-
- LM_QUERYITEMCOUNT Returns the number of items in the list.
-
- LM_INSERTITEM Inserts a new item in the list according to the
- position information passed with the message.
-
- LM_SETTOPINDEX Shows the specified item as the top item in the
- list window, scrolling the list as necessary.
-
- LM_QUERYTOPINDEX Returns the zero-based index to the item
- currently visible at the top of the list.
-
- LM_DELETEITEM Removes the specified item from the list,
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- LM_DELETEITEM Removes the specified item from the list,
- redrawing the list as necessary. Returns the
- number of items remaining in the list.
-
- LM_SELECTITEM Selects the specified item. If the list is a
- single-selection list, deselects the previous
- selection. Sends a WM_CONTROL message (with the
- LN_SELECT code) to the owner window.
-
- LM_QUERYSELECTION For a single-selection list box, returns the
- zero-based index of the currently selected
- item. For multiple-selection list boxes,
- returns the next selected item or LIT_NONE if
- no more items are selected.
-
- LM_SETITEMTEXT Sets the text for the specified item.
-
- LM_QUERYITEMTEXTLENGTH Returns the length of the specified item text.
-
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- LM_QUERYITEMTEXT Copies the specified item's text to a buffer
- supplied by the message sender.
-
- LM_SETITEMHANDLE Sets the specified item handle.
-
- LM_QUERYITEMHANDLE Returns the specified item handle.
-
- LM_SEARCHSTRING Searches the list for a match to the specified
- string.
-
- LM_SETITEMHEIGHT Sets the item height for the list. All items in
- the list have the same height.
-
- LM_DELETEALL Deletes all items in the list.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- 14.5 Summary
-
- List boxes are control windows that have style bits and that can send and
- receive messages. These styles and messages are listed in the following
- sections.
-
- 14.5.1 List-Box Styles
-
- The style of a list box determines how it displays its items and how it
- responds to user input. The following styles are used by list boxes:
-
- LS_MULTIPLESEL Allows more than one list item to be selected at a time.
-
- LS_NOADJUSTPOS Automatically adjusts the list-box height (by default) so
- that it is a multiple of the item height. This is done so that a list box
- will not display a partial item at the bottom of the list. The size of the
- list box can be different than the size specified by the application that
- created it. The style LS_NOADJUSTPOS tells the list box not to adjust the
- height of window in response to a WM_SIZE message. Applications that need
- absolute control over list-box size should use the LS_NOADJUSTPOS style
- (for example, when a list box needs to completely fill a client area).
- This style may cause items at the bottom of the box to be displayed
- partially.
-
- LS_OWNERDRAW Causes the owner window to receive a WM_DRAWITEM message
- each time an item must be drawn or highlighted.
-
- 14.5.2 Messages Sent from a List Box to an Owner Window
-
- Messages sent from a list box to an owner window notify the owner of
- events in the list box, such as when a user selects an item. The following
- messages are sent from list boxes to owner windows:
-
- WM_CONTROL Sent to the owner window of the list box when a user event
- occurs in the list box. This message contains a control code that notifies
- the owner that an event occurred and indicates the type of event. The
- following are possible control codes:
-
- Code Description
- ──────────────────────────────────────────────────────────────────────────
- LN_ENTER Sent to the owner window when the user presses ENTER or
- double-clicks an item while the list box has the focus. This
- code indicates that the user has chosen an item. The owner
- window may then query the current selection and respond
- accordingly.
-
- LN_KILLFOCUS Sent to the owner window when the list box loses the focus.
-
- LN_SCROLL Sent to the owner window when the list box scrolls.
-
- LN_SELECT Sent to the owner window when a different item in the list
- is selected. The owner window can use this code to query the
- current selection and respond accordingly.
-
- LN_SETFOCUS Sent to the owner window when the list box receives the
- focus.
- ──────────────────────────────────────────────────────────────────────────
-
- WM_DRAWITEM Sent to the owner window of a list box with the style
- LS_OWNERDRAW each time an item must be drawn. The owner window should
- return TRUE if it actually draws the item; otherwise, it should return
- FALSE. If the item contains text, the owner window can return FALSE and
- the list box will draw the item. This message allows the owner window to
- draw the item or allows default text drawing by the list box. This message
- contains a structure with a presentation space and a bounding rectangle in
- which to draw the item. It is also sent when an item must be highlighted.
- The owner window can handle the highlighting or indicate that the list box
- should handle this process.
-
- WM_MEASUREITEM This message is sent to the owner window of a list box
- that has the style LS_OWNERDRAW. The owner window returns a value that is
- the height of an item in the list. Note that all items in a list must have
- the same height and that this must be greater than or equal to 1. It is
- not necessary to specify the width of an item since the item is clipped to
- the width of the list box when drawn.
-
- 14.5.3 Messages Sent to a List Box
-
- Messages sent to a list box set or query the list data. The following
- messages are sent to list-box controls:
-
- LM_DELETEALL Deletes all items in the list.
-
- LM_DELETEITEM Deletes a specified item from the list.
-
- LM_INSERTITEM Inserts an item in the list box. Items can be inserted at a
- specified index, at the beginning or the end, or sorted in ascending or
- descending order.
-
- LM_QUERYITEMCOUNT Returns the number of items in the list box.
-
- LM_QUERYITEMHANDLE Returns the item handle for the specified item.
-
- LM_QUERYITEMTEXT Copies the text for a specified item into a buffer
- provided by the caller. The size of the required buffer can be determined
- by sending an LM_QUERYITEMTEXTLENGTH message for the item.
-
- LM_QUERYITEMTEXTLENGTH Returns the length of the text for a specified
- item in the list.
-
- LM_QUERYSELECTION Returns the index of the selected item in the list or
- LIT_NONE if no item is selected. In a multiple selection list, this
- message returns the first selected item, starting at a specified index.
-
- LM_QUERYTOPINDEX Returns the index of the item currently displayed at the
- top of the list-box window or LIT_NONE if the list is empty.
-
- LM_SEARCHSTRING Searches the list for a match with the specified string,
- returning the first matching item. Match criteria can be set using flags
- for case sensitivity and substring matching. Another parameter allows the
- search to start at a specified index, allowing iterative searches to start
- from the previous matching item.
-
- LM_SELECTITEM Sets the selection state of a specified item. If the list
- box allows only a single selection, the previous selection is deselected.
- An index of LIT_NONE deselects all items in the list. Sending an
- LM_SELECTITEM message with LIT_NONE set to a multiple-selection list box
- does not deselect anything. However, it does remove the cursor.
-
- LM_SETITEMHANDLE Sets the item handle for the specified item.
-
- LM_SETITEMHEIGHT Sets the height of all items in the list, redrawing the
- list box and all visible items.
-
- LM_SETITEMTEXT Sets the text of a specified item in the list.
-
- LM_SETTOPINDEX Displays a specified item at the top of the list box,
- scrolling the list as necessary.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 15 Static Controls
-
- 15.1 Introduction
- 15.2 About Static Controls
- 15.3 Using Static Controls in an Application
- 15.3.1 Static Controls in a Dialog Window
- 15.3.2 Static Controls in Client Windows
- 15.3.3 Changing the Static-Control Handle
- 15.4 Default Static-Control Behavior
- 15.5 Summary
- 15.5.1 Static-Control Styles
- 15.5.2 Messages Sent to Static Controls
-
- 15.1 Introduction
-
- This chapter describes how to use static control windows in your
- applications. You should already be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Window messages and message queues
-
-
- 15.2 About Static Controls
-
- Static controls are simple text fields, bitmaps, or icons that can be used
- to label, enclose, or separate other control windows. Static controls do
- not accept user input and they do not send notification messages to their
- owners.
-
- Static controls have style bits that determine whether the control
- displays text, draws a simple box containing text, displays an icon or a
- bitmap, or shows framed or unframed colored boxes. The various styles for
- static controls are discussed individually in Section 15.5.
-
- Static text controls are most commonly used in dialog windows as labels.
- Iconic and bitmap static controls can be used to provide graphic objects
- in dialog windows. One advantage of static controls is that, once created,
- they provide labels and graphics and require little attention from an
- application.
-
- Static controls never accept the keyboard focus. When a static control
- receives a WM_SETFOCUS message, or when a user clicks a static control,
- that control advances the focus to the next sibling window that is not a
- static control. If there are no sibling windows to the static control, the
- focus is given to the owner of the static control.
-
-
- 15.3 Using Static Controls in an Application
-
- Static controls can be used in dialog windows and client windows. There is
- usually very little interaction between an application and the static
- control once the control is created. However, an application can change
- the state of the static control.
-
- Static controls also are associated with a long-word handle which may be
- set and queried by an application. By default, icon and bitmap static
- controls use this handle to contain a handle to their display object.
- Applications can modify this handle by using the SM_SETHANDLE and
- SM_QUERYHANDLE messages to change static-control appearance.
-
- 15.3.1 Static Controls in a Dialog Window
-
- Static controls are most commonly used as labels and separators in dialog
- windows. As such, they are defined as part of a dialog template in the
- application resource file. Once the dialog window is displayed, the static
- controls do not interact with the application unless the application
- changes their state. Typically, an application might change the text or
- position of a static control. These operations are achieved by using the
- WinSetWindowText and WinSetWindowPos functions.
-
- When defining icon or bitmap static controls in a dialog template, the
- text for the control is interpreted as the resource ID of the bitmap or
- the icon. There are two ways that the text can be interpreted. If the
- first byte is '#', the rest of the text is assumed to be an ASCII decimal
- representation of the icon-or bitmap-resource ID. If the first byte of the
- text is 0xFF, the second byte is the low byte of the resource ID, and the
- third byte is the high byte of the resource ID. The following are two
- sample Resource Compiler definitions:
-
- CONTROL "#256",ID_ICON1, 140, 20, 0, 0, WC_STATIC,
- SS_ICON | WS_VISIBLE
-
- CONTROL 0xFF000100, ID_ICON2, 140, 20, 0, 0, WC_STATIC,
- SS_ICON | WS_VISIBLE
-
- Each definition specifies an SS_ICON static control that uses an icon with
- resource ID 256 (0x0100). The icon is assumed to be in the current
- application resource file.
-
- The window handle for a static-control window can be obtained by calling
- the WinWindowFromID function using the dialog-window handle and the window
- ID of the static control as defined in the dialog template.
-
- 15.3.2 Static Controls in Client Windows
-
- Applications can create static-control windows in non-dialog windows by
- calling the WinCreateWindow function with a WC_STATIC window class. The
- appearance of the control is defined by the style parameter to the
- WinCreateWindow function.
-
- If the application creates a control with SS_ICON or SS_BITMAP style, it
- must ensure that the resource ID specified by the window text corresponds
- to an actual resource in the application resource file or the static
- control will not be created.
-
- Once created, the static-control window can be moved and sized just like
- any other child window. An application can obtain the window handle of the
- static control by calling the WinWindowFromID function, supplying the
- parent window and the window ID of the static control.
-
- 15.3.3 Changing the Static-Control Handle
-
- The static-window handle contains a handle to an icon or bitmap. Applica-
- tions can query and set this handle by using the SM_QUERYHANDLE and
- SM_SETHANDLE messages. Setting the handle causes the static item to be
- redrawn, so the handle must be a valid icon or bitmap handle.
-
- For non-icon and non-bitmap static-control items, the handle is available
- for use by the application and has no effect on the appearance of the
- control.
-
-
- 15.4 Default Static-Control Behavior
-
- This section describes all the messages specifically handled by the
- predefined static-control class.
-
- ╓┌─┌───────────────────────────┌─────────────────────────────────────────────╖
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_PAINT Draws the static control based on its style
- attributes.
-
- WM_CREATE Sets the window text for static-text controls.
- Loads the bitmap or icon resource for the
- bitmap or icon static controls. Returns TRUE
- if the resource cannot be loaded.
-
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_DESTROY Frees the text for static-text controls.
- Destroys the bitmap or icon for the bitmap and
- icon static controls. The icon for a sysicon
- static control is not destroyed, because it
- belongs to the system.
-
- WM_ADJUSTWINDOWPOS Adjusts the SWP structure so that the new
- window size matches the bitmap, icon, or
- sysicon dimensions associated with the
- control.
-
- WM_QUERYWINDOWPARAMS Returns the requested window parameters.
-
- WM_SETWINDOWPARAMS Allows the window text to be set for
- static-text controls only.
-
- WM_ENABLE Invalidates the entire control window, forcing
- it to be redrawn.
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- it to be redrawn.
-
- WM_QUERYDLGCODE Returns the predefined constant DLGC_STATIC.
-
- WM_MOUSEMOVE Sets the mouse pointer to the arrow pointer
- and returns TRUE.
-
- WM_SETFOCUS Sets the focus to the next sibling window that
- can accept the focus, or if no such sibling
- exists, it sets the focus to the parent
- window.
-
- SM_SETHANDLE Sets the handle associated with the static
- control and invalidates the control window,
- forcing it to be redrawn.
-
- SM_QUERYHANDLE Returns the handle associated with the
- static-control window.
-
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_MATCHMNEMONIC Returns TRUE if the mnemonic passed in the mp1
- parameter matches the mnemonic in the
- control-window text.
-
- WM_HITTEST Returns HT_TRANSPARENT for the following
- static control styles: SS_GROUPBOX,
- SS_FGNDRECT, SS_HALFTONERECT, SS_BKGNDRECT,
- SS_FGNDFRAME, SS_HALFTONEFRAME, SS_BKGNDFRAME.
- For other styles, returns the WinDefWindowProc
- function.
- ──────────────────────────────────────────────────────────────────────────
-
-
-
- 15.5 Summary
-
- The following sections describe the styles and messages associated with
- static-control windows.
-
- 15.5.1 Static-Control Styles
-
- The following styles are associated with static-control windows:
-
- SS_BITMAP Draws a bitmap. The resource ID for the bitmap resource is
- determined in the same way as for SS_ICON controls. The bitmap resource is
- assumed to be in the current application resource file.
-
- SS_BKGNDFRAME Draws a rectangular frame with the current background
- color.
-
- SS_BKGNDRECT Draws a filled rectangle with the current background color.
-
- SS_FGNDFRAME Draws a rectangular frame with the current foreground color.
-
- SS_FGNDRECT Draws a filled rectangle with the current foreground color.
-
- SS_GROUPBOX Draws a box with control text in the upper-right corner of
- the box. This style is useful for enclosing groups of radio buttons or
- check boxes in a box.
-
- SS_HALFTONEFRAME Draws a rectangular frame with a halftone pattern in the
- current foreground color.
-
- SS_HALFTONERECT Draws a filled rectangle with a halftone pattern in the
- current foreground color.
-
- SS_ICON Draws an icon. The text of the control is interpreted as the
- resource ID of the icon. The bytes that make up the text can be
- interpreted as numeric values or as ASCII representations of numbers,
- depending on the value of the first byte. If the first byte is '#', the
- remaining text is assumed to be an ASCII decimal representation of the
- icon resource ID. If the first byte of the text is 0xFF, the second byte
- is the low byte of the resource ID and the third byte is the high byte of
- the resource ID.
-
- SS_SYSICON Displays a system pointer icon. The ID of the icon is
- extracted from the control text, as in the SS_ICON style. To display this
- icon, the system calls the WinQuerySysPointer function with the specified
- ID.
-
- SS_TEXT Allows various formatting options to be combined with the SS_TEXT
- style to produce formatted text in the boundaries of the control. The
- formatting option flags are the same as those used for the WinDrawText
- function.
-
- 15.5.2 Messages Sent to Static Controls
-
- The following messages are associated with static-control windows:
-
- SM_QUERYHANDLE──Returns the private handle for the static control. For
- controls with SS_ICON, SS_BITMAP, or SS_SYSICON style, the handle of the
- icon or bitmap is returned. For all other types of static controls, the
- handle is available for application-defined purposes.
-
- SM_SETHANDLE──Sets the private handle for the static control. Static
- controls with SS_ICON, SS_BITMAP, or SS_SYSICON style automatically use
- this handle to store the icon or bitmap when the control is created. An
- application can change the appearance of these controls by setting the
- handle. For all other types of static controls, the handle is available
- for application-defined purposes.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 16 Scroll-Bar Controls
-
- 16.1 Introduction
- 16.2 About Scroll Bars
- 16.2.1 Scroll-Bar Creation
- 16.2.2 Scroll-Bar Range and Position
- 16.2.3 Scroll-Bar Notification Messages
- 16.2.4 Scroll Bars and the Keyboard
- 16.3 Using Scroll Bars
- 16.3.1 Creating Scroll Bars
- 16.3.2 Retrieving a Scroll-Bar Handle
- 16.3.3 Using the Scroll-Bar Range and Position
- 16.4 Summary
- 16.4.1 Messages
- 16.4.2 System Values
-
- 16.1 Introduction
-
- This chapter describes creating and using scroll bars in Presentation
- Manager applications. You should also be familiar with the following
- topics:
-
- ■ Standard user-interface guidelines
-
- ■ Windows
-
- ■ Frame windows
-
- ■ Messages and message queues
-
- ■ Control windows
-
-
- 16.2 About Scroll Bars
-
- Scroll bars are control windows that convert mouse and keyboard input into
- integer values. Applications typically use scroll bars to control
- scrolling the contents in a client window.
-
- A scroll bar has several parts: the bar, arrows, and the slider. These are
- found on vertical and on horizontal scroll bars. Arrows are located at
- each end of a scroll bar. The left scroll arrow, on the left side of a
- horizontal scroll bar, lets the user scroll toward the left in a document.
- The right scroll arrow lets the user scroll toward the right. The upper
- scroll arrow lets the user scroll upward in the document. The lower scroll
- arrow lets the user scroll downward.
-
- The slider, a hollow box, lies between the two scroll arrows. The slider
- position in the scroll bar the reflects current value of the scroll bar.
- When the slider is against the left or top scroll arrow, the scroll-bar
- value is at a minimum; when the slider is against the right or bottom
- arrow, the scroll-bar value is at a maximum. The area between the scroll
- arrows is called the slider background.
-
- Scroll bars monitor the slider position and send notification messages to
- the owner window when the slider position changes through mouse or
- keyboard input.
-
- Scroll bars are often used in frame windows. A frame window automatically
- places scroll bars at the right and bottom sides of a window, depending on
- the scroll-bar style. The frame window automatically passes scroll-bar
- messages on to its client window. The client window handles these messages
- by adjusting the display. The client window can also send messages
- directly to the scroll bar, directing the scroll bar to adjust its range
- so that it will map to the data scrolling in the client window.
-
- An application can use scroll bars as stand-alone controls in any size or
- shape, at any position, in any sort of window. Scroll bars can be used as
- parts of other controls──for example, list-box controls use a scroll bar
- to let the user view items when the list box is too small to display all
- the items.
-
- 16.2.1 Scroll-Bar Creation
-
- An application creates a scroll bar by using the preregistered window
- class WC_SCROLLBAR. The application can create a scroll bar by using the
- WinCreateWindow function. There are two scroll-bar styles: SBS_HORZ and
- SBS_VERT. The style SBS_HORZ creates a horizontal scroll bar; SBS_VERT
- creates a vertical scroll bar. Although most applications specify an owner
- when creating a scroll bar, an owner is not required. If no owner is
- specified, the scroll bar does not send notification messages. An
- application can retrieve the scroll bar's current slider position by
- sending the SBM_QUERYPOS message to the scroll bar.
-
- An application can specify class-specific data when creating a scroll bar.
- The SBCDATA structure specifies the initial range and slider position for
- the scroll bar.
-
- If a scroll bar is a descendant of a frame window, its position relative
- to the parent window may change when the frame window's position changes.
- Frame windows draw scroll bars relative to the upper-left corner of the
- frame window (rather than the lower-left corner). The frame window may
- adjust the y-coordinate of the scroll-bar position. This is desirable when
- the scroll bar is an immediate child window of the frame window, but may
- be undesirable if the scroll bar is not an immediate child window.
-
- 16.2.2 Scroll-Bar Range and Position
-
- Every scroll bar has a range and a slider position. The range specifies
- the maximum and minimum values for the slider position. As the user moves
- the slider in the scroll bar, its position is reported as an integer value
- in the range. If the slider position is the minimum value, the slider is
- at the top of a vertical scroll bar or at the left end of a horizontal
- scroll bar. If the slider position is the maximum value, the slider is at
- the bottom or right end of the vertical or horizontal scroll bar,
- respectively.
-
- An application can adjust the range to convenient integer values by using
- the SBM_SETSCROLLBAR message (or initially, by using the SBCDATA
- structure). This makes it easy to translate the slider position to a value
- that corresponds to the data being scrolled. For example, an application
- that has 260 lines of text to display in a window that can show only 16
- lines at a time can set the vertical scroll-bar range to 1 through 244.
- When the slider is at position 1, the first line is at the top of the
- window. When the slider is at position 244, the last line is at the bottom
- of the window.
-
- To keep the scroll-bar range in useful relationship with the data, an
- application must adjust the range whenever the data or the size of the
- window changes. This means an application should adjust the range as part
- of processing WM_SIZE messages.
-
- An application must move the slider in the scroll bar. Although the user
- makes a request for scrolling in the scroll bar, the scroll bar does not
- update the slider position. Instead, it passes the request to the owner
- window. The owner window must scroll the data and update the slider
- position by using the SBM_SETPOS message. Because the application controls
- the slider movement, it can move the slider in increments that work best
- for the data being scrolled.
-
- 16.2.3 Scroll-Bar Notification Messages
-
- The scroll bar sends notification messages to the scroll-bar owner
- whenever the user clicks the scroll bar. The WM_VSCROLL and WM_HSCROLL
- messages are the notification messages for vertical and horizontal scroll
- bars, respectively. If the scroll bar is a frame-control window, the
- message is passed by the frame window to the client window.
-
- Each notification message includes the scroll-bar identifier, the specific
- scroll-bar command code that corresponds to the user's action, and, in
- some cases, the current position of the slider. If a scroll bar is created
- as part of a frame-control window, the scroll-bar identifier is one of the
- predefined constants FID_VERTSCROLL or FID_HORZSCROLL. Otherwise, it is
- the identifier given in the WinCreateWindow function.
-
- The scroll-bar command codes specify the action the user has taken. The
- code specifies where the user has clicked the mouse. MS OS/2
- user-interface guidelines recommend certain responses for each action. The
- following is a list of the command codes and the recommended responses. In
- each case, a "unit" is defined by the application and should be
- appropriate for the given data. For example, when scrolling text
- vertically, the unit is typically a line.
-
- ╓┌─┌───────────────────┌─────────────────────────────────────────────────────╖
- Command code Description
- ──────────────────────────────────────────────────────────────────────────
- SB_LINEUP User clicked the top scroll arrow. Decrement the
- slider position by one and scroll toward the top of
- the data by one unit.
-
- SB_LINEDOWN User clicked the bottom scroll arrow. Increment the
- slider position by one and scroll toward the bottom of
- the data by one unit.
-
- SB_LINELEFT User clicked the left scroll arrow. Decrement the
- Command code Description
- ──────────────────────────────────────────────────────────────────────────
- SB_LINELEFT User clicked the left scroll arrow. Decrement the
- slider position by one and scroll toward the left end
- of the data by one unit.
-
- SB_LINERIGHT User clicked the right scroll arrow. Increment the
- slider position by one and scroll toward the right end
- of the data one unit.
-
- SB_PAGEUP User clicked the scroll-bar background above the
- slider. Decrement the slider position by the number of
- data units in the window and scroll toward the top of
- the data by the same number of units.
-
- SB_PAGEDOWN User clicked the scroll-bar background below the
- slider. Increment the slider position by the number of
- data units in the window and scroll toward the bottom
- of the data by the same number of units.
-
- SB_PAGELEFT User clicked the scroll-bar background to the left of
- Command code Description
- ──────────────────────────────────────────────────────────────────────────
- SB_PAGELEFT User clicked the scroll-bar background to the left of
- the slider. Decrement the slider position by the
- number of data units in the window and scroll toward
- the left end of the data by the same number of units.
-
- SB_PAGERIGHT User clicked the scroll-bar background to the right of
- the slider. Increment the slider position by the
- number of data units in the window and scroll toward
- the right end of the data by the same number of units.
-
- SB_SLIDERTRACK User is dragging the slider. Applications that draw
- data quickly can set the slider to the position given
- in the message and scroll the data by the same number
- of units the slider has moved. Applications that can-
- not draw data quickly should wait for the
- SB_SLIDERPOSITION code before moving the slider and
- scrolling the data.
-
- SB_SLIDERPOSITION User released the slider after dragging it. Set the
- Command code Description
- ──────────────────────────────────────────────────────────────────────────
- SB_SLIDERPOSITION User released the slider after dragging it. Set the
- slider to the position given in the message and scroll
- the data by the same number of units the slider has
- moved.
-
- SB_ENDSCROLL User released the mouse after holding it on an arrow
- or in the scroll-bar background. No action is
- necessary.
- ──────────────────────────────────────────────────────────────────────────
-
-
- If the scroll-bar command code is either SB_SLIDERPOSITION or
- SB_SLIDERTRACK, indicating that the user is moving the scroll-bar slider,
- the notification message also contains the current position of the slider.
-
- The owner window can send a message to the scroll bar to read its current
- value and range or to reset its current value. The owner window can adjust
- data controlled by the scroll bar to reflect any changes in the state of
- the scroll bar.
-
- An application can disable a scroll bar by using the WinEnableWindow
- function. A disabled scroll-bar window ignores the user's actions, sending
- out no notification messages when the user tries to manipulate it. If an
- application has no data to scroll or all data fits in the client window,
- it should disable the scroll bar.
-
- Scroll bars have their own system color, SYSLR_SCROLLBAR. This color is
- used to paint the scroll-bar background. Other system colors are used in
- other parts of the scroll bar.
-
- 16.2.4 Scroll Bars and the Keyboard
-
- When a scroll bar has the keyboard focus, it generates notification
- messages for the following keys:
-
- Key Command code
- ──────────────────────────────────────────────────────────────────────────
- UP SB_LINEUP or SB_LINELEFT
-
- LEFT SB_LINEUP or SB_LINELEFT
-
- DOWN SB_LINEDOWN or SB_LINERIGHT
-
- RIGHT SB_LINEDOWN or SB_LINERIGHT
-
- PAGE UP SB_PAGEUP or SB_PAGELEFT
-
- PAGE DOWN SB_PAGEDOWN or SB_PAGERIGHT
- ──────────────────────────────────────────────────────────────────────────
-
- If an application uses scroll bars to scroll data but does not give the
- scroll bar the input focus, the window with the focus should process
- keyboard input itself. The window can generate scroll-bar notification
- messages or carry out the indicated scrolling. The following list gives
- the keys a window should process and what action to take for each:
-
- ╓┌─┌───────────────────────┌─────────────────────────────────────────────────╖
- Key Command
- ──────────────────────────────────────────────────────────────────────────
- UP SB_LINEUP
-
- Key Command
- ──────────────────────────────────────────────────────────────────────────
- DOWN SB_LINEDOWN
-
- PAGE UP SB_PAGEUP
-
- PAGE DOWN SB_PAGEDOWN
-
- CONTROL+HOME SB_SLIDERTRACK with slider set to minimum position
-
- CONTROL+END SB_SLIDERTRACK with slider set to maximum position
-
- LEFT SB_LINELEFT
-
- RIGHT SB_LINERIGHT
-
- CONTROL+PAGE UP SB_PAGELEFT
-
- CONTROL+PAGE DOWN SB_PAGERIGHT
-
- Key Command
- ──────────────────────────────────────────────────────────────────────────
- HOME SB_SLIDERTRACK with slider set to minimum position
-
- END SB_SLIDERTRACK with slider set to maximum position
- ──────────────────────────────────────────────────────────────────────────
-
-
- Vertical scroll bars that are part of list boxes have the following
- keyboard interface:
-
- Key Command
- ──────────────────────────────────────────────────────────────────────────
- CONTROL+UP SB_SLIDERTRACK with slider set to minimum position
-
- CONTROL+DOWN SB_SLIDERTRACK with slider set to maximum position
-
- F7 SB_PAGEUP
-
- F8 SB_PAGEDOWN
- ──────────────────────────────────────────────────────────────────────────
-
- The application must implement the suggested scroll-bar/keyboard
- interface. This can be accomplished by appropriate handling of WM_CHAR
- messages.
-
-
- 16.3 Using Scroll Bars
-
- This section explains how to create and use scroll bars in an application.
- Scroll bars are most often used in frame windows to let the user scroll
- data in the corresponding client window.
-
- 16.3.1 Creating Scroll Bars
-
- You can add scroll bars to a frame window by using the FCF_HORZSCROLL
- flag, the FCF_VERTSCROLL flag, or both flags when creating the frame
- window with the WinCreateStdWindow function. This adds a horizontal and/or
- a vertical scroll bar to the frame window. Because the frame window owns
- the scroll bars, it passes notification messages from these controls to
- the client window.
-
- The following code fragment adds scroll bars to a frame window:
-
- /* Set flags for a main window with scroll bars. */
-
- ULONG ulFrameControlFlags =
- FCF_STANDARD | FCF_HORZSCROLL | FCF_VERTSCROLL;
-
- /* Create the window. */
-
- hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE,
- &ulFrameControlFlags, szClientClass, szFrameTitle,
- 0L, NULL, 0L, &hwndClient);
-
- Scroll bars created this way have the window identifier FID_HORZSCROLL or
- FID_VERTSCROLL. The frame window determines the size and position of the
- scroll bars. A frame window uses the standard size specified by the system
- values SV_CXVSCROLL and SV_CYHSCROLL. The position is always the right and
- bottom edges of the frame window.
-
- Another way to create scroll bars is by using the WinCreateWindow
- function. This is most common for stand-alone scroll bars. Creating scroll
- bars in this way lets you set the size and position of the scroll bars.
- You can also specify the window to receive notification messages.
-
- The following code fragment creates a stand-alone scroll bar:
-
- HWND hwndScroll; /* scroll-bar handle */
-
- hwndScroll = WinCreateWindow(
- hwndClient /* scroll-bar parent */
- WC_SCROLLBAR, /* preregistered scroll-bar class */
- NULL, /* no window title */
- SBS_VERT | WS_VISIBLE, /* vertical style and visible */
- 10, 10, /* position */
- 20, 100, /* size */
- hwndClient, /* owner */
- HWND_TOP, /* Z-order position */
- 1, /* scroll-bar ID */
- NULL, /* no class-specific data */
- NULL); /* no presentation parameters */
-
- 16.3.2 Retrieving a Scroll-Bar Handle
-
- If you create a scroll bar as a child window of the frame window by using
- the WinCreateStdWindow function, you need a way to retrieve the scroll-bar
- handle. One way is to use the WinWindowFromID function, the frame-window
- handle, and a predefined identifier (such as FID_HORZSCROLL or
- FID_VERTSCROLL) to retrieve the scroll-bar handle:
-
- hwndHorzScroll = WinWindowFromID(hwndFrame, FID_HORZSCROLL);
- hwndVertScroll = WinWindowFromID(hwndFrame, FID_VERTSCROLL);
-
- If the standard frame window includes a client window, you can use that
- handle to access the scroll bars. The idea is to retrieve the frame-window
- handle first, then the scroll-bar handle. This is illustrated by the
- following code fragment:
-
- /* Get a handle to the horizontal scroll bar. */
-
- hwndScroll = WinWindowFromID(
- WinQueryWindow(hwndClient, QW_PARENT, FALSE),
- FID_HORZSCROLL);
-
- 16.3.3 Using the Scroll-Bar Range and Position
-
- You can initialize a scroll bar's current value and range to nondefault
- values by sending the SBCDATA structure with class-specific data for a
- call to the WinCreateWindow function:
-
- SBCDATA sbcd;
-
- /* Set up scroll-bar control data. */
-
- sbcd.posFirst = 200;
- sbcd.posLast = 400;
- sbcd.posThumb = 300;
-
- /* Create the scroll bar. */
-
- hwndScroll = WinCreateWindow(hwndClient, WC_SCROLLBAR, NULL,
- SBS_VERT | WS_VISIBLE,
- 10, 10, 20, 100,
- hwndClient, HWND_TOP, 1,
- &sbcd, /* class-specific data */
- NULL);
-
- You can adjust a scroll-bar value and range by sending it an
- SBM_SETSCROLLBAR message:
-
- /* Set the scroll-bar value and range. */
-
- WinSendMsg(hwndScroll, SBM_SETSCROLLBAR,
- MPFROM2SHORT(300, 0),
- MPFROM2SHORT(200, 400));
-
- You can read a scroll-bar value by sending it an SBM_QUERYPOS message:
-
- USHORT usSliderPos;
-
- /* Read the scroll-bar value. */
-
- usSliderPos = (USHORT) WinSendMsg(hwndScroll,
- SBM_QUERYPOS, NULL, NULL);
-
- Similarly, you can set a scroll-bar value by sending an SBM_SETPOS
- message:
-
- /* Set the vertical scroll-bar value. */
-
- WinSendMsg(hwndScroll, SBM_QUERYPOS, MPFROM2SHORT(300, 0), NULL);
-
- You can read a scroll-bar range by sending it an SBM_QUERYRANGE message:
-
- MRESULT mr;
- USHORT iMinimum, iMaximum;
-
- /* Read the vertical scroll-bar range. */
-
- mr = WinSendMsg(hwndScroll, SBM_QUERYRANGE, NULL, NULL);
-
- iMinimum = SHORT1FROMMR(mr); /* minimum in the low word */
- iMaximum = SHORT2FROMMR(mr); /* maximum in the high word */
-
-
- 16.4 Summary
-
- This section lists the messages and system values that applications use to
- create and control scroll-bar control windows.
-
- 16.4.1 Messages
-
- Applications use the following messages to create and control scroll bars:
-
- SBM_QUERYHILITE Sent to a scroll bar to obtain its highlight state.
-
- SBM_QUERYPOS Sent to a scroll bar to obtain the current value of the
- scroll bar.
-
- SBM_QUERYRANGE Sent to a scroll bar to obtain the scroll-bar range.
-
- SBM_SETHILITE Sent to a scroll bar to set the highlight state.
-
- SBM_SETPOS Sent to a scroll bar to set the current value of the scroll
- bar.
-
- SBM_SETSCROLLBAR Sent to a scroll bar to set the current value and range.
-
- WM_HSCROLL Sent by a horizontal scroll bar to its owner window when the
- user changes the state of the scroll bar. The high word of the second
- parameter (mp2) contains a scroll-bar command code.
-
- WM_VSCROLL Sent by a vertical scroll bar to its owner window when the
- user changes the state of the scroll bar. The high word of the second
- parameter (mp2) contains a scroll-bar command code.
-
- 16.4.2 System Values
-
- Applications use the following system values to create and control scroll
- bars:
-
- SV_CXHSCROLLARROW Width (in pels) of the scroll-arrow area in a
- horizontal scroll bar.
-
- SV_CXVSCROLL Width (in pels) of a standard vertical scroll bar.
-
- SV_CYHSCROLL Height (in pels) of a standard horizontal scroll bar.
-
- SV_CYVSCROLLARROW Height (in pels) of the scroll-arrow area in a vertical
- scroll bar.
-
- SV_FIRSTSCROLLRATE Initial rate at which a scroll bar sends notification
- messages when the user clicks the scroll arrows or scroll-bar background.
-
- SV_SCROLLRATE Similar to SV_FIRSTSCROLLRATE, this is the rate at which
- the scroll bar sends messages.
-
- SYSCLR_SCROLLBAR Color for drawing scroll-bar backgrounds.
-
- TID_SCROLL Timer ID for a reserved scrolling timer. This timer is used
- for sending notification messages when a scroll arrow or scroll-bar
- background is clicked.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 17 Menus
-
- 17.1 Introduction
- 17.2 About Menus
- 17.2.1 Menu-Bar and Pull-Down Menus
- 17.2.2 System Menu
- 17.2.3 Menu-Item Styles
- 17.2.4 Menu-Item Attributes
- 17.3 Defining Menu Items in a Resource File
- 17.4 Menu Data Structures
- 17.4.1 Menu Template
- 17.5 Using Menus in your Applications
- 17.5.1 Including a Menu in a Standard Window
- 17.5.2 Adding Menus to a Dialog Window
- 17.5.3 Accessing the System Menu
- 17.5.4 Responding to a User's Menu Choice
- 17.5.5 Using Menus with the Keyboard
- 17.5.6 Using Keyboard Accelerators
- 17.5.7 Help Item in the Menu Bar
- 17.5.8 Setting and Querying Menu-Item Attributes
- 17.5.9 Setting and Querying Menu-Item Contents
- 17.5.10 Adding and Deleting Menu Items
- 17.5.11 Owner-Drawn Menu Items
- 17.6 Summary
- 17.6.1 Menu-Item Styles
- 17.6.2 Menu-Item Attributes
- 17.6.3 Menu Functions
- 17.6.4 Messages Sent from a Menu to an Owner Window
- 17.6.5 Messages Sent to a Menu
-
- 17.1 Introduction
-
- This chapter describes how to use menus in your applications. You should
- also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Accelerator tables
-
- ■ Creating standard frame windows
-
- ■ Window messages and message queues
-
-
- 17.2 About Menus
-
- Menus are windows that contain a list of items. These items can be text
- strings, bitmaps, or images drawn by the application. Menus allow the user
- to use the mouse or keyboard to choose from a predetermined list of
- choices. When a user makes a choice from a menu, the menu posts a message
- containing the item's unique menu-item identifier to the menu's owner
- window.
-
- Typically, an application defines its menus by using Resource Compiler and
- associates the menus with an frame window when the window is created.
- Applications can also create menus by filling in menu-template data
- structures and then creating windows with the WC_MENU class. Either way,
- applications can dynamically add, delete, or change menu items by sending
- messages to menu windows.
-
- Menu windows are always owned by another window; this is important because
- a menu sends messages to its owner whenever a menu item is highlighted or
- chosen by the user. Owner windows send messages to menus to add, delete,
- or change menu items.
-
- 17.2.1 Menu-Bar and Pull-Down Menus
-
- Typically, an application uses a menu-bar menu and several pull-down
- submenus. The menu bar is a child window in the parent window frame. The
- submenus are normally hidden and become visible when the user makes
- selections in the menu bar. Figure 17.1 shows a typical menu-bar and
- submenu layout in a standard frame window:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 17.1 can be found in Section 17.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 17.1 Menu-Bar and Pull-Down Menus
-
- There are two main types of menu items: command items and submenu items.
- When the user chooses a command item, a command message is immediately
- posted to the parent window. When the user selects a submenu item, a
- pull-down menu is displayed from which the user may choose another command
- item. Since a pull-down menu window can also contain a submenu item,
- pull-down menus can originate from other pull-down menus. An item in the
- menu bar may be a command item or a submenu item.
-
- When a command item is selected, either from the menu bar or from a
- pull-down menu, the menu system posts a WM_COMMAND, WM_HELP, or
- WM_SYSCOMMAND message to the owner window, depending on the menu item's
- style bits.
-
- The menu bar is a child window of the frame window; the menu-bar window
- handle is the key to communicating with menus. The handle of the menu-bar
- window can be obtained by calling the WinWindowFromID function with the
- handle of the parent window and the FID_MENU frame-control identifier.
- Most messages for menus and submenus can be sent to the menu-bar window.
- Flags in the messages tell the window whether to search submenus for
- requested menu items.
-
- 17.2.2 System Menu
-
- The System menu in the upper-left corner of a standard frame window is
- different from the menu-bar and pull-down menus defined by the
- application. The System menu is controlled and defined almost exclusively
- by the system. Your only decision about the System menu is whether or not
- to include it when creating a frame window. (It is unusual for a frame
- window not to include a System menu.) The System menu generates
- WM_SYSCOMMAND messages instead of WM_COMMAND messages. Most applications
- simply allow the default behavior for WM_SYSCOMMAND messages. If
- necessary, you can obtain the handle of the System menu by calling the
- WinWindowFromID function with the handle of the parent (frame) window and
- the FID_SYSMENU frame-control identifier. The application can add, delete,
- and change System-menu entries.
-
- 17.2.3 Menu-Item Styles
-
- All menu items have a combination of style bits that determine what kind
- of data the item contains and what kind of message it generates when it is
- chosen by the user. For instance, a menu item can have the MIS_TEXT,
- MIS_BITMAP, or other styles, specifying what kind of display object
- visually represents the menu item on the screen. Other styles determine
- what kinds of messages the item sends to its owner window and whether the
- owner window draws the item. Menu-item styles typically do not change
- during program execution, but they can be queried and set by sending
- MM_SETITEM and MM_QUERYITEM messages to the menu with the identifier of
- the item. The possible menu-item styles are described in Section 17.6.1.
-
- 17.2.4 Menu-Item Attributes
-
- Menu items have attributes that determine how they are displayed and
- whether or not the user can choose them. Menu-item attributes can be set
- and queried by sending MM_SETITEMATTR and MM_QUERYITEMATTR messages with
- the identifier of the item to the menu-bar menu window. If the specified
- item is in a submenu, you must set a flag in the message so that submenus
- are searched for the item. The possible attributes of a menu item are
- listed in Section 17.6.2.
-
-
- 17.3 Defining Menu Items in a Resource File
-
- A menu resource consists of command items and submenu items. One menu
- resource typically represents the menu bar and all its submenus. An
- application can specify the identifier of the menu resource when creating
- a standard window, or it can load the menu resource directly by using the
- WinLoadMenu function. A menu-item definition is organized as follows:
-
- MENUITEM item text, item identifier, item style, item attributes
-
- The menu resource-definition file specifies the text of each item in the
- menu, unique identifier, its style and its attributes, and whether it is a
- command item or a submenu item. Following is sample source code that
- defines a menu resource for Resource Compiler. The code defines a menu
- with three submenu items in the menu bar (File, Edit, and Fonts) and a
- command item (Help). Each submenu has several command items, and the Fonts
- submenu has two other submenus within it.
-
- MENU ID_MENU_RESOURCE
- BEGIN
- SUBMENU "~File", IDM_FILE
- BEGIN
- MENUITEM "~Open...", IDM_FI_OPEN
- MENUITEM "~Close\tF3", IDM_FI_CLOSE, MIS_DISABLED
- MENUITEM "~Quit", IDM_FI_QUIT
- MENUITEM "", IDM_FI_SEP1, MIS_SEPARATOR
- MENUITEM "~About Sample", IDM_FI_ABOUT
- END
- SUBMENU "~Edit", IDM_EDIT
- BEGIN
- MENUITEM "~Undo", IDM_ED_UNDO, 0, MIA_DISABLED
- MENUITEM "", IDM_ED_SEP1, MIS_SEPARATOR
- MENUITEM "~Cut", IDM_ED_CUT
- MENUITEM "C~opy", IDM_ED_COPY
- MENUITEM "~Paste", IDM_ED_PASTE
- MENUITEM "C~lear", IDM_ED_CLEAR
- END
- SUBMENU "Font", IDM_FONT
- BEGIN
- SUBMENU "Style", IDM_FONT_STYLE
- BEGIN
- MENUITEM "Plain", IDM_FONT_STYLE_PLAIN
- MENUITEM "Bold", IDM_FONT_STYLE_BOLD
- MENUITEM "Italic", IDM_FONT_STYLE_ITALIC
- END
- SUBMENU "Size", IDM_FONT_SIZE
- BEGIN
- MENUITEM "10", IDM_FONT_SIZE_10
- MENUITEM "12", IDM_FONT_SIZE_12
- MENUITEM "14", IDM_FONT_SIZE_14
- END
- END
- MENUITEM "F1=Help", 0x00, MIS_TEXT | MIS_BUTTONSEPARATOR | MIS_HELP
- END
-
- Figure 17.2 shows how the submenus within a Delete submenu are displayed.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 17.2 can be found in Section 17.3 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 17.2 Submenus
-
- You can indicate a mnemonic keystroke for the menu item by preceding that
- character in the item text with a tilde, as in "~File". The user can
- choose that item by pressing the mnemonic key when the menu is active.
- (The menu bar is active when the user presses and releases the ALT key,
- and the first item in the menu bar is highlighted. A pull-down menu is
- active when it is open.)
-
- In addition to mnemonics, a menu item can have an associated keyboard
- accelerator. Accelerators are different from mnemonics, in that the menu
- does not have to be active for the accelerator key to work. If a menu item
- has a keyboard accelerator associated with it, the corresponding menu item
- should display the accelerator to the right of the menu item. This is done
- by placing a tab character (\t) in the menu text before the characters
- that should be displayed on the right. For example, if the Close item had
- the F3 function key as its keyboard accelerator, the text for the item
- would be "Close\tF3". For more information on accelerators, see Section
- 17.5.6.
-
- Each entry that defines a menu item specifies the text for the item, its
- identifier, and the style and attributes of the item. A menu item that has
- no specification for style or attributes has the default style of MIS_TEXT
- and all attribute bits off, indicating that the item is enabled. The
- MIS_SEPARATOR style identifies nonselectable lines between menu items.
-
- To define a menu item with the MIS_BITMAP style, an application should use
- a tool such as Icon Editor to create a bitmap, include the bitmap in the
- application's resource-definition file, and define a menu in the file (as
- shown in the following code fragment). The text for the bitmap menu items
- is an ASCII representation of the resource identifier of the bitmap
- resource to be displayed for that item.
-
- /* Bring externally created bitmaps into the resource file. */
-
- BITMAP 101 button.bmp
- BITMAP 102 hirest.bmp
- BITMAP 103 hizoom.bmp
- BITMAP 104 hired.bmp
-
- /* Connect a menu item with a bitmap. */
-
- SUBMENU "~Bitmaps", IDM_BITMAP
- BEGIN
- MENUITEM "#101", IDM_BM_01, MIS_BITMAP
- MENUITEM "#102", IDM_BM_02, MIS_BITMAP
- MENUITEM "#103", IDM_BM_03, MIS_BITMAP
- MENUITEM "#104", IDM_BM_04, MIS_BITMAP
- END
-
-
-
- 17.4 Menu Data Structures
-
- There are two main data structures that define the contents of a menu: the
- menu-item structure and the menu-template structure. The menu-item
- structure defines a single menu item, and the menu-template structure
- contains all the menu items that make up a menu resource, including the
- menu bar and all its pull-down menus.
-
- A single menu item is defined by the MENUITEM data structure. This data
- structure is used with the MM_INSERTITEM message to insert items into a
- menu, or to query and set item characteristics with the MM_QUERYITEM and
- MM_SETITEM messages. The MENUITEM data structure has the following form:
-
- typedef struct _MENUITEM {
- SHORT iPosition;
- USHORT afStyle;
- USHORT afAttribute;
- USHORT id;
- HWND hwndSubMenu;
- ULONG hItem;
- } MENUITEM;
-
- The values of most of the fields in the data structure can be derived
- directly from the resource-definition file shown in Section 17.3. The
- last field in the structure, hItem, depends on the style of the menu item.
-
- The iPosition field specifies the ordinal position of the item within its
- menu window. If the item is part of the menu bar, iPosition gives its
- relative left-to-right position, with zero being the leftmost item. If the
- item is part of a submenu, iPosition gives its relative top-to-bottom and
- left-to-right position, with zero being the upper-left item. An item with
- the MIS_BREAKSEPARATOR style in a pull-down menu will cause a new column
- to begin.
-
- The afStyle field contains the style bits of the item. The afAttribute
- field contains the attribute bits.
-
- The id field contains the identifier for the menu item. The identifier
- should be unique but does not have to be. When multiple items have the
- same identifier, they post the same command number in the WM_COMMAND,
- WM_HELP, and WM_SYSCOMMAND messages. Also, any message that specifies a
- menu item with a nonunique identifier will find the first item that has
- that identifier.
-
- The hwndSubMenu field contains the window handle of a pull-down menu
- window (if the item is a submenu item). The hwndSubMenu field is NULL for
- command items.
-
- The hItem field contains a handle to the display object for the item,
- unless the item has the MIS_TEXT style, in which case hItem is NULL. For
- example, a menu item with the MIS_BITMAP style has an hItem field that is
- equal to its bitmap handle.
-
- 17.4.1 Menu Template
-
- A menu template is a variable-length data structure that represents the
- entire menu, including all items and submenus. A menu template is made up
- of a series of variable-length records. Each record represents a single
- menu item. If the item is a submenu, the template that describes the
- submenu is nested after the submenu item record.
-
- The menu template is a representation of the menu as it is defined in the
- resource-definition file. Typically, applications require information
- about the internal structure of a menu template only when creating a menu
- template without using a resource-definition file.
-
- A template is defined as shown in the following code fragment:
-
- typedef struct _MT {
- USHORT cb; /* length of template in bytes */
- USHORT version; /* version; set to zero */
- USHORT codepage; /* code page */
- USHORT iInputsize; /* length of input field for host terminals */
- USHORT cMti; /* count of items */
- MTI rgMti(cMti);
- } MT;
-
- MS OS/2 version 1.1 sets the version, code-page, and input-size fields to
- zero, and ignores the contents of these fields if set by an application.
- The cMti field specifies the number of menu-template items that follow.
- Each menu-template item describes one item in the menu. Since each menu
- item can require a different amount of storage, the following variable
- definition of a menu-template item is used:
-
- typedef struct _MTI {
- USHORT afStyle;
- USHORT afAttribute;
- USHORT idItem;
- if (afStyle AND MIS_BITMAP)
- CHAR szItemString ? ;
- if (afStyle AND MIS_OWNERDRAW)
- VOID;
- if (afStyle AND MIS_TEXT)
- CHAR szItemString ? ;
- if (aStyle AND MIS_SEPARATOR)
- VOID;
- if (afStyle AND MIS_SUBMENU)
- MT MenuTemplate;
- } MTI;
-
- The first three fields of a structure for a menu-template item specify the
- style, attributes, and identifier of the item. The data that follows these
- fields is determined by the style of the item. The cases can be summarized
- as follows:
-
- If the afStyle field is MIS_TEXT, the data that follows the idItem field
- is a null-terminated string representing the menu-item text.
-
- If the afStyle field is MIS_BITMAP, the data that follows idItem is a
- null-terminated string that can represent one of three things:
-
- ■ If the first byte is NULL, then no bitmap resource is defined; the
- application provides a bitmap handle for the item.
-
- ■ If the first byte is "#", subsequent characters make up the decimal
- representation of the bitmap resource-identifier.
-
- ■ If neither of the previous cases apply, the handle is set to NULL, and
- the application must set it manually.
-
- If the afStyle field is MIS_OWNERDRAW or MIS_SEPARATOR, there is no data
- following the idItem field.
-
- If the afStyle field is MIS_SUBMENU, a complete menu-template structure
- for the submenu follows the idItem field.
-
-
- 17.5 Using Menus in your Applications
-
- Typically, an application that uses menus defines them in a
- resource-definition file and includes them in a standard frame window.
- During program execution, the application's window procedure receives
- messages generated by the menu windows in response to user input, either
- from the mouse or the keyboard. The application responds to these messages
- by using the identifier of the menu item that is contained in each menu
- message. The application can also load menu resources at run time and
- associate them with a particular owner window. This is useful for putting
- menus in windows other than the standard frame window.
-
- The user-interface guidelines specify that a user should not be required
- to have a mouse to operate an MS OS/2 application. Applications can define
- keyboard equivalents to menu items to aid users without mice.
-
- It is also suggested that all applications have a Help item in their menu
- bar. This presents a standard interface for the novice user across all
- applications. The Help item is defined with a particular style,
- attributes, and position in the menu, as shown in the resource-definition
- file in Section 17.3. The Help command item generates a WM_HELP message
- when chosen by the user, allowing the application to respond
- appropriately. For more information on the help system, see Chapter 29,
- "Help."
-
- Applications can change the attributes, style, and contents of menu items,
- and insert and delete items at run time, to reflect changes in the command
- environment. An application can also add or delete items from the menu bar
- or submenus. For example, an application might maintain a menu of the
- currently available fonts in the system. This application would use Gpi
- calls to determine which fonts were available, and then insert a menu item
- for each font into a submenu. Furthermore, the application might set the
- "checked" attribute of the menu item for the currently chosen font. When
- the user chooses a new font, the application would remove the check-mark
- attribute from the previous choice and add it to the new choice.
-
- An application can also draw a menu item itself by setting the attribute
- MIS_OWNERDRAW for the menu item. Typically, this is done by specifying the
- MIS_OWNERDRAW attribute for the menu item in the resource-definition file,
- but it can also be done at run time. When the application draws a menu
- item, it must respond to messages from the menu each time the item needs
- to be drawn.
-
- 17.5.1 Including a Menu in a Standard Window
-
- If you have defined a menu resource in a resource-definition file, you can
- include the menu in a standard window. You include the menu by using the
- FCF_MENU attribute flag and specifying the menu resource identifier in a
- call to the WinCreateStdWindow function, as shown in the following code
- fragment:
-
- ULONG lControlStyle = FCF_MENU | FCF_SIZEBORDER |
- FCF_TITLEBAR | FCF_ACCELTABLE;
-
- hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
- WS_VISIBLE,
- &lControlStyle,
- szClassName,
- szClassName,
- 0L, NULL,
- ID_MENU_RESOURCE,
- &hwndClient);
-
- After you make this call, MS OS/2 automatically includes the menu in the
- window, drawing the menu bar across the top of the window. When the user
- chooses an item from the menu, the menu posts the message to the frame
- window. The frame window passes any WM_COMMAND messages to the client
- window. (The frame window does not pass WM_SYSCOMMAND messages to the
- client window.) WM_HELP messages are posted to the focus window. The
- WinDefWindowProc function passes WM_HELP messages to the parent window. If
- a WM_HELP message is passed to a frame window, the frame window calls the
- HK_HELP hook. Your client window procedure should process these messages
- to respond to the user's actions. The details of responding to menu
- selections are shown in Section 17.5.4.
-
- 17.5.2 Adding Menus to a Dialog Window
-
- You may want to use menus in windows that were not created by using the
- WinCreateStdWindow function. For these windows, you can load a menu
- resource by using the WinLoadMenu function and specify the parent window
- for the menu. WinLoadMenu assigns the specified menu resource to the
- parent window. To see the menu in the window, you must send a
- WM_UPDATEFRAME message to the parent window after loading the menu
- resource. This strategy is especially useful for adding menus to a window
- created as a dialog window, but it can be used no matter what type of
- window is specified as the parent window.
-
- 17.5.3 Accessing the System Menu
-
- Although most applications do not alter the System menu, you can obtain
- the handle of the System menu by calling the WinWindowFromID function with
- a frame-window handle (or dialog-window handle) and the FID_SYSMENU
- identifier. Once you have the handle of the System menu, you can access
- the individual menu items by using predefined constants. For example, the
- following code fragment shows how to disable the Close menu item in the
- System menu of a window:
-
- HWND hwndSysMenu;
-
- hwndSysMenu = WinWindowFromID(hwndFrame, FID_SYSMENU);
-
- WinSendMsg(hwndSysMenu, MM_SETITEMATTR,
- MPFROM2SHORT(SC_CLOSE, TRUE),
- MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
-
- 17.5.4 Responding to a User's Menu Choice
-
- When a user chooses a menu, item your client window procedure receives a
- WM_COMMAND message with the low word of the mp1 parameter equal to
- the menu identifier of the selected item. Your application should use the
- menu identifier to guide its response to the selection. Typically, the
- code in the client window procedure resembles the following code fragment:
-
- case WM_COMMAND:
- DoMenuCommand(hwnd, LOUSHORT(mp1));
- return 0;
-
- The function that translates the menu identifier into an action typically
- resembles the following code fragment:
-
- VOID DoMenuCommand(hwnd, usItemID)
- HWND hwnd;
- USHORT usItemID;
- {
-
- /* Test the menu item. */
-
- switch (usItemID) {
- case IDM_FI_NEW:
- DoNew(hwnd);
- break;
- .
- .
- .
- }
- }
-
- The menu system sends a WM_MENUSELECT message every time the menu
- selection changes. The low word of the mp1 parameter contains the
- identifier of the item that is changing state and the high word is a 6-bit
- Boolean value that describes whether or not the item is chosen; the mp2
- parameter contains the handle of the menu.
-
- If the Boolean value is FALSE, the item is selected but not chosen──for
- example, the user may have moved the cursor or mouse pointer over the item
- while the button was down. An application can use this message to display
- help information at the bottom of the application window. The return value
- is ignored.
-
- If the Boolean value is TRUE, the item is chosen──that is, the user
- pressed ENTER or released the mouse button when an item was selected. If
- the application returns FALSE, the menu does not generate a WM_COMMAND,
- WM_SYSCOMMAND, or WM_HELP message, and the menu is not dismissed.
-
- 17.5.5 Using Menus with the Keyboard
-
- MS OS/2 is designed to work with or without a mouse or other pointing
- device. The system provides default behavior to allow a user to interact
- with menus without using a mouse. The following are the keystrokes that
- produce this default behavior:
-
- ╓┌─┌─────────────────┌───────────────────────────────────────────────────────╖
- Keystroke Action
- ──────────────────────────────────────────────────────────────────────────
- ALT Toggles into and out of menu mode.
-
- ALT, SPACEBAR Shows the System menu.
-
- Keystroke Action
- ──────────────────────────────────────────────────────────────────────────
- ESC Backs up one level. If a pull-down menu is displayed, it
- is canceled. If no pull-down menu is displayed, this
- keystroke exits from menu mode.
-
- RIGHT Cycles to the next menu-bar item. If the selected item
- is at the far-left side of the menu bar, the menu code
- sends a WM_NEXTMENU message to the frame. The default
- processing by the frame is to cycle between the
- application and System menus. (An application can modify
- this behavior by subclassing the frame window.) If the
- selected item is in a pull-down menu, the next column in
- the pull-down menu is selected or the next menu-bar item
- is selected; this key may also send or process a
- WM_NEXTMENU message.
-
- LEFT Works like the RIGHT key, except in the opposite
- direction. In pull-down menus, this keystroke backs up
- one column, except when the currently selected item is
- Keystroke Action
- ──────────────────────────────────────────────────────────────────────────
- one column, except when the currently selected item is
- in the far-left column, in which case the previous
- pull-down menu is selected.
-
- UP or DOWN Activates a pull-down menu when in the menu bar. This
- keystroke selects the next or previous item when in a
- pull-down menu.
-
- ENTER Activates a pull-down menu and highlights the first item
- if an item has a pull-down menu associated with it;
- otherwise, this keystroke chooses the item as if the
- user released the mouse button while the item was
- selected.
-
- Alphabetic Selects the first menu item with the specified character
- characters as its mnemonic key. A mnemonic is defined for a menu
- item by placing a tilde (~) before the character in the
- menu text. If the selected item has a pull-down menu or
- secondary menu associated with it, the menu is displayed
- Keystroke Action
- ──────────────────────────────────────────────────────────────────────────
- secondary menu associated with it, the menu is displayed
- and the first item is highlighted; otherwise, the item
- is chosen.
- ──────────────────────────────────────────────────────────────────────────
-
-
- An application does not need to support this default behavior with any
- unusual code. The application receives a message when a menu item is
- chosen by using the keyboard just as if it had been chosen by using a
- mouse.
-
- 17.5.6 Using Keyboard Accelerators
-
- Applications can define accelerator tables to make user interaction with
- menus more efficient. Accelerator tables are resources that associate
- keystrokes with menu command items. For example, an application can define
- an accelerator table resource that makes the F8 key generate a WM_COMMAND
- message that is identical to the message generated when the user chooses
- the Quit item from the File menu. Accelerator tables provide a shortcut
- for proficient users that allows them to work more quickly with the
- application. A sample resource-definition file for an accelerator table is
- shown in the following code fragment:
-
- ACCELTABLE ID_ACCEL_RESOURCE
- BEGIN
- VK_F8, IDM_FILE_QUIT, VIRTUALKEY
- VK_F3, IDM_SEARCH_FIND, VIRTUALKEY
- VK_F1, NULL, VIRTUALKEY, HELP
- END
-
- The resource-definition file associates keystrokes with menu-item command
- identifiers. Notice that the definition uses virtual-keystroke definitions
- that are independent of the particular scan codes generated by different
- keyboard hardware.
-
- In order to use an accelerator table with a window, the window should be
- created with the FS_ACCELTABLE style, and the resource identifier of the
- accelerator table must be the same as the identifier of the window's menu.
- Alternatively, you can associate an accelerator table with a frame window
- after the window is created, by calling the WinSetAccelTable function.
-
- For more information on keyboard accelerators, see Chapter 18,
- "Accelerator Tables."
-
- 17.5.7 Help Item in the Menu Bar
-
- The user-interface guidelines suggest that all applications have a Help
- menu item at the far-right end of the menu bar. The item should read
- "F1=Help", have an identifier of zero, and have the MIS_BUTTONSEPARATOR or
- MIS_HELP item style. The Help menu item should be the last item in the
- menu template, so that it is displayed at the far-right end of the menu
- bar.
-
- The user can use either a mouse or the F1 key to select the Help menu
- item, if the application uses the system default accelerator table. (For
- more information on the system default accelerator table, see Section
- 17.5.6.) The Help item generates a WM_HELP message instead of a
- WM_COMMAND message.
-
- 17.5.8 Setting and Querying Menu-Item Attributes
-
- Menu-item attributes are represented in the afAttribute field of the
- MENUITEM data structure. Typically, attributes are set in the
- resource-definition file of the menu and changed at run time as required.
- Applications can use the MM_SETITEMATTR and MM_QUERYITEMATTR messages to
- set and query attributes for a particular menu item. One of the most
- common uses of these messages is to check and uncheck menu items to let
- the user know what option is currently selected. For example, if you have
- a menu item that should toggle between checked and unchecked each time it
- is chosen, you could use the following code to change the checked
- attribute. You first send an MM_QUERYITEMATTR message to the menu item to
- obtain its current checked attribute, then use the exclusive OR operator
- to toggle the state, and then you send the new attribute-state back to the
- item by using an MM_SETITEMATTR message.
-
- usAttrib = (SHORT) WinSendMsg(hwndMenu, /* submenu window */
- MM_QUERYITEMATTR, /* message */
- MPFROMSHORT(itemID), /* identifier of item */
- MPFROMSHORT(MIA_CHECKED)); /* attribute mask */
-
- usAttrib ^= MIA_CHECKED; /* XOR to toggle checked attribute */
-
- WinSendMsg(hwndMenu, /* submenu window */
- MM_SETITEMATTR, /* message */
- MPFROMSHORT(itemID), /* identifier of item */
- MPFROM2SHORT(MIA_CHECKED, usAttrib)); /* attribute mask, value */
-
- There are two methods for manipulating individual menu items in submenus.
- The first is to send MM_SETITEMATTR and MM_QUERYITEMATTR messages to the
- menu-bar menu, specifying the identifier of the item and setting a flag so
- that the message searches all submenus for the item. The handle of the
- menu-bar window can be obtained by calling the WinWindowFromID function
- with the handle of the frame window and the FID_MENU frame-control
- identifier.
-
- The second method, which is more efficient if you want to work with more
- than one item in a submenu or set the same item several times, involves
- two steps:
-
- 1. Sending an MM_QUERYITEM message to the menu-bar window with the
- identifier of the submenu. The updated MENUITEM structure contains the
- window handle of the submenu.
-
- 2. Send an MM_QUERYITEMATTR (or MM_SETITEMATTR) message to the submenu
- window, specifying the identifier of the item in the submenu.
-
- 17.5.9 Setting and Querying Menu-Item Contents
-
- Applications can change the contents of a menu item dynamically by sending
- messages to the menu. For MIS_TEXT items, an MM_SETITEMTEXT message sets
- the text. The MM_QUERYITEMTEXT message queries the item's text.
-
- For nontext menu items, the hItem field of the MENUITEM data structure
- typically contains a handle of a display object, such as a bitmap handle
- for MIS_BITMAP menu items. You can change the Item field for a menu item
- by sending an MM_QUERYITEM message to the menu to fill in the MENUITEM
- structure, changing the relevant fields, and then sending the structure
- back to the menu with an MM_SETITEM message.
-
- 17.5.10 Adding and Deleting Menu Items
-
- An application can add and delete items from its menus dynamically by
- sending MM_INSERTITEM and MM_DELETEITEM messages to the menu window. Any
- item, including those in submenus, can be deleted by sending a message to
- the menu-bar window. Messages to insert items in submenus must be sent to
- the submenu's pull-down menu window (rather than to the menu-bar window).
- The handle of the pull-down menu window can be obtained by sending an
- MM_QUERYITEM message to the menu-bar window and specifying the identifier
- of the submenu item for the submenu, as shown in the following code
- fragment:
-
- /* IDM_MYMENUID is the ID of the submenu containing the item. */
-
- MENUITEM mi;
-
- hwndActionBar = WinWindowFromID(hwndFrame, FID_MENU);
- WinSendMsg(hwndActionBar, /* handle of menu bar */
- MM_QUERYITEM, /* message */
- MPFROM2SHORT(IDM_MYMENUID, TRUE), /* submenu identifier */
- (MPARAM) &mi); /* pointer to MENUITEM */
-
- hwndpulldown = mi.hwndSubMenu; /* handle to submenu */
-
-
- Once the application has the handle of the pull-down menu window, it can
- insert an item by filling in a MENUITEM structure and sending an
- MM_INSERTITEM message to the pull-down menu. For text-menu items, the
- application must send a pointer to the text string as well as to the
- MENUITEM structure.
-
- mi.iPosition = MIT_END;
- mi.afStyle = MIS_TEXT;
- mi.afAttribute = 0;
- mi.id = IDM_MYMENU_FIRST;
- mi.hwndSubMenu = NULL;
- mi.hItem = NULL;
-
- WinSendMsg(hwndpulldown, MM_INSERTITEM, (PMENUITEM) &mi,
- (MPARAM) szNewItemString);
-
- To delete an item, the application sends an MM_DELETEITEM message to the
- menu-bar window, specifying the identifier of the item to delete. For
- example, to clear all the items following IDM_MYMENU_FIRST in a submenu in
- which the items are numbered sequentially, you would use the following
- code fragment:
-
- /* Clear all the items in MYMENU. */
-
- hwndActionBar = WinWindowFromID(hwndFrame, FID_MENU);
- usItemNum = IDM_MYMENU_FIRST;
- while (WinSendMsg(hwndActionBar, MM_DELETEITEM,
- MPFROM2SHORT(usItemNum++, TRUE), (MPARAM) 0L));
-
- Adding a complete submenu to the menu bar is a more complicated procedure
- than shown in the previous examples. There are two strategies. The
- recommended technique is to define all possible submenus in your
- resource-definition file and then selectively remove and insert the
- submenus as needed as your program runs.
-
- For example, assume that your program has a submenu that you want to be
- displayed only when a particular application tool is in use. You define
- the submenu as part of the main menu resource in your resource-definition
- file, so that the system reads in the resource menu template and creates
- the submenu window along with the rest of the menu. You can then remove
- the submenu from the menu bar, saving the title of the submenu and the
- MENUITEM data structure that defines the submenu, as shown in the
- following code fragment:
-
- HWND hwndActionBar;
- MENUITEM mi;
- CHAR szMenuTitle[MAX_STRINGSIZE];
-
- /* Remove a submenu so that you can replace it later. */
-
- /* Obtain the handle of a menu menu. */
-
- hwndActionBar = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE),
- FID_MENU);
-
- /* Obtain information on the item to remove. */
-
- WinSendMsg(hwndActionBar, MM_QUERYITEM,
- MPFROM2SHORT(IDM_MENUID, TRUE), /* TRUE to search submenus */
- &mi);
-
- /* Save the text for the submenu item. */
-
- WinSendMsg(hwndActionBar, MM_QUERYITEMTEXT,
- MPFROM2SHORT(IDM_FONT, MAX_STRINGSIZE),
- szMenuTitle);
-
- /* Remove the item, but retain mi and szMenuTitle. */
-
- WinSendMsg(hwndMenu, MM_REMOVEITEM,
- MPFROM2SHORT(IDM_FONT, TRUE), NULL);
-
- It is important to use the MM_REMOVEITEM message to remove the item,
- rather than the MM_DELETEITEM message; deleting the item destroys the
- submenu window but removing it does not destroy the submenu. The submenu
- should remain intact so that you can insert it later.
-
- To reinsert the submenu, send an MM_INSERTITEM message to the menu bar,
- passing the MENUITEM structure and menu title that you saved when you
- removed the item. The following code fragment shows how to insert a
- submenu that was removed by using the previous code example:
-
- /* Put the submenu back in and obtain the handle of the menu bar. */
-
- hwndMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE),
- FID_MENU);
-
- /* Use the information that you saved when you removed the menu. */
-
- WinSendMsg(hwndMenu, MM_INSERTITEM, &mi, szMenuTitle);
-
- The other technique that you can use to insert a submenu in the menu bar
- is to build up a data structure as a menu template in memory and use that
- template and the WinCreateWindow function to create a submenu window. The
- resulting submenu window handle is then placed in the hwndSubMenu field of
- a nMENUITEM structure and the menu item is sent to the menu bar with an
- MM_INSERTITEM message.
-
- You also can create an empty submenu window by using the WinCreateWindow
- function. Pass NULL for the pCtlData and pPresParams parameters, instead
- of building the menu template in memory. Then insert a new menu item into
- the menu bar by using the MM_INSERTITEM message, setting the style
- MIS_SUBMENU, and putting the window handle of the created menu into the
- hwndSubMenu parameter. Then use the MM_INSERTITEM message to insert the
- items into the new pull-down menu.
-
- 17.5.11 Owner-Drawn Menu Items
-
- Applications can customize the appearance of an individual menu item by
- setting the MIS_OWNERDRAW style bit for the item. MS OS/2 sends two
- different messages to an application that includes owner-drawn menu items:
- WM_MEASUREITEM and WM_DRAWITEM. Both messages include a pointer to an
- OWNERITEM data structure, as shown in the following code fragment:
-
- typedef struct _OWNERITEM {
- HWND hwnd; /* handle of menu window */
- HPS hps; /* presentation space in which to draw */
- USHORT fsState; /* requested style */
- USHORT fsAttribute; /* requested attribute */
- USHORT fsStateOld; /* current style */
- USHORT fsAttributeOld; /* current attribute */
- RECTL rclItem; /* bounding rectangle of item */
- SHORT idItem; /* item identifier */
- ULONG hItem; /* handle of item-display object */
- } OWNERITEM;
-
- The WM_MEASUREITEM message is sent only once for each owner-drawn item,
- when the menu is initialized. The message is sent to the menu's owner
- window (typically, a frame window), which forwards the message to its
- client window. Typically, the client window procedure processes the
- message WM_MEASUREITEM by filling in the yTop and xRight fields of the
- RECTL structure specified by the rclItem field of this OWNERITEM
- structure; this specifies the size of the rectangle needed to enclose the
- item when it is drawn. The code fragment shown below responds to a
- WM_MEASUREITEM message. If your owner-drawn menu contains text, you should
- compute the size of the items from the height of the system font or some
- other system characteristic.
-
- case WM_MEASUREITEM:
- (POWNERITEM) mp2->rclItem.xRight = 26;
- (POWNERITEM) mp2->rclItem.yTop = 10;
- return ((MRESULT) 0);
-
- If a menu item has the MIS_OWNERDRAW style, the owner window receives a
- WM_DRAWITEM message every time the menu item needs to be drawn. You should
- process this message by using the hps and rclItem fields of the OWNERITEM
- structure to draw the item. There are two situations in which the owner
- window receives a WM_DRAWITEM message:
-
- ■ The item needs to be completely redrawn.
-
- ■ The item needs to highlighted or unhighlighted.
-
- You can choose to handle one or both of these situations. Typically, you
- handle the drawing of the item. The system default behavior of inverting
- the item rectangle to show that the item is selected is often acceptable,
- however, so you may not want to do this yourself.
-
- The two situations in which a WM_DRAWITEM message is received are detected
- by comparing the values of the fsAttribute and fsAttributeOld fields of
- the OWNERITEM structure that is sent as part of the message. If the two
- fields are the same, you should draw the item. When drawing the item, you
- can also check the attributes of the item to see if the item has the
- MIA_CHECKED, MIA_FRAMED, or MIA_DISABLED attribute. You should draw the
- item according to the settings of the attribute bits. For example, when
- the checked attribute of a owner-drawn menu item changes, the system sends
- a WM_DRAWITEM message to the item so that it can redraw itself and either
- draw or remove the check mark. If you want the system default check mark,
- simply draw the item and leave the fsAttribute and fsAttributeOld fields
- unchanged; the system will draw the check mark, if necessary. If you draw
- the check mark yourself, clear the MIA_CHECKED bit in both fsAttribute and
- fsAttributeOld, so that the system does not attempt to draw a check mark.
-
- If the fsAttribute and fsAttributeOld fields of the OWNERITEM structure in
- a WM_DRAWITEM message are not equal, the highlight showing that an item
- is selected needs to change. The MIA_HILITED bit of the fsAttribute field
- is set if the item needs to be highlighted and is not set if the item
- needs to be unhighlighted. If you do not wish to provide your own, you
- should ignore any WM_DRAWITEM message in which fsAttribute and
- fsAttributeOld are not equal. If you do not alter these two fields, the
- system performs its default highlighting operation, which is to invert the
- bits within the item rectangle. If, however, you wish to provide your own
- visual cue that an item is selected, you should respond to a WM_DRAWITEM
- message in which fsAttribute and fsAttributeOld are not equal by providing
- the cue and then clearing the MIA_HILITED bit of both fsAttribute and
- fsAttributeOld before returning from the message.
-
- Likewise, the MIA_CHECKED and MIA_FRAMED bits of the fsAttribute and
- fsAttributeOld fields can either be used to perform the corresponding
- action or can be passed on unchanged so that the system performs the
- action.
-
- The following code fragment shows how to respond to a WM_DRAWITEM message
- when you want to draw the item and also be responsible for its
- highlighted/unhighlighted state:
-
- case WM_DRAWITEM:
- POWNERITEM poi;
- RECTL rcl;
-
- poi = (POWNERITEM) mp2;
-
- /*
- * If the new attribute equals the old attribute,
- * redraw the entire item.
- */
-
- if (poi->fsAttribute == poi->fsAttributeOld) {
-
- /*
- * Draw the item in poi->hps and poi->rclItem,
- * and check the attributes for check marks. If you
- * produce your own check marks, use this line of code:
- * poi->fsAttributeOld = (poi->fsAttribute &= ~MIA_CHECKED;
- */
-
- /* Else the item should be highlighted or unhighlighted. */
-
- } else if ((poi->fsAttribute & MIA_HILITED) !=
- (poi->fsAttributeOld & MIA_HILITED)) {
-
- /*
- * Set bits the same so that the menu system does not make
- * the item highlighted or unhighlighted.
- */
-
- poi->fsAttributeOld = (poi->fsAttribute &= ~MIA_HILITED);
- }
- return TRUE; /* TRUE means item is drawn */
-
-
- 17.6 Summary
-
- This section describes the styles, attributes, functions, and messages
- associated with menus.
-
- 17.6.1 Menu-Item Styles
-
- Menu item styles determine what kind of data a menu contains (text,
- bitmap, etc.), how the menu is displayed (whether or not it is drawn by
- the owner), and what kind of message it generates when chosen (WM_COMMAND,
- WM_SYSCOMMAND, or WM_HELP). Menu-item styles are set when the menu item is
- created and are not typically changed at run time. Menu item attributes,
- described in the next section, are used for the aspects of a menu item
- that change frequently while a program is running.
-
- MIS_BITMAP The menu-display object is a bitmap.
-
- MIS_BREAK The item begins a new row or column.
-
- MIS_BREAKSEPARATOR Same as MIS_BREAK, except that it draws a separator
- between rows or columns.
-
- MIS_BUTTONSEPARATOR The item cannot be selected by using the cursor keys,
- but it can be selected by using the mouse or the appropriate accelerator
- key. A menu bar can have zero, one, or two button-separator items. They
- are always placed at the right side of the menu bar or at the bottom of a
- pull-down menu.
-
- MIS_HELP A command item with this style notifies its owner window
- that it has been chosen by using a WM_HELP message rather than a
- WM_COMMAND message.
-
- MIS_OWNERDRAW The item is drawn by the owner window. The menu sends
- WM_DRAWITEM and WM_MEASUREITEM messages to the owner window to draw the
- item and specify its size.
-
- MIS_SEPARATOR This item is a horizontal dividing line in a pull-down
- menu. It cannot be checked, disabled, or selected.
-
- MIS_STATIC The item is for information only. It cannot be selected by
- using the mouse or keyboard.
-
- MIS_SUBMENU The item is a submenu item. When the user selects a submenu
- item, a pull-down menu window is displayed from which the user can choose
- a command item.
-
- MIS_SYSCOMMAND A command item with this style notifies its owner window
- that it has been chosen by using a WM_SYSCOMMAND message, rather than a
- WM_COMMAND message. MIS_TEXT The menu-display object is a text string.
- This is the default menu-item style.
-
- The following menu-item styles are mutually exclusive; they may not be
- specified in combination with each other:
-
- MIS_BITMAP
- MIS_OWNERITEM
- MIS_SEPARATOR
- MIS_TEXT
-
- Likewise, the following menu-item styles are mutually exclusive:
-
- MIS_HELP
- MIS_SYSCOMMAND
-
- 17.6.2 Menu-Item Attributes
-
- Menu-item attributes specify changing display aspects of a menu item, such
- as its highlighted, and checked state. Attributes are set when the item is
- created and typically can change frequently as the program executes and
- the user interacts with the menus.
-
- MIA_CHECKED Set to produce a check mark to the left of the item.
-
- MIA_ENABLED Set when the item can be selected by the user. If not set,
- the item is drawn grayed and cannot be selected by the user. An
- application should disable a menu item when choosing it would be
- inappropriate──for example, a Save menu item should be disabled when there
- have been no changes since the last save operation.
-
- MIA_FRAMED Set when a submenu item in the menu bar is framed by vertical
- lines to the left and right when its pull-down menu is displayed. This is
- typically handled by the system; an application does not usually have to
- set this attribute.
-
- MIA_HILITED Set only when the item is currently selected. The application
- rarely sets this attribute directly, relying instead on the default
- processing of user input to set the highlighted state of an item.
-
- 17.6.3 Menu Functions
-
- Most applications will not use the menu functions listed below, relying
- instead on the automatic association of menus and frame windows provided
- by menu resources and the WinCreateStdWindow function. These menu
- functions are useful if you want to use menus in a nonstandard way.
-
- WinCreateMenu Creates a menu window from a menu-template data structure,
- assigning ownership to the specified window. This function is like the
- WinLoadMenu function, except that the menu data is stored as a menu
- template in memory, rather than in a resource-definition file.
-
- WinLoadMenu Loads a menu resource from the specified resource-definition
- file (NULL for the current application's resource file) and assigns
- ownership to the specified window. The menu is owned by the specified
- window and is displayed when the owner window receives a WM_UPDATEFRAME
- message.
-
- 17.6.4 Messages Sent from a Menu to an Owner Window
-
- These messages are sent from a menu to an owner. If the owner window is a
- standard frame window, the messages are passed to the client window's
- window procedure. All applications that use menus must respond to
- WM_COMMAND messages. Other messages in this section are appropriate for
- applications that use the more advanced features of menus.
-
- WM_COMMAND Notifies the owner window when the user chooses a menu item.
- Applications must respond to this message to use menus.
-
- WM_SYSCOMMAND Notifies the owner window when the user chooses a System
- menu item; this is equal to the WM_COMMAND message except that the menu
- item has the MIS_SYSCOMMAND style. The frame window usually does not pass
- this message to the client window. To process a WM_SYSCOMMAND message, the
- application must subclass the frame window.
-
- WM_HELP Notifies the owner window when the user chooses a Help menu item;
- equal to the WM_COMMAND message except that the menu item has the MIS_HELP
- style. This message is usually generated by the "F1=Help" command item in
- the menu bar. Applications should respond to this message with a help
- dialog-box or by using the help-hook facility.
-
- WM_INITMENU Notifies the owner window that the menu or submenu is about
- to be displayed. This message allows an application to change the state of
- a menu before the menu is displayed.
-
- WM_MENUSELECT Notifies the owner window each time a menu item is
- selected. Applications do not need to handle this message to obtain the
- default menu behavior. For example, an application receives multiple
- WM_MENUSELECT messages when a user moves the mouse pointer up and down in
- a menu while the mouse button is pressed. This message allows an
- application to perform some other action coincident with the selection of
- a menu item, such as displaying a context-appropriate message in another
- part of the window. This message is also sent when the user actually
- chooses a menu item. If the application returns FALSE in response to this
- message when the user chooses a menu item, the command associated with the
- menu item is not posted, and the menu is not dismissed.
-
- WM_MENUEND Notifies the owner window when exiting from menu mode.
-
- WM_DRAWITEM Notifies the owner window when an item with the style
- MIA_OWNERDRAW needs to be drawn. Applications with owner-drawn menu items
- must respond to this message. The message contains a pointer to a data
- structure containing a presentation space handle and a rectangle in which
- to draw the item.
-
- WM_MEASUREITEM Allows the owner window to specify the dimensions of an
- owner-drawn menu item. Applications with owner-drawn menu items must
- respond to this message.
-
- WM_QUERYFOCUSCHAIN Temporarily sets the focus to the menu bar while in
- menu mode. This message is routed to the window from which the menu took
- the focus. WM_FOCUSCHANGE Exits from menu mode, if the menu is losing the
- focus. If the exit operation fails, this message sets the state and is
- passed to the window that had the focus before menu mode was started.
-
- WM_SETFOCUS Posts an MM_STARTMENUMODE message to initiate menu
- processing, if receiving the focus. If losing the focus, call the
- WinDefWindowProc function.
-
- WM_QUERYDLGCODE Returns DLGC_MENU or DLGC_STATIC to indicate that this is
- a menu control and that the menu should not receive the focus when the
- user presses the DIRECTION keys or the TAB key.
-
- WM_PAINT Draws the menu.
-
- WM_CREATE Creates a list of items from the menu-template structure.
-
- WM_DESTROY Destroys the menu and all its submenus and any display objects
- associated with the menu items.
-
- WM_ENABLE Invalidates the window rectangle, causing it to be redrawn.
-
- WM_ADJUSTWINDOWPOS Reformats the contents of the menu window.
-
- WM_CONTROLHEAP Notifies the owner of a menu that a control needs the
- handle of a heap from which memory will be allocated.
-
- WM_CONTROLPOINTER Notifies the owner of a menu that the mouse pointer is
- over the window.
-
- WM_BUTTON1DOWN Begins processing a user's menu choice.
-
- WM_MOUSEMOVE Sets the default mouse pointer (arrow cursor).
-
- WM_BUTTON2DOWN Activates the menu window.
-
- WM_BUTTON3DOWN Activates the menu window.
-
- WM_QUERYCONVERTPOS Determines whether or not to begin double-byte
- character set (Kanji) conversion. Menus in MS OS/2 version 1.1 return
- QCP_NOCONVERT, which indicates that the menu code does not set up
- the rectangle pointed to by the mp1 parameter with the cursor bounding
- rectangle and that conversion should not be performed. Edit controls
- return QCP_CONVERT and fill in a RECTL structure with the cursor
- boundaries. (Programs can use this rectangle to position a Kanji window
- next to the cursor.)
-
- 17.6.5 Messages Sent to a Menu
-
- The messages in this section are sent to menus, either by the system or by
- applications. Many of these messages are for manipulating the data that
- represents the state of menu items. Applications will find these messages
- useful for dynamically adjusting menus to reflect the current processing
- environment. Other messages in this section control the display of menu
- items during menu selection; these typically are sent automatically by the
- system, although an application can send them to control its menus more
- directly and override the default behavior.
-
- MM_QUERYITEMCOUNT Returns the number of items in the menu. For the menu
- bar, this is the number of items in the menu bar. For a submenu, this is
- the number of items in the submenu. MM_STARTMENUMODE Starts
- menu-selection processing, including mouse tracking for menu-item
- selection.
-
- MM_ENDMENUMODE Exits from menu mode and hides any active submenus.
-
- MM_INSERTITEM Insert the specified menu item in the menu.
-
- MM_DELETEITEM Removes the specified item from the menu and destroys any
- resources and data structures for that item (such as display objects or
- submenus).
-
- MM_REMOVEITEM Same as the MM_DELETEITEM message, except that it does not
- destroy associated submenus or display objects.
-
- MM_SELECTITEM Selects the specified item; and if the fDismiss flag is
- set, posts a WM_COMMAND, WM_SYSCOMMAND, or WM_HELP message.
-
- MM_QUERYSELITEMID Returns the identifier of the currently selected item.
-
- MM_QUERYITEM Copies information about a specified item into a
- caller-supplied MENUITEM data structure.
-
- MM_QUERYITEMTEXT Copies the text for a specified menu item into a
- caller-supplied buffer.
-
- MM_QUERYITEMTEXTLENGTH Returns the length of the text, not including the
- NULL terminator, for a specified item.
-
- MM_SETITEMHANDLE Sets the menu-item handle for a nontext item and forces
- the item to be redrawn.
-
- MM_SETITEMTEXT Sets the text for a menu item and forces the item to be
- redrawn.
-
- MM_ISITEMVALID Returns TRUE if item can be selected.
-
- MM_SETITEM Sets the state of an item, based on the data in a MENUITEM
- structure, and forces the item to be redrawn.
-
- MM_ITEMPOSITIONFROMID Returns the position of a menu item in a menu
- window, searching submenus if requested.
-
- MM_ITEMIDFROMPOSITION Returns the identifier of the menu item at the
- specified position in the menu window.
-
- MM_QUERYITEMATTR Returns the current attributes of a menu item.
-
- MM_SETITEMATTR Sets the specified attributes of a menu item.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 18 Accelerator Tables
-
- 18.1 Introduction
- 18.2 About Accelerator Tables
- 18.3 Accelerator Tables in a Resource-Definition File
- 18.4 Accelerator-Table Data Structures
- 18.5 Using an Accelerator Table in an Application
- 18.5.1 Including an Accelerator Table in a Frame Window
- 18.5.2 Modifying an Accelerator Table
- 18.6 Summary
- 18.6.1 Functions
- 18.6.2 Accelerator-Item Styles
- 18.6.3 Messages
-
- 18.1 Introduction
-
- This chapter describes how to use accelerator tables in your applications.
- You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Menus
-
- ■ Creating standard frame windows
-
- ■ Window messages and the message queue
-
-
- 18.2 About Accelerator Tables
-
- Accelerators are keystrokes that generate command messages for an
- application; they elicit the same behavior as choosing a menu item. Menus
- provide an easy way to learn an application's command set, but
- accelerators provide quicker access to those commands.
-
- Accelerators filter keyboard input. Accelerator keystrokes are translated
- into command messages before they reach the application. When an
- accelerator is used, the application receives a command message rather
- than a keyboard message.
-
- Accelerators function differently from the usual keyboard-to-menu
- interface. By default, a user can use the ALT key to access submenus and
- the arrow keys to move along the menu bar. Accelerators provide single
- keystrokes that generate command messages without the visual effects of
- pulling down menus or stepping from one item to another.
-
- Like menu items, accelerators can generate WM_COMMAND, WM_HELP, and
- WM_SYSCOMMAND messages, depending on the setting of the accelerator's
- style bits. Although accelerators are normally used to generate commands
- that already exist as menu items, they can also send commands that have no
- equivalent menu items.
-
- An accelerator table contains an array of accelerators. Accelerator tables
- exist at two levels within MS OS/2. MS OS/2 maintains a single accelerator
- table for the system queue and individual accelerator tables for
- application windows. Accelerators in the system queue apply to all
- applications──for example, the F1 key always generates a WM_HELP message.
- Having accelerators for individual application windows ensures that an
- application can define its own accelerators without interfering with other
- applications. An accelerator for an application window overrides the
- accelerator in the system queue. An application can modify both its own
- accelerator table and the system accelerator table.
-
-
- 18.3 Accelerator Tables in a Resource-Definition File
-
- An application that uses accelerators typically creates an accelerator
- table resource-definition file containing its accelerators and associates
- that resource with a standard frame window when the window is created.
-
- The resource-definition file of an accelerator table is a list of
- accelerator items. Each item defines the keystroke that triggers the
- accelerator, the command that the accelerator generates, and the
- accelerator's style. The style bits specify whether the keystroke is a
- virtual key, a character, or a scan code, and whether the message that is
- generated is WM_COMMAND, WM_SYSCOMMAND, or WM_HELP. (WM_COMMAND is the
- default message.)
-
- A resource-definition file for an accelerator table is shown in the
- following code fragment:
-
- ACCELTABLE ID_ACCEL_RESOURCE
- BEGIN
- VK_ESC, IDM_ED_UNDO, VIRTUALKEY, SHIFT
- VK_DELETE, IDM_ED_CUT, VIRTUALKEY
- VK_F2, IDM_ED_COPY, VIRTUALKEY
- VK_INSERT, IDM_ED_PASTE, VIRTUALKEY
- END
-
- This accelerator table has four accelerator items. The first one is
- triggered when the user presses SHIFT+ESC; it sends a WM_COMMAND message
- (the default) just as if the IDM_ED_UNDO menu item had been chosen.
-
- The accelerator table resource-definition file has a
- resource-identification number that is usually the same as the identifier
- of the application's menu resource; this allows the accelerator table to
- be associated with a standard frame window when the frame window is
- created. You can also define accelerator-table resources with other
- identification numbers and associate them with windows after the windows
- are created.
-
-
- 18.4 Accelerator-Table Data Structures
-
- Applications that manipulate accelerator tables can refer to them with a
- 32-bit handle (HACCEL). Using this handle allows an application to make
- most API function calls for accelerators without needing to account for
- the internal structures that define the accelerator table. To use
- accelerator tables in the default manner, it is sufficient to define the
- table in the resource-definition file and associate it with a standard
- frame window when creating the window. When an application needs to
- dynamically create or change an accelerator table, it must use the ACCEL
- and ACCELTABLE data structures.
-
- An accelerator table is made up of individual accelerator items. Each item
- is represented by an ACCEL data structure that defines the accelerator's
- style, keystroke, and command identifier. The ACCEL structure has the
- following form:
-
- typedef struct _ACCEL {
- USHORT fs;
- USHORT key;
- USHORT cmd;
- } ACCEL;
-
- Typically, an application defines the aspects of the accelerator in the
- resource-definition file for the accelerator, but the data structure can
- be built in memory at run time, if necessary.
-
- An accelerator table is made up of one or more accelerator items and
- information that specifies the number of accelerator items in the table
- and the code page used for the keystrokes in the accelerator items. The
- ACCELTABLE structure has the following form:
-
- typedef struct _ACCELTABLE {
- SHORT cAccel;
- USHORT codepage;
- ACCEL aaccel[1];
- } ACCELTABLE;
-
- Notice that the array of accelerator items is defined as having only one
- member. Applications that use accelerator-table data structures directly
- must allocate sufficient memory to hold all the items in the table.
-
-
- 18.5 Using an Accelerator Table in an Application
-
- An application can automatically load an accelerator table
- resource-definition file when creating a standard frame window, or it can
- load the resource independently and associate it with a window or with the
- entire system.
-
- An application can set and query the accelerator tables for a specific
- window or for the entire system. For example, an application could query
- the system accelerator table, copy it, modify the copied accelerator-table
- data structures, and then use the modified copy to set the system
- accelerator table. An application that does this should maintain the
- original accelerator table and restore it when the application terminates.
- An application can also modify its window's accelerator table at run time
- to respond more appropriately to the current environment.
-
- 18.5.1 Including an Accelerator Table in a Frame Window
-
- An application can add an accelerator table to a frame window either by
- using the WinSetAccelTable function or by defining an accelerator-table
- resource and creating a frame window with the FCF_ACCELTABLE frame style.
- The second method is shown in the following code fragment:
-
- ULONG lControlStyle = FCF_MENU | FCF_SIZEBORDER
- | FCF_TITLEBAR | FCF_ACCELTABLE;
-
- hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE,
- &lControlStyle, szClassName, szTitle, 0L, NULL, ID_MENU_RESOURCE,
- &hwndClient);
-
- Note that if you set the lControlStyle parameter to FCF_STANDARD you must
- define an accelerator-table resource, because FCF_STANDARD includes the
- FCF_ACCELTABLE flag.
-
- If the window being created also has a menu, the menu resource and the
- accelerator resource must have the same resource identifier; this is
- because the WinCreateStdWindow function has only one input parameter to
- specify the resource ID of menus, accelerator tables, and icons. If an
- application creates a resource-definition file for the accelerator table
- and then opens a standard frame window, as shown in the preceding example,
- the accelerator table is automatically installed in the window's input
- queue and keyboard events are translated during normal events-processing.
- The application responds to WM_COMMAND, WM_SYSCOMMAND, and WM_HELP
- messages; it does not matter whether they come from a menu or from an
- accelerator.
-
- An application can also add an accelerator table to a window by calling
- the WinSetAccelTable function with an accelerator-table handle and a
- frame-window handle. The application can call either the WinLoadAccelTable
- function to retrieve an accelerator table from a resource file or the
- WinCreateAccelTable function to create an accelerator table from an
- accelerator-table data structure in memory.
-
- 18.5.2 Modifying an Accelerator Table
-
- An application can modify an accelerator table, either for its own windows
- or for the system, by retrieving the handle of the accelerator table,
- using the handle to copy the accelerator-table data to an
- application-supplied buffer, changing the data in the buffer, and then
- using the data in the buffer to create a new accelerator table. The
- application can then use the new accelerator-table handle to set the
- accelerator table, either for a window or for the system. This process is
- outlined in the following list:
-
- 1. Call the WinQueryAccelTable function to retrieve an accelerator-table
- handle.
-
- 2. Call the WinCopyAccelTable function with a null buffer handle to
- determine how many bytes are in the table.
-
- 3. Allocate sufficient memory for the accelerator-table data.
-
- 4. Call the WinCopyAccelTable function with a pointer to the allocated
- memory.
-
- 5. Modify the data in the buffer (assuming it has the form of an
- ACCELTABLE data structure).
-
- 6. Call the WinCreateAccelTable function, passing a pointer to the buffer
- with the modified accelerator-table data.
-
- 7. Call the WinSetAccelTable function with the handle returned by the
- WinCreateAccelTable function.
-
-
- 18.6 Summary
-
- This section summarizes the functions, styles, and messages related to
- accelerator tables.
-
- 18.6.1 Functions
-
- The following functions allow your application to use accelerator tables:
-
- WinCopyAccelTable Copies the specified accelerator table to an
- application-provided ACCELTABLE data structure.
-
- WinCreateAccelTable Creates an accelerator table using an ACCELTABLE data
- structure. This is similar to the WinLoadAccelTable function except that
- this function does not use resources.
-
- WinDestroyAccelTable Destroys the specified accelerator table.
-
- WinLoadAccelTable Loads a specified accelerator table from a specified
- dynamic-link module (the module handle is NULL for the current
- application) and returns a handle of the accelerator table.
-
- WinQueryAccelTable Returns the accelerator-table handle for the specified
- window, or for the system if the window handle is NULL.
-
- WinSetAccelTable Sets the accelerator table for the specified window, or
- for the system if the window handle is NULL. WinSetAccelTable will remove
- an existing accelerator table if the accelerator-table handle is NULL.
-
- WinTranslateAccel Translates a WM_CHAR message into a WM_COMMAND,
- WM_SYSCOMMAND, or WM_HELP message by using the specified accelerator
- table. This function is normally called automatically by the WinGetMsg or
- WinPeekMsg function when a WM_CHAR message is received.
-
- 18.6.2 Accelerator-Item Styles
-
- The following accelerator-item styles are specified in the fs field of the
- ACCEL structure:
-
- AF_ALT Means the ALT key must be held down when the key is pressed.
-
- AF_CHAR Means the keystroke is a translated character, using the code
- page for the accelerator table. This is the default style.
-
- AF_CONTROL Means the CTRL key must be held down when the key is pressed.
-
- AF_HELP Means the accelerator generates a WM_HELP message instead of a
- WM_COMMAND message.
-
- AF_LONEKEY Means no other key is pressed while the key is down. This
- style is typically used with the ALT key to specify that simply pressing
- and releasing the ALT key triggers the accelerator.
-
- AF_SCANCODE Means the keystroke is an untranslated scan code from the
- keyboard.
-
- AF_SHIFT Means the SHIFT key must be held down when the key is pressed.
-
- AF_SYSCOMMAND Means a WM_SYSCOMMAND message is generated by the
- accelerator, instead of a WM_COMMAND message.
-
- AF_VIRTUALKEY Means the keystroke is a virtual key──for example, the F1
- function key.
-
- 18.6.3 Messages
-
- The following messages are used in the management of accelerator tables:
-
- WM_QUERYACCELTABLE Sent to a frame window by the WinQueryAccelTable
- function.
-
- WM_SETACCELTABLE Sent to a frame window by the WinSetAccelTable function.
-
- WM_TRANSLATEACCEL Sent to a frame window by the WinTranslateAccel
- function.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 19 Dialog Windows
-
- 19.1 Introduction
- 19.2 About Dialog Windows
- 19.2.1 Modal and Modeless Dialog Windows
- 19.2.2 Dialog Items
- 19.2.3 Dialog-Control Groups
- 19.2.4 Message Boxes
- 19.3 Dialog Data Structures
- 19.3.1 Dialog Coordinates
- 19.4 Dialog Resources
- 19.5 Using Message and Dialog Boxes
- 19.5.1 Message Boxes
- 19.5.1.1 System-Modal Message Boxes
- 19.5.2 Dialog Boxes
- 19.5.2.1 Modal Dialog Boxes
- 19.5.2.2 Modeless Dialog Boxes
- 19.5.2.3 Initializing a Dialog Box
- 19.5.2.4 Menus in Dialog Boxes
- 19.5.2.5 Dialog Procedure
- 19.5.2.6 Manipulating Dialog Items
- 19.6 Summary
- 19.6.1 Dialog-Window Styles
- 19.6.2 Message-Box Styles
- 19.6.3 Message-Box Return Values
- 19.6.4 Functions
- 19.6.5 Messages Sent to Dialog Boxes and Dialog Items
-
- 19.1 Introduction
-
- This chapter describes creating and using dialog windows and message boxes
- in your applications. You should also be familiar with the following
- topics:
-
- ■ Standard user interface guidelines
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Control windows
-
- ■ Window messages and message queues
-
-
- 19.2 About Dialog Windows
-
- A dialog window (also called a dialog box or a dialog) is a window that
- contains one or more child control windows and is typically used to
- display messages to and gather input from the user. It is often a
- temporary window that an application creates to gather specific input,
- destroying the window immediately after use.
-
- Dialog windows provide a high-level method for applications to display and
- gather information. MS OS/2 contains many functions and messages that help
- manage the control windows that make up a dialog window, thus easing the
- burden of maintaining complex input and output systems.
-
- 19.2.1 Modal and Modeless Dialog Windows
-
- Dialog windows can be modal or modeless. A modal dialog window requires
- that the dialog window be dismissed before the user can activate other
- windows in the same application. Generally, an application uses a modal
- dialog window to get essential information from the user before proceeding
- with an operation. A modeless dialog window allows the user to activate
- other windows without dismissing the dialog window.
-
- Both modal and modeless dialog windows allow the user to activate windows
- in another application before responding to the dialog window. For more
- information, see Section 19.2.4.
-
- Modal dialog windows are simpler for an application to manage because they
- are created, perform their task, and close, all in a single function call.
-
- Modeless dialog windows require more attention from the application
- because they exist until explicitly dismissed. Modeless dialog windows
- provide a more flexible interface, however, by allowing the user to move
- to other windows in the application before responding to the dialog
- window.
-
- 19.2.2 Dialog Items
-
- A dialog item is a child window of the dialog window. The dialog window is
- usually a window of class WC_FRAME. MS OS/2 provides many predefined
- window classes, called control windows, that are used as dialog items.
- Predefined control windows include static display boxes, text-entry
- fields, buttons, and list boxes. Customized window classes can also be
- used as dialog items.
-
- Because dialog items are windows, they can be manipulated by all
- window-management functions relating to size, position, and visibility.
- Dialog items are always owned by the dialog frame window. Most predefined
- control-window classes send notification messages to their owners when the
- user interacts with their control windows. The dialog frame window
- receives these notification messages and passes them on to the application
- through the application-defined dialog procedure.
-
- 19.2.3 Dialog-Control Groups
-
- Items within a dialog window can be organized into groups. When items are
- arranged in a group, the user can move from one item to another in the
- same group by using the direction keys. When the user presses a direction
- key, the focus moves from one item in a group to the next item of the same
- group, but not to items of other groups within the dialog window.
-
- Arranging items in groups is useful for radio buttons. Although other
- control types can also be displayed this way, entry-field controls cannot;
- they process direction keys themselves.
-
- The first item in a dialog-control group has the WS_GROUP window style.
- All subsequent items in the dialog template are considered part of that
- group until another item is given the WS_GROUP style, which begins a new
- group.
-
- The WS_TABSTOP style is often used along with the WS_GROUP style. This
- style marks the items that can receive the focus when the user presses the
- TAB key. Each time the user presses the TAB key, the focus moves to the
- next item that has the WS_TABSTOP style. Generally, the WS_GROUP and
- WS_TABSTOP styles are defined together for the first item of each group in
- the dialog template. This makes it possible for a user to press the TAB
- key to move between groups of items and to use the direction keys to move
- between items within a group.
-
- The WS_TABSTOP style should not be used for radio buttons because the
- system automatically maintains a tabstop on any selected item in a
- radio-button group; the focus will always be on the currently selected
- item when pressing the TAB key in a group of radio buttons.
-
- The WS_GROUP and WS_TABSTOP styles are also useful for preventing the user
- from moving to a particular button when using the keyboard. For example,
- if the dialog window has an OK and a Cancel button, you should put them in
- the same group, with the OK button as the first item in the group. The
- user can press the TAB key to select the OK button, but not the Cancel
- button. To move to the Cancel button by using the keyboard, the user must
- first press the TAB key to move to the OK button, and then press a
- direction key to move the focus to the Cancel button. For more information
- on how to define groups and tabstops in dialog windows, see Section 19.4.
-
- 19.2.4 Message Boxes
-
- Message boxes are dialog windows predefined by the system and used as a
- simple interface for applications without creating dialog-template
- resources or dialog procedures. An application can call the WinMessageBox
- function and specify the type of message box and message text. The system
- displays the message and waits for the user to dismiss the message box by
- selecting a button in the message box. The system then returns a result
- code to the application, indicating which button the user selected.
-
- Message boxes are best for short notification messages that require a
- simple acknowledgment or choice by the user. Applications do not specify a
- dialog procedure for message boxes, so they cannot readily change the
- action of a message box. There are many predefined message-box styles.
- Figure 19.1 shows a sample message box.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 19.1 can be found in Section 19.2.4 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 19.1 Sample Message Box
-
- Message boxes can be application-modal or system-modal. Application-modal
- means that the user cannot activate another window in the current
- application before responding to the message box, but can switch to
- another application before responding. System-modal means that the user
- cannot activate another window in any application while the message box is
- present. A system-modal message box should be used only to display urgent
- error messages (running out of memory, for example).
-
-
- 19.3 Dialog Data Structures
-
- A dialog-window item is a control window that is owned by the dialog
- window. Each dialog-window item is described by a DLGTITEM data structure.
- The DLGTITEM structure is rarely accessed directly by an application. Most
- manipulation of dialog items is handled by system functions. Applications
- that create dialog items that are not defined as part of a dialog-template
- resource must create dialog-window-item structures in memory. The format
- of a DLGTITEM structure is as follows:
-
- typedef struct _DLGTITEM {
- USHORT fsItemStatus;
- USHORT cChildren;
- USHORT cchClassName;
- USHORT offClassName;
- USHORT cchText;
- USHORT offText;
- ULONG flStyle;
- SHORT x;
- SHORT y;
- SHORT cx;
- SHORT cy;
- USHORT id;
- USHORT offPresParams;
- USHORT offCtlData;
- } DLGTITEM;
-
- Because a dialog window can have many items, a DLGTEMPLATE data structure
- consists of header information followed by an array of dialog-window
- items. Applications that create dialog windows without using dialog
- resources must create a dialog template in memory and then call the
- WinCreateDlg function. The format of a DLGTEMPLATE structure is as
- follows:
-
- typedef struct _DLGTEMPLATE {
- USHORT cbTemplate;
- USHORT type;
- USHORT codepage;
- USHORT offadlgti;
- USHORT fsTemplateStatus;
- USHORT iItemFocus;
- USHORT coffPresParams;
- DLGTITEM adlgti[1];
- } DLGTEMPLATE;
-
- 19.3.1 Dialog Coordinates
-
- Coordinates in a dialog template are specified in dialog coordinates and
- are based on the size of the system font. A horizontal unit is one-fourth
- of the system-font-character average width; a vertical unit is one-eighth
- of the system-font-character average height. The origin of the dialog
- template is the lower-left corner of the dialog window. MS OS/2 provides
- the WinMapDlgPoints function for converting dialog coordinates into window
- coordinates.
-
-
- 19.4 Dialog Resources
-
- Most applications define dialog templates in resource files rather than
- constructing template data structures in memory at run time. The
- dialog-resource file defines the size and style of the dialog-window frame
- and specifies each control item.
-
- The following source-code fragment creates a dialog template. Notice that
- the WS_GROUP and WS_TABSTOP style designations are given for the first
- item in each group. The dimensions and position for each item are given in
- dialog coordinates rather than in window coordinates.
-
- DLGTEMPLATE IDD_ABOUT
- BEGIN
- DIALOG "", IDD_ABOUT2, 10, 10, 150, 110, FS_DLGBORDER, 0
- BEGIN
- CONTROL "Attributes:",100,
- 10, 30, 100, 70,
- WC_STATIC,
- SS_GROUPBOX | WS_VISIBLE
- CONTROL "Highlighted",101,
- 20, 80, 58, 12,
- WC_BUTTON,
- WS_GROUP | WS_TABSTOP | BS_AUTOCHECKBOX | WS_VISIBLE
- CONTROL "Enabled",102,
- 20, 60, 58, 12,
- WC_BUTTON,
- BS_AUTOCHECKBOX | WS_VISIBLE
- CONTROL "Checked",103,
- 20, 40, 58, 12,
- WC_BUTTON,
- BS_AUTOCHECKBOX | WS_VISIBLE
- CONTROL "Okay", DID_OK,
- 10, 10, 50, 14,
- WC_BUTTON,
- WS_GROUP | WS_TABSTOP | BS_PUSHBUTTON | BS_DEFAULT | WS_VISIBLE
- CONTROL "Cancel", DID_CANCEL,
- 80, 10, 50, 14,
- WC_BUTTON,
- BS_PUSHBUTTON | WS_VISIBLE
- END
- END
-
- Figure 19.2 shows the dialog box created by the previous dialog-template
- resource definition:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 19.2 can be found in Section 19.4 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 19.2 Sample Dialog Box
-
-
- 19.5 Using Message and Dialog Boxes
-
- The simplest dialog window is the message box. Most message boxes present
- simple messages and offer the user one, two, or three responses
- (represented by buttons). A message box is easy to use and is appropriate
- when an application requires a clearly defined response to a static
- message. However, message boxes lack flexibility in size and placement on
- the screen, and they are limited in the choices they offer the user.
- Applications that require more control over size, position, and content
- should use regular dialog boxes instead of message boxes.
-
- 19.5.1 Message Boxes
-
- Message boxes provide an easy way for applications to display simple
- messages without creating dialog templates or writing dialog procedures.
- Message boxes are intended mainly for conveying information to users,
- although they do have limited input capabilities.
-
- There are several different kinds of predefined message boxes. There are
- three parts to a message box: the icon, the message, and buttons.
- Applications specify the icons and buttons using message-box style
- constants. Message text is specified by a null-terminated string.
-
- To create a message box, the application calls the WinMessageBox function,
- which displays the message box and processes user input until the user
- selects a button in the message box. The return value of the WinMessageBox
- function indicates which button was selected.
-
- The following code fragment illustrates how to create a message box with a
- default Yes button, a No button, and a question-mark (?) icon. This exam-
- ple assumes that you have defined a string resource with the identifier
- MY_MESSAGESTR_ID in the resource file.
-
- CHAR szMessageString[255];
- USHORT cch;
- USHORT usResult;
-
- cch = WinLoadString(hab,
- (HMODULE) NULL,
- MY_MESSAGESTR_ID,
- sizeof(szMessageString),
- szMessageString);
-
- usResult = WinMessageBox(hwndFrame, /* parent */
- hwndFrame, /* owner */
- szMessageString, /* text */
- (PSZ) "", /* caption */
- MY_MESSAGEWIN, /* window ID */
- MB_YESNO |
- MB_ICONQUESTION |
- MB_DEFBUTTON1); /* style */
-
- if (usResult == MBID_YES)
-
- /* do yes case */
-
- else
-
- /* do no case */
-
- The WinMessageBox function returns predefined values indicating which
- button has been selected. These values are listed in Section 19.6.3.
-
- Note that strings for message boxes should be defined as string resources
- to facilitate program translation for other countries. However, there is a
- danger in using string resources in message boxes that are called in
- low-memory situations. Loading a string resource in these situations could
- cause severe memory problems and cause an application to fail. One way to
- solve this problem is to preload the string resource and make it
- nondiscardable so it will be available when the message box must be
- displayed.
-
- 19.5.1.1 System-Modal Message Boxes
-
- Message boxes are always modal. The default style for a message box is
- application-modal. With this style, a user cannot select another window in
- the same application until the message box is dismissed. However, the user
- can switch to a different application.
-
- It is possible to create a message box that is system-modal. A
- system-modal message box prevents a user from selecting another window in
- the current application or switching to a different application until
- responding to the message box. A system-modal message box is useful when
- displaying a warning to the user that there may be serious problems with
- the system, such as insufficient memory.
-
- There are two levels of modality for system-modal message boxes──soft
- modal and hard modal. A soft-modal message box does not allow keystrokes
- or mouse input to reach any other window, but does allow other messages,
- such as deactivation and timer messages, to reach other windows. A
- hard-modal message box does not allow any messages to reach other windows.
- A hard-modal message box is appropriate for serious system warnings.
-
- A hard-modal message box is created by combining the MB_ICONHAND
- style with the MB_SYSTEMMODAL style. A soft-modal message box is
- created by using the MB_SYSTEMMODAL style with any style other than
- MB_ICONHAND. The MB_SYSTEMMODAL icon is always in memory and is available
- even in low-memory situations.
-
- 19.5.2 Dialog Boxes
-
- When using dialog boxes, an application must load the dialog box, process
- user input, and destroy the dialog box when the user finishes the task.
- The process for handling dialog boxes varies, depending on whether the
- dialog box is modal or modeless. A modal dialog box requires the user to
- dismiss the dialog box before activating another window in the
- application. However, the user can activate windows in different
- applications. A modeless dialog box does not require an immediate response
- from the user. It is similar to a frame window containing control windows.
- The following sections discuss how to use both types of dialog boxes.
-
- 19.5.2.1 Modal Dialog Boxes
-
- Modal dialog boxes present users with information and questions in such a
- way that they must respond before proceeding with other operations in the
- application.
-
- The easiest way to use a modal dialog box is to define a dialog template
- in the resource file and then call the WinDlgBox function, specifying the
- dialog-box resource ID and a pointer to the dialog procedure. The
- WinDlgBox function loads the dialog-box resource, displays the dialog box,
- and handles all user input until the user dismisses the dialog box. The
- dialog procedure receives messages when the dialog box is created
- (WM_INITDLG) and other messages when the user interacts with each dialog
- item, such as entering text in entry fields or selecting buttons.
-
- You must specify both the parent and owner windows when loading a dialog
- box using the WinDlgBox function. Generally, the parent window should be
- HWND_DESKTOP and the owner should be a client window in your application.
-
- Dialog boxes typically contain buttons that send WM_COMMAND messages when
- selected by the user. WM_COMMAND messages passed to the WinDefDlgProc
- function result in the WinDismissDlg function being called, with the
- window ID of the source button as the return code. Dialog boxes with OK or
- Cancel as the only buttons can ignore WM_COMMAND messages, allowing them
- to be passed to the WinDefDlgProc function. The WinDefDlgProc function
- calls the WinDismissDlg function to dismiss the dialog box and returns the
- DID_OK or DID_CANCEL code.
-
- Passing WM_COMMAND messages to the WinDefDlgProc function means that all
- button presses in the dialog box will dismiss the dialog box. If you want
- particular buttons to initiate operations without closing the dialog box
- or if you want to perform some processing without closing the dialog box,
- you should handle the WM_COMMAND messages in the dialog procedure.
-
- If you handle WM_COMMAND messages in the dialog procedure, you must call
- the WinDismissDlg function to dismiss the dialog box. Your dialog
- procedure passes the DID_OK code to the WinDismissDlg function if the user
- selects the OK button or the DID_CANCEL code if the user selects the
- Cancel button.
-
- When you call the WinDismissDlg function or pass the WM_COMMAND message to
- the WinDefDlgProc function, the dialog box is dismissed and the WinDlgBox
- function returns the value passed to the WinDismissDlg function. This
- return value identifies the button selected.
-
- An alternative to using the WinDlgBox function is to call the individual
- functions that duplicate its functionality, as shown in the following code
- fragment:
-
- dlg = WinLoadDlg(...);
- result = WinProcessDlg(dlg);
- WinDestroyWindow(dlg);
-
- After calling the WinProcessDlg function, your dialog procedure must call
- the WinDismissDlg function to dismiss the dialog box. Although the dialog
- box is dismissed (hidden), it still exists. You must call the
- WinDestroyWindow function to destroy a dialog box if it was loaded using
- the WinLoadDlg function. The WinDlgBox function automatically destroys a
- dialog box before returning.
-
- If you want to manipulate individual items in a dialog box or add a menu
- after loading the dialog box (but before calling WinProcessDlg), it is
- better to make individual calls rather than calling the WinDlgBox
- function. Individual calls are also useful for querying individual dialog
- items, such as the contents of an entry-field control after a dialog box
- is closed but before it is destroyed. Destroying a dialog box also
- destroys any dialog-item control windows that are child windows of the
- dialog box.
-
- 19.5.2.2 Modeless Dialog Boxes
-
- A modeless dialog box, unlike a modal dialog box, does not require user
- interaction to activate another window in the current application.
-
- To use a modeless dialog box in an application, you should create a dialog
- template in the resource file, just as for a modal dialog box. Because
- modeless dialog boxes share the screen equally with other frame windows,
- it is a good idea to give modeless dialog boxes a title bar so they can be
- moved around the screen. The following Resource Compiler source fragment
- shows a dialog template for a dialog box with a title bar, a System menu,
- and a Minimize Box.
-
- DLGTEMPLATE IDD_SAMP
- BEGIN
- DIALOG "Modeless Dialog", IDD_SAMP, 80, 92, 126, 130,
- WS_VISIBLE | FS_DLGBORDER,
- FCF_TITLEBAR | FCF_SYSMENU | FCF_MINIMIZE
- BEGIN
-
- /* Put control-window definitions here. */
-
- END
- END
-
- The application loads the dialog resource from the resource file by using
- the WinLoadDlg function, receiving in return a window handle to the dialog
- box. The application treats the dialog box as if it were an ordinary
- window. Messages for the dialog box are dispatched through the event loop
- the application uses for its other windows. In fact, an application can
- have a modeless dialog box as its only window.
-
- The resource for a modeless dialog box is just like that used for a modal
- dialog box. The difference between modal and modeless dialog boxes is in
- the way applications handle input to each box. For a modal dialog, the
- WinDlgBox and WinProcessDlg functions handle all user input to the dialog
- box, preventing access to other windows in the application. For a modeless
- dialog box, the application does not call these functions, relying instead
- on a normal message loop to dispatch messages to the dialog procedure.
-
- The main difference between a modeless dialog box and a standard frame
- window with child control windows is that for a modeless dialog box, an
- application can define child windows for the dialog box in a dialog
- template, automating the creation process of the window and its child
- windows. The same effect can be achieved by creating a standard frame
- window, but the child control windows must be created individually.
-
- It is important that an application keep track of all open modeless dialog
- boxes so that it can destroy all open windows before terminating.
-
- 19.5.2.3 Initializing a Dialog Box
-
- Generally, an application defines a dialog template in its resource file
- and loads the dialog box by calling the WinLoadDlg function or the
- WinDlgBox function (which itself calls WinLoadDlg). The dialog box is
- created as an invisible window unless the window style WS_VISIBLE is
- specified in the dialog template. A WM_INITDLG message is sent to the
- dialog procedure before the WinLoadDlg function returns. As each control
- defined in the template is created, the dialog procedure may receive
- various control notifications before the function returns. A dialog window
- can be destroyed by using the WinDestroyWindow function. The WinLoadDlg
- function returns a handle to the dialog window immediately after creating
- a dialog box.
-
- In general, it is a good idea to define a dialog box as invisible since
- this allows for optimization. For example, an experienced user may rapidly
- type ahead, anticipating the processing of a dialog-box command. In such a
- case, there is no need to display the dialog box because the user has
- finished the interaction before the window can be displayed. This is how
- the WinProcessDlg function works──it does not display a dialog box while
- there are still WM_CHAR messages in the input queue. It allows these
- messages to be processed first.
-
- As control windows in a dialog box are created from the template, strings
- in the template are processed by the WinSubstituteStrings function. Any
- WM_SUBSTITUTESTRING messages are sent to the dialog procedure before the
- WinLoadDlg function returns.
-
- When child windows of a dialog window are created, the
- WinSubstituteStrings function is used so child windows can make
- substitutions in their window text. If any child-window text string
- contains the percent sign (%) substitution character, the length of the
- text string is limited to 256 characters after it is returned from the
- substitution.
-
- 19.5.2.4 Menus in Dialog Boxes
-
- To create a menu bar and menus in a dialog box, an application should
- first load the dialog box to get a handle to the dialog-frame window. The
- dialog-frame window can be associated with a menu resource by calling the
- WinLoadMenu function. This function requires arguments specifying the menu
- ID and handle of the parent window for the menu. Finally, the dialog-frame
- window must incorporate the menu by sending a WM_UPDATEFRAME message to
- the dialog box. The following code fragment illustrates these operations:
-
- /* Get the dialog resource. */
-
- hwndDialog = WinLoadDlg(...);
-
- /* Get the menu resource and attach it to the dialog. */
-
- hwndMenu = WinLoadMenu(hwndDialog, ...);
-
- /* Inform the dialog that it has a new menu. */
-
- WinSendMsg(hwndDialog, WM_UPDATEFRAME, 0L, 0L);
-
- Applications can create menus in modal and modeless dialog boxes. The code
- fragment above can be used for either type of dialog box. In the case of a
- modal dialog box, your application should call the WinProcessDlg function
- to handle user input until the dialog box is dismissed. For a modeless
- dialog box, your application should call the WinShowWindow function to
- display the dialog box, allowing the message loop to direct messages to
- the dialog box.
-
- 19.5.2.5 Dialog Procedure
-
- The main difference between a dialog procedure and a window procedure is
- that a dialog procedure does not receive WM_CREATE messages. Instead, a
- dialog procedure receives WM_INITDLG messages, which are sent after a
- dialog box is created but before it is displayed. The WM_INITDLG message
- can be used to do the same type of initialization tasks that are handled
- by WM_CREATE messages.
-
- For example, if a dialog box contains a list box, you should use the
- message WM_INITDLG to fill the list box with items. This procedure can
- also be used to enable or disable buttons in a dialog box, depending on
- your application.
-
- You can also call the WinSetDlgItemText or WinSetDlgItemShort function
- during dialog initialization to set up text items that reflect the current
- conditions in your application.
-
- Another typical task for the WM_INITDLG message handler is centering a
- dialog on the screen or within its owner window. The following code
- fragment illustrates how to center a dialog box on screen using the
- WM_INITDLG message:
-
- case WM_INITDLG:
- /* Center the dialog box and get the screen rectangle. */
-
- WinQueryWindowRect(HWND_DESKTOP, &rclScreenRect);
-
- /* Get the dialog-box rectangle. */
-
- WinQueryWindowRect(hwnd, &rclDialogRect);
-
- /* Get the dialog-box width. */
-
- sWidth = (SHORT) (rclDialogRect.xRight - rclDialogRect.xLeft);
-
- /* Get the dialog-box height. */
-
- sHeight = (SHORT) (rclDialogRect.yTop - rclDialogRect.yBottom);
-
- /* Set the lower-left corner horizontal coordinate. */
-
- sBLCx = ((SHORT) rclScreenRect.xRight - sWidth) / 2;
-
- /* Set the lower-left corner vertical coordinate. */
-
- sBLCy = ((SHORT) rclScreenRect.yTop - sHeight) / 2;
-
- /* Move, size, and show the window. */
-
- WinSetWindowPos(hwnd,
- HWND_TOP,
- sBLCx, sBLCy,
- 0, 0, /* ignores size arguments */
- SWP_MOVE);
-
- return 0L;
-
- The dialog procedure receives notification messages from each
- control-window item in a dialog box whenever a user clicks an item or
- enters text in an entry field. Most dialog procedures wait for the user to
- select one or more dialog-window buttons to signal that he or she has
- finished with the dialog box. When the dialog procedure receives one of
- these messages, it should call the WinDismissDlg function, as shown in the
- following code fragment. The second argument to the WinDismissDlg function
- is the value returned by the WinDlgBox or WinProcessDlg function.
- Generally, the ID of the button that was pressed is returned.
-
- MRESULT FAR PASCAL SampDialogProc(hwnd, usMessage, mp1, mp2)
- HWND hwnd;
- USHORT usMessage;
- MPARAM mp1;
- MPARAM mp2;
- {
- switch (usMessage) {
- case WM_COMMAND:
- switch (SHORT1FROMMP(mp1)) {
- case DID_OK:
-
- /*
- * Final dialog-item queries,
- * dismiss the dialog.
- */
-
- WinDismissDlg(hwnd, DID_OK);
- return 0L;
- }
- break;
- }
- return (WinDefDlgProc(hwnd, usMessage, mp1, mp2));
- }
-
- Other dialog-box items send notification messages specific to the type of
- control window. Your dialog procedure should respond to notification
- messages from each dialog item. Any messages that a dialog procedure does
- not handle should be passed to the WinDefDlgProc function for default
- processing. The default dialog procedure is exactly the same as the
- default frame-window procedure.
-
- The WM_COMMAND message from the OK button indicates that the user has
- selected the OK button and is finished with the dialog box. If the dialog
- box has other controls, such as entry fields or check boxes, your dialog
- procedure should query the contents or state of each control when it
- receives a message from the OK button. Before dismissing a dialog box,
- your dialog procedure should collect input from each dialog-box control
- before closing the dialog box.
-
- 19.5.2.6 Manipulating Dialog Items
-
- Dialog items are control windows, and as such they can be manipulated
- using standard window-management function calls. The window handle is
- obtained for each dialog item by calling the WinWindowFromID function and
- passing the window handle for the dialog box and the window ID for the
- dialog item as defined in the dialog template. For example, the following
- Resource Compiler source-code fragment should be included in your dialog
- template:
-
- DLGTEMPLATE IDD_ABOUT
- BEGIN
- DIALOG "", IDD_ABOUT, 80, 92, 126, 130, FS_DLGBORDER, 0
- BEGIN
- PUSHBUTTON "My Button", ITEMID_MYBUTTON, 37, 107, 56, 12
-
- /* Other item definitions ... */
-
- END
- END
-
- Based on the above code fragment, your application will receive the
- button-item handle by initiating the following call to the WinWindowFromID
- function:
-
- hwndItem = WinWindowFromID(hwndDialog, ITEMID_MYBUTTON);
-
- Applications often change the contents, enabled state, or position of
- dialog items at run time. For example, in a dialog box that contains a
- list box of filenames and an Open button, the Open button should be
- disabled until the user selects a file from the list. To do this, the
- button should be defined as disabled in the dialog resource so that it is
- disabled when the dialog box is first displayed. At run time, the dialog
- procedure receives a notification message from the list box when the user
- selects a file. At that time, the dialog procedure calls the
- WinEnableWindow function to enable the Open button.
-
- Applications can also change the text in static dialog items and buttons.
- This is done by calling the WinSetWindowText function and using the window
- handle of particular dialog item.
-
-
- 19.6 Summary
-
- The following sections summarize the styles, functions, and messages
- associated with dialog windows and message boxes.
-
- 19.6.1 Dialog-Window Styles
-
- The following style constants can be used to specify the border and
- alignment of a dialog box:
-
- FCF_DLGBORDER Draws the dialog window with a double border that
- identifies it as a dialog box.
-
- FCF_MOUSEALIGN Draws the dialog window using the x- and y-position
- relative to the mouse position at the time the dialog window is created.
- The dialog window position is modified to keep it within the screen
- boundaries, if possible. The dialog window can be drawn with the OK button
- under the mouse pointer by using negative x- and y-position values in the
- dialog template.
-
- FCF_SCREENALIGN Draws the dialog window using the x- and y-position
- relative to the coordinates of the entire screen rather than using the
- default coordinates of the owner window.
-
- 19.6.2 Message-Box Styles
-
- The following style constants can be used to specify the type of message
- box created by calling the WinMessageBox function:
-
- MB_ABORTRETRYIGNORE Creates a message box that has Abort, Retry, and
- Ignore buttons.
-
- MB_APPLMODAL Creates an application-modal message box. A user cannot
- select other windows in the current application, but can switch to other
- applications.
-
- MB_CANCEL Creates a message box that has a Cancel button.
-
- MB_DEFBUTTON1 Defines the first button in a message box as the default
- button. All message boxes have this style unless MB_DEFBUTTON2 or
- MB_DEFBUTTON3 is specified.
-
- MB_DEFBUTTON2 Defines the second button as the default button.
-
- MB_DEFBUTTON3 Defines the third button as the default button.
-
- MB_ENTER Creates a message box that has an Enter button.
-
- MB_ENTERCANCEL Creates a message box that has Enter and Cancel buttons.
-
- MB_HELP Creates a message box that has a Help button.
-
- MB_ICONASTERISK Creates a message box that has an asterisk (*) icon.
-
- MB_ICONEXCLAMATION Creates a message box that has a exclamation-point (!)
- icon.
-
- MB_ICONHAND Creates a message box that has the hand icon. This icon is
- always in memory and should be used when displaying message boxes in
- low-memory situations.
-
- MB_ICONQUESTION Creates a message box that has a question-mark (?) icon.
-
- MB_MOVEABLE Creates a message box that a user can move by using the
- mouse.
-
- MB_NOICON Creates a message box that has no icons.
-
- MB_OK Creates a message box that has an OK button.
-
- MB_OKCANCEL Creates a message box that has OK and Cancel buttons.
-
- MB_RETRYCANCEL Creates a message box that has Retry and Cancel buttons.
-
- MB_SYSTEMMODAL Creates a system-modal message box. A user cannot select
- any other window in the current application or switch to another
- application until this message box is dismissed. This style is used in
- combination with MB_ICONHAND to prevent any messages from being sent to
- other windows or applications. This is useful in situations where the
- system is damaged or there are other serious problems.
-
- MB_YESNO Creates a message box that has Yes and No buttons.
-
- MB_YESNOCANCEL Creates a message box that has Yes, No, and Cancel
- buttons.
-
- 19.6.3 Message-Box Return Values
-
- The following are predefined values returned by the WinMessageBox
- function, indicating which button is pressed to dismiss the message box:
-
- MBID_ABORT Abort button dismisses the message box.
-
- MBID_CANCEL Cancel button dismisses the message box.
-
- MBID_ENTER Enter button dismisses the message box.
-
- MBID_ERROR An error has occurred in processing the message box.
-
- MBID_HELP Help button dismisses the message box.
-
- MBID_IGNORE Ignore button dismisses the message box.
-
- MBID_NO No button dismisses the message box.
-
- MBID_OK OK button dismisses the message box.
-
- MBID_RETRY Retry button dismisses the message box.
-
- MBID_YES Yes button dismisses the message box.
-
- 19.6.4 Functions
-
- The following functions are used with dialog windows and message boxes:
-
- WinAlarm Creates an audible signal. The type of sound is specified by one
- of three predefined constants: WA_WARNING, WA_NOTE, and WA_ERROR. The
- actual sound emitted for these styles varies, depending on the hardware
- capabilities.
-
- WinCreateDlg Functions similarly to the WinLoadDlg function except that
- the WinCreateDlg function dialog template is in memory rather than in a
- resource file. This function returns a handle to the dialog window.
-
- WinDefDlgProc Creates the default dialog procedure that processes dialog
- messages (messages that the application dialog procedure does not
- process). This action is identical to that produced by the
- WinDefWindowProc function for frame windows.
-
- WinDestroyWindow Destroys the dialog window and all its child control
- windows. This function uses the dialog-window handle.
-
- WinDismissDlg Hides the dialog box and causes the WinProcessDlg or
- WinDlgBox function to return a specified result. Applications call this
- function from a dialog procedure when a user selects a button indicating
- the interaction with the dialog box is finished.
-
- WinDlgBox Loads and processes a modal dialog box and returns the result
- generated by the WinDismissDlg function. This function makes the dialog
- box visible when the message queue is empty. This means that a dialog box
- defined as invisible will not become visible as long as there is input for
- it. This allows a user to type ahead and even dismiss the dialog box
- before the dialog box becomes visible, thus saving the time needed to draw
- the dialog box. The WinDlgBox function is equivalent to the following code
- fragment:
-
- dlg = WinLoadDlg(...);
- result = WinProcessDlg(dlg);
- WinDestroyWindow(dlg);
- return (result);
-
- WinEnumDlgItem Searches dialog-box child windows for the next control
- window that fits a specified characteristic. An application can specify a
- child window from which to start the search; this facilitates repeated
- linear searches for the next occurrence of a particular type of child
- window. This function allows an application to identify the next tabstop
- or group item.
-
- WinLoadDlg Loads a dialog resource from a specified resource-file module
- (NULL indicates the current application's executable file). The parent and
- owner window of the new dialog box must specified, as well as a pointer to
- the dialog procedure for the application. This function returns a handle
- to the dialog window.
-
- WinMapDlgPoints Converts dialog coordinates into window coordinates and
- vice versa.
-
- WinMessageBox Creates a modal message box with specified caption, icon,
- buttons, and text. The WinMessageBox function maintains control until the
- user selects one of the message-box buttons. The return value is a
- predefined constant that indicates which button is selected.
-
- WinProcessDlg Processes messages for a modal dialog box, making the
- dialog box visible when the message queue is empty. This means that a
- dialog box defined as invisible will not become visible as long as there
- is input for it. This allows a user to type ahead and even dismiss the
- dialog box before the dialog box becomes visible, thus saving the time
- needed to draw the dialog box. This function does not return until the
- dialog procedure calls the WinDismissDlg function.
-
- WinQueryDlgItemShort Translates the text of a specified dialog item into
- a short integer.
-
- WinQueryDlgItemText Retrieves the window text of a specified dialog item.
-
- WinSendDlgItemMsg Sends a message to a child window in the specified
- dialog box. This function is used for child windows in standard frame
- windows.
-
- WinSetDlgItemShort Sets the text of the specified dialog item to the text
- representation of the specified short integer.
-
- WinSetDlgItemText Sets the window text for a specified dialog item.
-
- WinSubstituteStrings Performs a substitution process on a text string,
- replacing certain marker characters with application-supplied text. When
- the string %n (where "n" is a number from 0 through 9) is encountered in
- the source string, a WM_SUBSTITUTESTRING message is sent to a specified
- window. This message returns a text string that replaces the characters %n
- in the destination string, which is an exact copy of the source string.
- This function is important for dialog boxes because the
- WM_SUBSTITUTESTRING message is received by the dialog procedure, allowing
- an application to make string substitutions in dialog items that reflect
- the current environment.
-
- 19.6.5 Messages Sent to Dialog Boxes and Dialog Items
-
- The following messages are sent to dialog boxes and dialog items:
-
- WM_INITDLG Sent to a dialog procedure after a dialog box is created but
- before it is shown. This allows an application to perform run-time
- initialization for the dialog box, such as filling in default text for
- entry fields, static-text controls, or list boxes. If any control window
- in a dialog box requires text substitution, the dialog box receives a
- WM_SUBSTITUTESTRING message before the WM_INITDLG message. The WM_INITDLG
- message also contains a window handle of the control window in the dialog
- box that receives the keyboard focus when the dialog box is shown. An
- application can change the focus by calling the WinSetFocus function for
- another control window and then returning TRUE. To leave the focus as is,
- it should return FALSE.
-
- WM_QUERYDLGCODE Sent by the system to control windows in a dialog box to
- determine the capabilities of the control. Most applications ignore this
- message unless they are creating custom control windows. The following are
- predefined result codes for the WM_QUERYDLGCODE message:
-
- Code Meaning
- ──────────────────────────────────────────────────────────────────────────
- DLGC_BUTTON Button item
-
- DLGC_CHECKBOX Check box
-
- DLGC_DEFAULT Default push button
-
- DLGC_ENTRYFIELD Entry-field item, handles EM_SETSEL messages
-
- DLGC_MENU Menu
-
- DLGC_PUSHBUTTON Non-default push button
-
- DLGC_RADIOBUTTON Radio button
-
- DLGC_SCROLLBAR Scroll bar
-
- DLGC_STATIC Static item
-
- DLGC_TABONCLICK Next-on-tab control
- ──────────────────────────────────────────────────────────────────────────
-
- WM_SUBSTITUTESTRING Sent to a dialog box when it is created (before the
- WM_INITDLG message is sent) when the system encounters the characters %n
- (where n is a number from 0 through 9) in the window text of a dialog
- control window. This message allows an application dialog procedure to
- make text substitutions. For example, an application can define dialog-box
- entry-field text as the characters %1, substituting context-appropriate
- text in the response to the WM_SUBSTITUTESTRING message.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 20 Painting and Drawing
-
- 20.1 Introduction
- 20.2 About Painting and Drawing
- 20.2.1 Presentation Spaces and Device Contexts
- 20.2.2 Window Regions
- 20.3 Strategies for Painting and Drawing
- 20.3.1 When to Draw in a Window
- 20.3.2 The WM_PAINT Message
- 20.3.2.1 Drawing the Minimized View
- 20.3.3 Drawing Without the WM_PAINT Message
- 20.3.4 Three Kinds of Presentation Spaces
- 20.3.4.1 Cached-Micro Presentation Spaces
- 20.3.4.2 Micro Presentation Spaces
- 20.3.4.3 Normal Presentation Spaces
- 20.4 Printing
- 20.5 Summary
- 20.5.1 Window Styles for Painting
- 20.5.2 Functions
- 20.5.3 Messages for Painting
-
- 20.1 Introduction
-
- This chapter describes presentation spaces, device contexts, and window
- regions, and how an application uses them for painting and drawing. (For
- information on functions that are specifically designed for graphics
- production, see Chapter 21, "Drawing in Windows," and Part 3, "Graphics
- Programming Interface.") You should also be familiar with the following
- topics:
-
- ■ Standard user-interface guidelines
-
- ■ Standard frame windows
-
- ■ Window messages and message queues
-
- ■ Presentation spaces and device contexts
-
- ■ Graphics programming interface (GPI)
-
-
- 20.2 About Painting and Drawing
-
- An application typically maintains an internal representation of the data
- that it is manipulating. The information displayed by a screen, window, or
- by printed copy is a visual representation of some portion of that data.
- MS OS/2 provides a rich environment for displaying information in a
- variety of ways. This chapter introduces concepts and strategies necessary
- to make your application function smoothly and cooperatively in the MS
- OS/2 display environment.
-
- 20.2.1 Presentation Spaces and Device Contexts
-
- A presentation space is a data structure maintained by the operating
- system that describes the drawing environment for an application. An
- application can create and hold several presentation spaces, each
- describing a different drawing environment. All drawing in an MS OS/2
- application must be directed into a presentation space.
-
- Each presentation space is associated with a device context that describes
- the physical device where graphics commands are displayed. The device
- context translates graphics commands made to the presentation space into
- commands that cause the physical device to display information. Typical
- device contexts are the screen (windows), printers and plotters, and
- off-screen memory bitmaps. Figure 20.1 shows how graphics commands from
- an application go through a presentation space, to a device context, and
- then to the physical device.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 20.1 can be found in Section 20.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 20.1 Application-to-Device Path
-
- By creating presentation spaces and associating them with particular
- device contexts, an application can control where its graphics output
- appears. Because a presentation space and device context isolate the
- application from the physical details of displaying graphics, the same
- graphics commands can typically be used for many types of displays. This
- virtualization of output can reduce the amount of display code that an
- application needs to support.
-
- This chapter discusses how an application sets up its presentation spaces
- and device contexts before drawing and how to use window-drawing
- functions. Other chapters in this manual discuss the individual graphics
- routines available in MS OS/2.
-
- 20.2.2 Window Regions
-
- A window and the presentation space associated with it have three regions
- that control where drawing takes place in the window. These regions ensure
- that the application does not draw outside the boundaries of the window or
- intrude into the space of an overlapping window.
-
- ╓┌─┌───────────────┌─────────────────────────────────────────────────────────╖
- Region Description
- ──────────────────────────────────────────────────────────────────────────
- Update region This region represents the area of the window that needs
- Region Description
- ──────────────────────────────────────────────────────────────────────────
- Update region This region represents the area of the window that needs
- to be redrawn. This region changes when overlapping
- windows change their Z order or when an application
- explicitly adds an area to the update region to force a
- window to be painted.
-
- Clip region This region and the visible region determine where drawing
- takes place. Applications can change the clip region to
- limit drawing to a particular portion of a window.
- Typically, a presentation space is created with a clip
- region equal to NULL, which means that there is no
- clipping supplied by this region.
-
- Visible region This region and the clip region determine where drawing
- takes place. The system changes the visible region to
- represent the portion of a window that is visible.
- Typically, the visible region is used to mask out
- overlapping windows. When the application calls the
- WinBeginPaint function in response to a WM_PAINT message,
- Region Description
- ──────────────────────────────────────────────────────────────────────────
- WinBeginPaint function in response to a WM_PAINT message,
- the system sets the visible region to the intersection of
- the visible region and the update region to produce a new
- visible region. Applications cannot change the visible
- region directly.
- ──────────────────────────────────────────────────────────────────────────
-
-
- Whenever drawing occurs in a window's presentation space, the output is
- clipped to the intersection of the visible region and the clip region.
- Figure 20.2 shows how the intersection of the visible region and the clip
- region of a window that is behind another window prevents drawing in the
- back window from intruding into the front window. The clip region includes
- the overlapped part of the back window, but the visible region excludes
- that portion of the back window. The system maintains the visible region
- to protect other windows on the screen and the application maintains the
- clip region to specify the portion of the window in which it draws.
- Together, these two regions provide safe and controllable clipping.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 20.2 can be found in Section 20.2.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 20.2 Clip Region and Visible Region
-
- The update region is manipulated by both the system and the application to
- further control drawing. For example, if the windows shown in Figure
- 20.2 switch positions front to back, several changes occur in the regions
- of both windows. The system adds the lower-right corner of the new front
- window to that window's visible region. The system also adds that corner
- area to the window's update region, as shown in Figure 20.3. Adding an
- area to this window's update region causes the window's window procedure
- to receive a WM_PAINT message. During the processing of the WM_PAINT
- message, the system sets the new visible region to be the intersection of
- the previous visible region and the update region. With this restricted
- visible region, only the appropriate part of the window is redrawn──the
- lower-right corner.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 20.3 can be found in Section 20.2.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 20.3 Update Region and Visible Region
-
-
- 20.3 Strategies for Painting and Drawing
-
- The following sections discuss drawing strategies for an MS OS/2
- application. Because an application shares the screen with other windows
- and applications, drawing must not interfere with other applications and
- windows. When these strategies are followed, your application will coexist
- with other applications and still take full advantage of the graphics
- capabilities of MS OS/2.
-
- 20.3.1 When to Draw in a Window
-
- Ideally, all drawing in a window should be done during the processing of
- the WM_PAINT message. Applications maintain an internal representation of
- what should be displayed in the window, such as text or a linked list of
- graphics objects, and use the WM_PAINT message as a cue to display a
- visual representation of that data in the window.
-
- To route all display output through the WM_PAINT message, an application
- should not draw on the screen at the time its data changes. Instead, the
- application should update the internal representation of the data and then
- call the WinInvalidateRect or WinInvalidateRegion function to invalidate
- the portion of the window that needs to be redrawn. Of course, it is often
- much more efficient to draw directly in a window without relying on the
- WM_PAINT message──for example, when drawing and redrawing an object for a
- user who is dragging or sizing with the mouse.
-
- If the window has the WS_SYNCPAINT or CS_SYNCPAINT style, invalidating a
- portion of the window causes a WM_PAINT message to be sent to the window
- immediately. Because sending a message is essentially like making a
- function call, the actions corresponding to the WM_PAINT message are
- carried out before the call that caused the invalidation returns──that is,
- the painting is synchronous.
-
- If the window does not have the WS_SYNCPAINT or CS_SYNCPAINT style,
- invalidating a portion of the window causes the invalidated region to be
- added to the window's update region. The next time the application calls
- the WinGetMsg or WinPeekMsg function when there are no other messages in
- the queue and the update region for the window is not empty, the
- application is sent a WM_PAINT message. If there are many messages in the
- queue the painting occurs after the invalidation──that is, the painting is
- asynchronous. Painting for windows that do not have the WS_SYNCPAINT or
- CS_SYNCPAINT style is a low-priority operation; all other messages are
- processed first. Because a WM_PAINT message is not posted to the queue in
- this case, all invalidation operations since the last WM_PAINT message are
- consolidated into a single WM_PAINT message the next time the application
- has no messages in the queue.
-
- There are advantages to both synchronous and asynchronous painting.
- Windows that have simple painting routines should be painted
- synchronously. Most of the system-defined control windows, such as buttons
- and frame controls, are painted synchronously because they can be painted
- quickly without interfering with the responsiveness of the program.
- Windows with more time-consuming painting operations should be painted
- asynchronously so that the painting can be initiated only when there are
- no other pending messages that might otherwise be blocked while waiting
- for the window to be painted. Also, windows that use an incremental
- approach to invalidating small portions of the window should usually allow
- those operations to consolidate into a single asynchronous WM_PAINT
- message, rather than a series of synchronous WM_PAINT messages.
-
- If necessary, an application can call the WinUpdateWindow function to
- cause an asynchronous window to update itself without going through the
- event loop. WinUpdateWindow sends a WM_PAINT message directly to the
- window if the window's update region is not empty.
-
- 20.3.2 The WM_PAINT Message
-
- A window receives a WM_PAINT message whenever its update region is not
- NULL. A window procedure should respond to a WM_PAINT message by calling
- the WinBeginPaint function, drawing to fill in the update areas, and then
- calling the WinEndPaint function.
-
- The WinBeginPaint function returns a handle to a presentation space that
- is associated with the device context for the window and that has a
- visible region equal to the intersection of the window's update region and
- its visible region. This means that only those portions of the window that
- need to be redrawn are drawn. Attempts to draw outside this region are
- clipped and do not appear on the screen.
-
- If the application maintains its own presentation space for the window, it
- can pass that handle of the presentation space to the WinBeginPaint
- function, which modifies the visible region of the presentation space and
- passes the handle of the presentation-space back to the caller. If the
- application does not have its own presentation space, it can pass a NULL
- presentation-space handle and the system will return a cached-micro
- presentation space for the window. In either case, the application can use
- the presentation space to draw in the window.
-
- The WinBeginPaint function takes a pointer to a RECTL structure that it
- fills in with the coordinates of the rectangle enclosing the area to
- update. The application can use this rectangle to optimize drawing, by
- drawing only those portions of the window that intersect with the
- rectangle. If an application passes a NULL pointer for the rectangle
- argument, the application draws the entire window and relies on the
- clipping mechanism to filter out the unneeded areas.
-
- After the WinBeginPaint function sets the update region of a window to
- NULL, the application does the drawing necessary to fill the update areas.
- If an application handles a WM_PAINT message and does not call
- WinBeginPaint or otherwise empty the update region, the application
- continues to receive WM_PAINT messages as long as the update region is not
- empty.
-
- Once the application has finished drawing, it should call the WinEndPaint
- function to restore the presentation space to its former state. When a
- cached-micro presentation space is returned by the WinBeginPaint function,
- the presentation space is returned to the system for reuse. If the
- application supplies its own presentation space to WinBeginPaint, the
- presentation state is restored to its previous state.
-
- 20.3.2.1 Drawing the Minimized View
-
- When an application creates a standard frame window, it has the option of
- specifying an icon that the system will use to represent the application
- in its minimized state. Typically, if an icon is supplied, the system
- draws the icon in the minimized window and labels the icon with the name
- of the window. If the application does not specify the FS_ICON style for
- the window, the window receives a WM_PAINT message when it is minimized.
- The code in the window procedure that handles the WM_PAINT message can
- determine if the frame window is currently minimized and then draw
- accordingly. Notice that because the WS_MINIMIZED style is relevant only
- for the frame window, not for the client, the window procedure checks the
- frame window rather than the client window. The following code fragment
- shows how to draw a window in the minimized state and the normal state:
-
- case WM_PAINT:
- hps = WinBeginPaint(hwnd, NULL, &rect);
-
- /* See if the frame window (client's parent) is minimized. */
-
- ulStyle = WinQueryWindowULong(WinQueryWindow(hwnd, QW_PARENT,
- FALSE), QWL_STYLE);
-
- if (ulStyle & WS_MINIMIZED) {
- .
- . /* paints the minimized state */
- .
- }
- else {
- .
- . /* paints the normal state */
- .
- }
- WinEndPaint(hps);
- return 0L;
-
- 20.3.3 Drawing Without the WM_PAINT Message
-
- An application can draw in a window's presentation space if it has not
- received a WM_PAINT message. As long as there is a presentation space for
- the window, an application can draw into the presentation space and avoid
- intruding into other windows or the desktop. Applications that draw
- without using the WM_PAINT message typically call the WinGetPS function to
- obtain a cached-micro presentation space for the window and call the
- WinReleasePS function when they have finished drawing. An application can
- also use any of the other types of presentation spaces described in the
- following sections.
-
- 20.3.4 Three Kinds of Presentation Spaces
-
- All drawing must take place within a presentation space. MS OS/2 provides
- three kinds of presentation spaces for drawing: the normal presentation
- space, the micro presentation space, and the cached-micro presentation
- space.
-
- The normal presentation space provides the most functionality, allowing
- access to all the graphics functions of MS OS/2 and allowing the
- application to draw to all device types. The normal presentation space is
- more difficult to use than the other two kinds of presentation spaces and
- it uses more memory. It is created by using the GpiCreatePS function and
- it is destroyed by using the GpiDestroyPS function.
-
- The micro presentation space allows access to only a subset of the MS OS/2
- graphics functions, but it uses less memory and is faster than a normal
- presentation space. The micro presentation space also allows the
- application to draw to all device types. It is created by using the
- GpiCreatePS function and destroyed by using the GpiDestroyPS function.
-
- The cached-micro presentation space provides the least functionality of
- the three kinds of presentation spaces, but it is the most efficient and
- easiest to use. The cached-micro presentation space draws only to the
- screen. It is created and destroyed by using either the WinBeginPaint and
- WinEndPaint functions or the WinGetPS and WinReleasePS functions.
-
- The following sections describe each of the three types of presentation
- spaces in detail and discuss strategies for using each type in an
- application. (For more information, see Chapter 30, "Presentation Spaces
- and Device Contexts.") All three kinds of presentation spaces can be used
- in a single application. Some windows, especially if they will never be
- printed, are best served by cached-micro presentation spaces. Other
- windows may require the more flexible services of micro or normal
- presentation spaces.
-
- 20.3.4.1 Cached-Micro Presentation Spaces
-
- The cached-micro presentation space provides the simplest and most
- efficient drawing environment. It can be used only for drawing on the
- screen, typically in the context of a window. It is most appropriate for
- application tasks that need simple window-drawing functions that do not
- need to be printed. Cached-micro presentation spaces do not support
- retained graphics.
-
- After an application draws to a cached-micro presentation space, the
- drawing commands are routed through an implied device context to the
- current display. The application does not need information about the
- actual device context, since it is assumed to be the display. This process
- makes cached-micro presentation spaces easy for applications to use.
- Figure 20.4 illustrates this process:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 20.4 can be found in Section 20.3.4.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 20.4 Cached-Micro Presentation Space
-
- There are two common strategies for using cached-micro presentation spaces
- in an application. The simplest is to call the WinBeginPaint function
- during the WM_PAINT message, use the resulting cached-micro presentation
- space to draw in the window, and then return the presentation space to the
- system by calling the WinEndPaint function. By using this method, the
- application only interacts with the presentation space when it needs to
- draw in the presentation space. This method is most appropriate for simple
- drawing. A disadvantage of this method is that the application must set up
- any special attributes for the presentation space, such as line color and
- font, each time a new presentation space is obtained.
-
- A second strategy is for the application to allocate a cached-micro
- presentation space during initialization, by calling the WinGetPS function
- and saving the resulting presentation-space handle in a static variable.
- The application can then set attributes in the presentation space that
- persist for the life of the program. The presentation-space handle can be
- used as an argument to the WinBeginPaint function each time the window
- gets a WM_PAINT message; the system modifies the visible region and
- returns the presentation space to the application with its attributes
- intact. This strategy is appropriate for applications that need to
- customize their window-drawing attributes.
-
- A presentation space that is obtained by calling the WinGetPS function
- should be released by calling WinReleasePS when the application has
- finished using it. (Typically, this will be during program termination.) A
- presentation space that is obtained by calling the WinBeginPaint function
- should be released by calling the WinEndPaint function, typically as the
- last part of processing a WM_PAINT message.
-
- 20.3.4.2 Micro Presentation Spaces
-
- The main advantage of a micro presentation space over a cached-micro
- presentation space is that it can be used for printing as well as for
- painting in a window. An applications that uses a micro presentation space
- must explicitly associate it with a device context. This makes the micro
- presentation space useful for painting to a printer, plotter, or an
- off-screen memory bitmap.
-
- A micro presentation space does not support the full set of MS OS/2
- graphics functions. Unlike a normal presentation space, a micro
- presentation space does not support retained graphics.
-
- An application that needs to display in a window and print to a printer or
- plotter typically maintains two presentation spaces: one for the window
- and one for the printing device. Figure 20.5 shows how an application's
- graphics output can be routed through separate presentation spaces to
- produce a screen display and printed copy:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 20.5 can be found in Section 20.3.4.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 20.5 Micro Presentation Space
-
- An application creates a micro presentation space by calling the
- GpiCreatePS function. Because a device context must be supplied at the
- time the micro presentation space is created, an application typically
- creates a device context and then a presentation space. The following code
- fragment demonstrates this by obtaining a device context for a window and
- associating it with a new micro presentation space:
-
- hdc = WinOpenWindowDC(...);
- hps = GpiCreatePS(...,hdc,...,GPIA_ASSOC);
-
- To create a micro presentation space for a device other than the screen,
- replace the call to the WinOpenWindowDC function with a call to the
- DevOpenDC function, which obtains a device context for a device that is
- not the screen. The device context that is obtained by this call can be
- used as an argument to the GpiCreatePS function.
-
- An application typically creates a micro presentation space during
- initialization and uses it until termination. Each time the application
- receives a WM_PAINT message, it should pass the handle of the micro
- presentation space as an argument to the WinBeginPaint function; this
- prevents the system from returning a cached-micro presentation space. The
- system modifies the visible region of the supplied micro presentation
- space and returns the presentation space to the application. This method
- allows the application to use the same presentation space for all drawing
- in a specified window.
-
- Micro presentation spaces created by using the GpiCreatePS function should
- be destroyed by calling the GpiDestroyPS function before the application
- terminates. Do not call the WinReleasePS function to release a
- presentation space obtained by using the GpiCreatePS function. Before
- terminating, applications should also use the DevCloseDC function to close
- any device contexts opened by using the DevOpenDC function. No action is
- necessary for device contexts obtained with the WinOpenWindowDC function,
- since the system automatically closes these device contexts when
- destroying the associated windows.
-
- 20.3.4.3 Normal Presentation Spaces
-
- The normal presentation space supports the full power of MS OS/2 graphics,
- including retained graphics. The main advantages of a normal presentation
- space over the other two presentation-space types are its support of all
- graphics functions, including retained graphics, and its ability to be
- associated with many kinds of device contexts.
-
- A normal presentation space can be associated with many different device
- contexts. Typically, this means that an application creates a normal
- presentation space and associates it with a window device context for
- screen display. When the user asks to print, the application associates
- the same presentation space with a printer device context. Later, the
- application can reassociate the presentation space with the window device
- context. A presentation space can be associated with only one device
- context at a time, but the normal presentation space allows the
- application to change the device context whenever necessary. Figure 20.6
- shows how an application typically routes graphics through one normal
- presentation space into another device context:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 20.6 can be found in Section 20.3.4.3 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 20.6 Normal Presentation Space
-
- A normal presentation space can be associated with a device context when
- the normal presentation space is created, or association can be deferred
- to a later time. The GpiAssociate function associates a device context
- with a normal presentation space after the presentation space has been
- created. An application typically associates the normal presentation space
- with a device context when calling the GpiCreatePS function and later
- associates the presentation space with a different device context by
- calling GpiAssociate. To obtain a device context for a window, call the
- WinOpenWindowDC function. To obtain a device context for a device other
- than the screen, call the DevOpenDC function.
-
- An application typically creates a normal presentation space during
- initialization and uses it until termination. Each time the application
- receives a WM_PAINT message, it should pass the handle of the normal
- presentation space as an argument to the WinBeginPaint function; this
- prevents the system from returning a cached-micro presentation space. The
- system modifies the visible region of the supplied normal presentation
- space and returns the presentation space to the application. This method
- allows the application to use the same presentation space for all drawing
- in a specified window.
-
- Normal presentation spaces created by using the GpiCreatePS function
- should be destroyed by calling the GpiDestroyPS function before the
- application terminates. Do not call the WinReleasePS function to release a
- presentation space obtained by using the GpiCreatePS function. Before
- terminating, applications should also use the DevCloseDC function to close
- any device contexts opened by using the DevOpenDC function. No action is
- necessary for device contexts obtained with the WinOpenWindowDC function,
- since the system automatically closes these device contexts when
- destroying the associated windows.
-
-
- 20.4 Printing
-
- Although a detailed discussion of printing is beyond the scope of this
- chapter, printing should be seen as a variation of screen painting. To
- draw in a window, an application issues graphics calls to a presentation
- space associated with a screen device context. To print, the application
- makes graphics calls to a presentation space associated with a printer
- device context. In an application that supports a what-you-see-is-
- what-you-get window display, the printing code should be
- the same as or very similar to the window-display code, as though the
- printed page were an 8 1/2-by-11-inch window. (Of course, many applications
- will optimize printing code to take advantage of such properties of the
- output device as high-resolution page-description languages.)
-
- An application achieves greater device-independence if it does not use
- pels as its drawing unit. For example, if an application does all its
- drawing into a presentation space with PU_LOENGLISH units (.01 inch), a
- 100-unit line is certain to be one inch long on any printing device. The
- presentation space and device context automatically scale a drawing to
- compensate for the resolution of the output device.
-
-
- 20.5 Summary
-
- This section summarizes the window styles related to window painting; the
- functions that control presentation spaces, device contexts, and window
- regions; and the messages related to window painting.
-
- 20.5.1 Window Styles for Painting
-
- Most of the styles relating to window drawing can be set either for the
- window class (CS prefix) or for an individual window (WS prefix). The
- following styles control how the system manipulates the window's regions
- and how the window is notified to paint itself:
-
- WS_CLIPCHILDREN, CS_CLIPCHILDREN All of the child windows of a window
- with this style are excluded from the window's visible region. This style
- protects child windows but more time is required when calculating the
- visible region. This style is normally not necessary, since if the parent
- and child overlap and are both invalidated, the parent is drawn before the
- child. If the child is invalidated independently from the parent, only the
- child is redrawn. If the update region of the parent does not intersect
- the child, drawing the parent should not disturb the child.
-
- WS_CLIPSIBLINGS, CS_CLIPSIBLINGS Any windows that have the same parent as
- a window with this style and that are in front of the window are excluded
- from the window's visible region. This style protects windows with the
- same parent from being drawn in accidentally but requires more time when
- calculating the visible region. This style is appropriate for windows that
- overlap and that have same parent.
-
- WS_PARENTCLIP, CS_PARENTCLIP The visible region for a window with this
- style is the same as the visible region of the parent window. This style
- simplifies the calculation of the visible region but is potentially
- dangerous, since the parent window's visible region is usually larger than
- the child window. Windows with this style should not draw outside their
- boundaries.
-
- WS_SAVEBITS, CS_SAVEBITS The system saves the bits underneath a window
- with this style when the window is displayed. When the window moves or is
- hidden, the uncovered bits are simply restored by the system; there is no
- need to add the area to the uncovered window's update region. Because this
- operation can consume a great deal of memory, it is recommended only for
- transient windows such as menus and dialog boxes, not for main application
- windows.
-
- WS_SYNCPAINT, CS_SYNCPAINT Windows that have this style receive WM_PAINT
- messages as soon as their update regions are not empty and are updated
- immediately (synchronously). For more details on synchronous painting, see
- Section 20.3.1.
-
- CS_SIZEREDRAW A window with this class style receives a WM_PAINT message
- and is completely invalidated whenever the window is resized, even if it
- is made smaller. (Typically, only the uncovered area of a window is
- invalidated when a window is resized.) This class style is useful when an
- application scales graphics to fill the current window.
-
- 20.5.2 Functions
-
- The following functions control presentation spaces, device contexts, and
- window regions:
-
- DevCloseDC Closes a device context created by using the DevOpenDC
- function. Do not use this function to close a device context that was
- created by using the WinOpenWindowDC function.
-
- DevOpenDC Creates a device context for a specified device type.
-
- GpiAssociate Creates an association between a presentation space and a
- device context. Any subsequent drawing to the presentation space goes to
- the specified device. This function is typically used only with normal
- presentation spaces, since micro presentation spaces must be associated
- with a device context during the call to the GpiCreatePS function.
-
- fbGpiCreatePS Creates a handle of a normal or micro presentation space.
- The presentation space can be associated with a specified device context
- at the time of creation (this is mandatory for micro presentation spaces),
- or it can be associated later by using the GpiAssociate function.
-
- GpiDestroyPS Destroys a presentation space. Do not attempt to destroy a
- cached-micro presentation space by using this function.
-
- WinBeginPaint Returns a handle of a presentation space that has a visible
- region equal to the intersection of the window's update region and the
- visible region of the window's presentation space. This function is called
- when a WM_PAINT message is received. If the hps parameter is a valid
- presentation-space handle, the visible region of the presentation space is
- modified and the handle is returned. If the hps parameter is NULL, the
- system returns the handle of a cached-micro presentation space. The update
- region of the window is set to NULL by this function because the system
- assumes that the caller will do all drawing necessary to fill the invalid
- region of the window.
-
- WinEnableWindowUpdate Sets the window-visibility state for subsequent
- drawing, without causing any visible change to the window. This function
- can be used to defer drawing when making a series of changes to a window.
-
- WinEndPaint Indicates that a drawing operation that was started by using
- the WinBeginPaint function is finished. The hps parameter is the
- presentation-space handle returned by WinBeginPaint. A cached-micro
- presentation space is returned to the system for reuse and the drawing
- environment of a previous presentation space is restored.
-
- WinExcludeUpdateRegion Removes the update region from the clip region of
- the specified window. This can be useful for optimization, since it
- prevents drawing in the update region. The application must restore the
- clip region when the exclusion is no longer needed.
-
- WinGetClipPS Returns a clipped presentation space for the specified
- window. The type of clipping depends on the flag settings of the
- function's parameters. The presentation space should be released by using
- the WinReleasePS function.
-
- WinGetPS Returns the handle of a cached-micro presentation space for the
- specified window. The presentation space should be released by using the
- WinReleasePS function.
-
- WinGetScreenPS Returns a presentation-space handle that can be used to
- draw anywhere on the screen.
-
- WinInvalidateRect Adds the specified rectangle to the update region of
- the window. If the specified window has the WS_SYNCPAINT style, it
- receives a WM_PAINT message before WinInvalidateRect returns. This
- function can be used to force part of a window to be repainted. If the
- fIncludeChildren parameter is TRUE, any child windows that intersect the
- invalid rectangle are also invalidated.
-
- WinInvalidateRegion Adds the specified region to the update region of the
- specified window. If the window has the WS_SYNCPAINT style, it receives a
- WM_PAINT message before WinInvalidateRegion returns. This function can be
- used to force a portion of a window to be repainted. If the
- fIncludeChildren parameter is TRUE, any child windows that intersect the
- invalid region are also invalidated.
-
- WinLockWindowUpdate Prevents updates to the specified window and its
- child windows. This is useful if you need to delay updating during
- incremental data changes, such as adding items to a list box. Calling
- WinLockWindowUpdate with NULL for the hwndLockUpdate parameter invalidates
- the windows that were previously locked and causes WM_PAINT messages to be
- sent to those windows.
-
- WinLockVisRegions Locks or unlocks the visible regions of all windows on
- the screen. This function is useful to threads because it prevents the
- visible regions of windows from changing while the thread performs a
- screen operation, such as copying screen pels into a memory bitmap.
-
- WinOpenWindowDC Returns a device-context handle for the specified window.
- Attempting to open more than one device context for a given window is an
- error. The returned device context is automatically closed when the window
- is destroyed; it must not be closed by using the DevCloseDC function.
-
- WinQueryUpdateRect Returns the coordinates of the smallest rectangle that
- encloses the window's update region.
-
- WinQueryUpdateRegion Obtains the update region of the specified window.
-
- WinQueryWindowDC Returns the device-context handle associated with the
- specified window.
-
- WinReleasePS Releases the handle of a cached-micro presentation space
- that was obtained by using the WinGetPS or WinGetClipPS function. This
- function should not be used for presentation-space handles that are not
- cached──that is, WinReleasePS should not be used for presentation spaces
- obtained by using the GpiCreatePS function.
-
- WinValidateRect Removes the specified rectangle from the update region of
- the window. This function can be used to avoid duplicate drawing, by
- signaling that part of the window has been drawn without using the
- WM_PAINT message.
-
- WinValidateRegion Removes the specified region from the update region of
- the window. This function can be used to avoid duplicate drawing, by
- signaling that part of the window has been drawn without using the
- WM_PAINT message.
-
- WinWindowFromDC Returns the handle of the window associated with the
- specified device-context.
-
- 20.5.3 Messages for Painting
-
- The following message is used in the management of window painting:
-
- WM_PAINT This message is sent when some portion of the window needs to be
- repainted. The window procedure should respond to the message by painting
- the relevant portion of the window.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 21 Drawing in Windows
-
- 21.1 Introduction
- 21.2 Window-Drawing Functions
- 21.2.1 Points and Rectangles
- 21.3 Using Window-Drawing Functions
- 21.3.1 Working with Points and Rectangles
- 21.3.2 Scrolling Window Contents
- 21.3.3 Drawing Bitmaps
- 21.3.4 Drawing Text
- 21.4 Summary
-
- 21.1 Introduction
-
- This chapter describes the functions that are specifically designed to
- help you draw in windows. (For information on the complete set of drawing
- functions, see Part 3, "Graphics Programming Interface.") You should also
- be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Standard frame windows
-
- ■ Presentation spaces and device contexts
-
- ■ Graphics programming interface (GPI)
-
-
- 21.2 Window-Drawing Functions
-
- The functions described in this chapter overlap the functionality of
- similar drawing functions provided by the GPI sections of MS OS/2. The
- difference between the Gpi drawing functions and these window-drawing
- functions is that the functions described in this chapter are designed
- specifically for drawing in windows. Because these window-drawing
- functions are less general than the Gpi functions, they are somewhat
- easier to use, but they also offer fewer capabilities than the complete
- set of Gpi functions. The functions described in this chapter offer a
- quick and easy way to create simple graphics. Programmers seeking more
- functionality should use the Gpi functions of MS OS/2.
-
- 21.2.1 Points and Rectangles
-
- All drawing in a window takes place in the context of the window's
- coordinate system. Locations in the window are described by POINTL
- structures that contain an x- and a y-coordinate for the location. The
- lower-left corner of a window always has the coordinates (0,0). The POINTL
- structure has the following form:
-
- typedef struct _POINTL {
- LONG x;
- LONG y;
- } POINTL;
-
- The RECTL structure defines a rectangular area in a window. This structure
- is made up of two points that define the lower-left and upper-right
- corners of the rectangle. The RECTL structure has the following form:
-
- typedef struct _RECTL {
- LONG xLeft;
- LONG yBottom;
- LONG xRight;
- LONG yTop;
- } RECTL;
-
- An empty rectangle is a rectangle that has no area: the right coordinate
- is less than or equal to the left coordinate or the top coordinate is less
- than or equal to the bottom coordinate.
-
- There are two types of rectangles in MS OS/2: inclusive-exclusive and
- inclusive-inclusive. In inclusive-exclusive rectangles the lower-left
- coordinate of the rectangle is included in the rectangle area while the
- upper-right coordinate is excluded from the rectangle area. In an
- inclusive-inclusive rectangle, both the lower-left and the upper-right
- coordinates are included in the rectangle. Figure 21.1 shows both types
- of rectangles:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 21.1 can be found in Section 21.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 21.1 Rectangle Types
-
- The dimensions of an inclusive-exclusive rectangle can be calculated as
- follows:
-
- cx = rcl.xRight - rcl.xLeft;
- cy = rcl.yTop - rcl.yBottom;
-
- The dimensions of an inclusive-inclusive rectangle can be calculated as
- follows:
-
- cx = (rcl.xRight - rcl.xLeft) + 1;
- cy = (rcl.yTop - rcl.yBottom) + 1;
-
- In general, graphics operations involving device coordinates (such as
- regions, bitmaps and bit blits, and window management) use
- inclusive-exclusive rectangles. All other graphics operations, such as Gpi
- functions that define paths, use inclusive-inclusive rectangles.
-
-
- 21.3 Using Window-Drawing Functions
-
- The functions described in this chapter are intended for simple drawing.
- The rectangle functions manipulate and combine rectangles. The drawing and
- scrolling functions perform within a presentation space's coordinate
- system. For more advanced drawing you should use the Gpi functions of MS
- OS/2.
-
- 21.3.1 Working with Points and Rectangles
-
- MS OS/2 includes many functions for manipulating rectangles. Many of these
- functions change the coordinates of a rectangle. Other functions draw in a
- presentation space, using a rectangle to position the drawing operation.
-
- The WinFillRect function fills a rectangle with a specified color. For
- example, to fill an entire window with blue in response to a WM_PAINT
- message, you could use the following code fragment, which is taken from a
- window procedure:
-
- case WM_PAINT:
- hps = WinBeginPaint(hwnd, NULL, NULL);
- WinQueryWindowRect(hwnd, &rect);
- WinFillRect(hps, &rect, CLR_BLUE);
- WinEndPaint(hps);
- return 0L;
-
- A more efficient way of painting a client window is to pass a rectangle to
- the WinBeginPaint function. The rectangle will be set to the coordinates
- of the rectangle that encloses the update region of the window. Drawing in
- this rectangle updates the window; this can make drawing faster if only a
- small portion of the window needs to be painted. This method is shown in
- the following code fragment. Notice that the WinFillRect function uses the
- presentation space and a rectangle defined in window coordinates to guide
- the paint operation.
-
- case WM_PAINT:
- hps = WinBeginPaint(hwnd, NULL, &rect);
- WinFillRect(hps, &rect, CLR_BLUE);
- WinEndPaint(hps);
- return 0L;
-
- Of course, you can draw the entire window during the WM_PAINT message, but
- the graphics output will be clipped to the update region.
-
- The default method of indicating that a particular portion of a window has
- been selected is for the WinInvertRect function to invert the rectangle's
- bits.
-
- The rest of the rectangle functions are mathematical and do not draw. They
- are used to manipulate and combine rectangles to produce new rectangles,
- which can then be used for drawing operations.
-
- The WinMapWindowPoints function converts the points from one
- window-coordinate space to another window-coordinate space. If one of the
- specified windows is HWND_DESKTOP, then screen coordinates are used. This
- function is useful for converting from window coordinates to screen
- coordinates and back again.
-
- 21.3.2 Scrolling Window Contents
-
- An application normally responds to a click in a scroll bar by scrolling
- the contents of the window. This operation typically has three parts.
- First, the application changes its internal data-representation state to
- show what portion of the image should now be in the window. Next, the
- application moves the current image in the window. Finally, the
- application draws in the area that has been uncovered by the scrolling
- operation.
-
- For example, a simple text editor may display a small portion of several
- pages of text in a window. When the user clicks the down arrow of the
- vertical scroll bar, the application should move all the text up one line
- and display the next line at the bottom of the window.
-
- When the user clicks the down arrow of the vertical scroll bar, the client
- window of the frame window that owns the scroll bar receives a message.
- The application responds to this message by changing its internal
- data-representation state to show which line of text is topmost in the
- window, scrolling the text in the window up one line, and drawing the new
- line at the bottom of the window. There is normally no need to completely
- redraw the entire window, because the scrolled portion of the image
- remains valid.
-
- The WinScrollWindow function allows applications to scroll the contents of
- their windows. WinScrollWindow scrolls a specified rectangular area of the
- window by a specified x- and y-offset (in window coordinates). By setting
- the SW_INVALIDATERGN flag for this function, the areas uncovered by the
- scroll are automatically added to the window's update region, causing a
- WM_PAINT message to be sent to the window for those areas.
-
- For example, in the simple text editor described earlier, the following
- call scrolls the text up one line (assuming that iVScrollInc is the height
- of the current font) and adds the uncovered area at the bottom of the
- window to the update region.
-
- /* Scroll, adding new area to update region. */
-
- WinScrollWindow (hwnd, /* window */
- 0, /* x-displacement */
- -(iVScrollInc), /* y-displacement */
- NULL, /* scroll rectangle is entire window */
- NULL, /* clip rectangle is entire window */
- NULL, /* update region */
- NULL, /* update rectangle */
- SW_INVALIDATERGN); /* flags */
-
- When the uncovered area at the bottom of the window is added to the
- window's update region, a WM_PAINT message is sent to the window. When the
- message is received, the window draws the line of text at the bottom of
- the window. If the window has the WS_SYNCPAINT style, the WM_PAINT message
- is sent to the window before the WinScrollWindow function returns.
-
- To optimize scrolling speed for repeated scrolling operations, you can
- omit the SW_INVALIDATERGN flag from the call to the WinScrollWindow
- function. This prevents WinScrollWindow from adding the invalid region
- uncovered by the scroll to the window's update region. If the
- SW_INVALIDATERGN flag is omitted, you must pass a region or rectangle to
- WinScrollWindow. The rectangle or region will contain the area that needs
- to be updated after scrolling.
-
- 21.3.3 Drawing Bitmaps
-
- The WinDrawBitmap function draws a bitmap, specified by a bitmap handle,
- in a specified rectangle. This function allows you to shrink or enlarge
- the bitmap from the source rectangle to the destination. WinDrawBitmap can
- also draw in several different copy modes, including using the OR operator
- to combine source and destination pels.
-
- 21.3.4 Drawing Text
-
- There are many ways to draw text in a window in an MS OS/2 application.
- The simplest way is to use the WinDrawText function, which draws a single
- line of text in a specified rectangle, using a variety of alignment
- methods.
-
- The WinDrawText function allows you to set a flag so that the function
- does not draw any text; instead, it returns the number of characters in
- the string that will fit in the specified rectangle. For a section of
- running text, an application could alternate between computation and calls
- to WinDrawText to draw successive lines of text. The DT_WORDBREAK flag in
- the WinDrawText function can be set, when performing this kind of
- repetitive operation, to put line breaks on word boundaries rather than
- between arbitrary characters.
-
-
- 21.4 Summary
-
- The following functions are provided specifically for drawing in windows
- and manipulating rectangles:
-
- WinCopyRect Copies the coordinates of one rectangle to another.
-
- WinDrawBitmap Draws a bitmap in a rectangle, scaling the bitmap to fit,
- if necessary.
-
- WinDrawBorder Draws a rectangle.
-
- WinDrawText Draws a single line of formatted text in a specified
- rectangle.
-
- WinEqualRect Returns TRUE if two rectangles have the same coordinates or
- FALSE if the coordinates are different.
-
- WinFillRect Fills a rectangle with a specified color.
-
- WinInflateRect Enlarges or shrinks the rectangle horizontally and
- vertically by the specified amounts. If the specified values are negative,
- the rectangle is inset.
-
- WinIntersectRect Calculates the intersection of two source rectangles and
- returns the result in a destination rectangle, or returns FALSE if the
- result is an empty rectangle.
-
- WinInvertRect Inverts the pels in a rectangle.
-
- WinIsRectEmpty Returns TRUE if the rectangle is empty (that is, if
- the right coordinate is less than or equal to the left coordinate
- or if the top coordinate is less than or equal to the bottom
- coordinate).
-
- WinMapWindowPoints Converts points from one window-coordinate system to
- another.
-
- WinOffsetRect Changes the left and right coordinates of a rectangle by
- the specified offsets.
-
- WinPtInRect Returns TRUE if the point is inside the rectangle or FALSE if
- it is not.
-
- WinScrollWindow Scrolls the contents of a rectangular area of a window.
- If the proper flags are set, the area uncovered by scrolling is added to
- the window's update region, causing a WM_PAINT message to be sent. The
- application can then respond to the message by drawing in the invalidated
- region of the window.
-
- WinSetRect Sets the rectangle's coordinates.
-
- WinSetRectEmpty Sets the coordinates of a rectangle to (0,0,0,0).
-
- WinSubtractRect Subtracts the coordinates of one rectangle from those of
- another rectangle. This function returns FALSE if the result is an empty
- rectangle.
-
- WinUnionRect Calculates a rectangle that encloses two source rectangles.
- This function returns FALSE if the result is an empty rectangle.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 22 Mouse Pointers and Icons
-
- 22.1 Introduction
- 22.2 About Mouse Pointers
- 22.2.1 Mouse Pointers and Icon Bitmaps
- 22.2.2 Mouse-Pointer Hot Spot
- 22.3 Using a Mouse Pointer in an Application
- 22.3.1 Creating or Loading a Mouse Pointer
- 22.3.2 Changing the Mouse Pointer
- 22.3.3 Drawing an Icon
- 22.3.4 System Bitmaps
- 22.4 Summary
- 22.4.1 Predefined Mouse Pointers
- 22.4.2 Mouse-Pointer Functions
-
- 22.1 Introduction
-
- This chapter describes how to use mouse pointers and icons in your
- applications. You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Resources and using the MS OS/2 Resource Compiler (rc)
-
- ■ Window messages and message queues
-
- ■ Bitmaps
-
-
- 22.2 About Mouse Pointers
-
- Mouse pointers are special bitmaps that MS OS/2 uses to show a user the
- current location of the mouse on the screen. The mouse pointer moves
- around the screen in response to user manipulation.
-
- Mouse pointers are also used to draw icons on the screen, such as graphics
- in message boxes and icons that represent minimized windows on the
- desktop. The data structures for mouse pointers and icon bitmaps are
- identical.
-
- 22.2.1 Mouse Pointers and Icon Bitmaps
-
- Mouse pointers and icons are made up of monochrome bitmaps that MS OS/2
- uses to paint an image of the pointer or icon on the screen. A monochrome
- bitmap is a series of bytes. Each bit corresponds to a single pel in the
- image (the bitmap representing the display typically has four bits for
- each pel).
-
- A mouse pointer or icon bitmap is always twice as tall as it is wide. The
- top half of the bitmap is an AND mask, where the bits are combined using
- the AND operator with the screen bits where the pointer is being drawn.
- The lower half of the bitmap is the XOR mask, which is combined using the
- XOR operator with the destination screen bits.
-
- The combination of the AND and XOR masks results in four possible colors
- in the bitmap. The pels of an icon or pointer can be black, white,
- transparent (the screen color beneath the pel), or inverted (inverting the
- screen color beneath the pel). Figure 22.1 shows the relationship of the
- bit values in the AND and XOR masks:
-
- Figure 22.1 Bit Values in the AND and XOR Masks
-
- AND mask 0 0 1 1
- XOR mask 0 1 0 1
-
- Result Black White Transparent Inverted
-
- 22.2.2 Mouse-Pointer Hot Spot
-
- Each mouse pointer has a hot spot defined as an x- and y-offset from the
- lower-left corner of the mouse-pointer bitmap. The hot spot defines the
- single point that represents the mouse-pointer location. For the
- arrow-shaped pointer, the hot spot is at the tip of the arrow. For the
- cross-hairs pointer, the hot spot is at the center of the cross. Each
- pointer has its own hot spot.
-
-
- 22.3 Using a Mouse Pointer in an Application
-
- Applications typically use mouse-pointer resources to control the
- appearance of the mouse pointer and to draw icons in windows. The
- following sections show how to use mouse pointers in applications.
-
- 22.3.1 Creating or Loading a Mouse Pointer
-
- Before an application can use a mouse pointer, it must first receive a
- handle to the pointer. Most applications load mouse pointers from the
- system or their own resource file. MS OS/2 maintains many predefined mouse
- pointers that an application can use by calling the WinQuerySysPointer
- function. System mouse pointers include all the standard mouse-pointer
- shapes and message-box icons.
-
- You can also load mouse pointers that are defined in the resource file for
- your application. Typically, you define the mouse-pointer resource using
- Icon Editor or a similar program. The resulting mouse pointer or icon can
- then be included in your resource file. This is done by pulling the Icon
- Editor data file into your resource file using the key word POINTER, a
- resource ID number, and a filename for the mouse-pointer data created by
- the Icon Editor. When the mouse-pointer resource is included in the
- resource file, you can use it by calling the WinLoadPointer function,
- specifying the pointer-resource ID and the resource-module handle.
- Typically, the resource resides in the executable file of the application,
- so you can supply NULL for the module handle to indicate the current
- application resource file.
-
- Finally, you can create mouse pointers at run time by constructing a
- bitmap for the pointer and calling the WinCreatePointer function. The
- bitmap must be twice as tall as it is wide, with the first half defining
- the AND mask and the second half defining the XOR mask. You also must
- specify the hot spot when you create a mouse pointer. The handle returned
- can be used to set or draw the mouse pointer.
-
- 22.3.2 Changing the Mouse Pointer
-
- Once you create or load a mouse pointer, you can change its shape by
- calling the WinSetPointer function. The following are three main
- situations where an application typically changes the shape of the mouse
- pointer:
-
- ■ When an application receives a WM_MOUSEMOVE message, there is an
- opportunity to change the mouse pointer based on its location the
- window. If you want the standard arrow pointer, pass this message on to
- the WinDefWindowProc function.
-
- ■ When an application is about to start a time-consuming process during
- which it will not accept user input, the application should display the
- "system-wait" mouse pointer. This pointer is shaped like an hourglass,
- indicating that the user must wait. Once this process is complete, the
- application should reset the mouse pointer to its former shape.
-
- ■ The following code fragment shows how to save the current mouse
- pointer, set the hourglass pointer, and then restore the original mouse
- pointer. Notice that the hourglass pointer is also saved in a global
- variable so that the application can return it when responding to a
- WM_MOUSEMOVE message during a time-consuming process.
-
- /* Get current pointer. */
-
- hptrOld = WinQueryPointer(HWND_DESKTOP);
-
- /* Get wait mouse pointer. */
-
- hptrWait = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE);
-
- /* Save wait pointer to use in WM_MOUSEMOVE processing.*/
-
- hptrCurrent = hptrWait;
-
- /* Set mouse pointer to wait pointer.*/
-
- WinSetPointer(HWND_DESKTOP, hptrWait);
-
- /* Do time-consuming operation; restore original mouse pointer.*/
-
- WinSetPointer(HWND_DESKTOP, hptrOld);
-
- ■ The mouse pointer can be used to indicate the current operational mode
- of an application. For example, a paint program with a palette of
- drawing tools should change the mouse pointer shape to indicate which
- drawing tool is currently in use.
-
- 22.3.3 Drawing an Icon
-
- You can use mouse-pointer resources to draw icons. The WinDrawPointer
- function draws a specified mouse pointer in a specified presentation
- space. Many of the predefined system mouse pointers are standard icons
- displayed in message boxes.
-
- 22.3.4 System Bitmaps
-
- In addition to mouse pointers and icons defined by the system, you can use
- standard system bitmaps by calling the WinGetSysBitmap function. This
- function returns a bitmap handle that is passed to the WinDrawBitmap
- function or one of the Gpi bitmap calls. The system uses standard bitmaps
- to draw portions of control windows such as the system menu, the
- minimize/maximize box, and scroll-bar arrows.
-
-
- 22.4 Summary
-
- The following sections describe the system mouse pointers and the
- functions available for mouse pointers, icons, and system bitmaps.
-
- 22.4.1 Predefined Mouse Pointers
-
- MS OS/2 provides many predefined mouse-pointer shapes. You receive a
- handle to these pointers by using one of the following constants as an
- argument to the WinQuerySysPointer function:
-
- SPTR_APPICON Square icon.
-
- SPTR_ARROW Arrow that points to the upper-left corner of the screen.
-
- SPTR_ICONERROR Icon containing an exclamation point, used in a warning
- dialog box.
-
- SPTR_ICONINFORMATION Octagon-shaped icon containing the image of a human
- hand, used in a warning dialog box.
-
- SPTR_ICONQUESTION Icon containing a question mark, used in a query dialog
- box.
-
- SPTR_ICONWARNING Icon containing an asterisk, used in a warning dialog
- box.
-
- SPTR_MOVE Four-headed arrow, used when dragging an object or window
- around the screen.
-
- SPTR_SIZENESW Two-headed diagonal arrow that points from the upper-right
- (northeast) window border to the lower-left (southwest) window border,
- used when sizing a window.
-
- SPTR_SIZENS Two-headed arrow that points from top to bottom (north to
- south), used when sizing a window.
-
- SPTR_SIZENWSE Two-headed diagonal arrow that points from the upper-left
- (northwest) window border to the lower-right (southeast) window border,
- used when sizing a window.
-
- SPTR_SIZEWE Two-headed arrow that points from left to right (west to
- east), used when sizing a window.
-
- SPTR_TEXT Text-insertion and selection pointer, often called the I-beam
- pointer.
-
- SPTR_WAIT Hourglass, used to indicate that a time-consuming operation is
- in progress.
-
- MS OS/2 contains a second set of predefined mouse pointers that are used
- as icons in Presentation Manager. The resulting mouse pointer must be
- explicitly destroyed using the WinDestroyPointer function before the
- application terminates. These icons are available for application use by
- supplying one of the following constants to the WinQuerySysPointer
- function:
-
- SPTR_FILE Icon representing a single file (in the shape of a single sheet
- of paper). It must be explicitly destroyed before the application
- terminates.
-
- SPTR_FOLDER Icon representing a file folder. It must be explicitly
- destroyed before the application terminates.
-
- SPTR_ILLEGAL Circular icon containing a slash, used to indicate an
- illegal operation. It must be explicitly destroyed before the application
- terminates.
-
- SPTR_MULTFILE Icon representing multiple files. It must be explicitly
- destroyed before the application terminates.
-
- SPTR_PROGRAM Icon representing an executable file. It must be explicitly
- destroyed before the application terminates.
-
- 22.4.2 Mouse-Pointer Functions
-
- The following mouse-pointer functions can be used in your application:
-
- WinCreatePointer Creates a mouse pointer from a bitmap.
-
- WinDestroyPointer Destroys a pointer or an icon. A pointer can only be
- destroyed by the thread that created it. This function decrements the use
- count of processes that have accessed the pointer. The pointer is deleted
- when the use count reaches zero.
-
- WinDrawPointer Draws the specified mouse pointer (or icon) in a
- presentation space.
-
- WinGetSysBitmap Returns a handle to one of the standard bitmaps provided
- by the system. The bitmap returned can be used for any routine bitmap
- operations. The WinGetSysBitmap function returns a new copy of the system
- bitmap each time it is called.
-
- The following bitmaps are available:
-
- ╓┌─┌───────────────────────┌─────────────────────────────────────────────────╖
- Bitmap Description
- ──────────────────────────────────────────────────────────────────────────
- SBMP_BTNCORNERS Push-button corners.
-
- SBMP_CHECKBOXES Check-box or radio-button check mark.
-
- SBMP_CHILDSYSMENU Smaller version of the system-menu bitmap, used in
- child windows.
-
- SBMP_DRIVE Symbol used by File System to indicate a disk
- drive.
-
- SBMP_FILE Symbol used by File System to indicate a .
-
- SBMP_FOLDER Symbol used by File System to indicate
- subdirectories.
- Bitmap Description
- ──────────────────────────────────────────────────────────────────────────
- subdirectories.
-
- SBMP_MAXBUTTON Maximize button.
-
- SBMP_MENUATTACHED Symbol used to indicate that a menu item has an
- attached, hierarchical menu.
-
- SBMP_MENUCHECK Menu check mark.
-
- SBMP_MINBUTTON Minimize button.
-
- SBMP_PROGRAM Symbol used by File System to indicate that a file
- is an executable program.
-
- SBMP_RESTOREBUTTON Restore button.
-
- SBMP_SBDNARROW Scroll-bar down arrow.
-
- SBMP_SBLFARROW Scroll-bar left arrow.
- Bitmap Description
- ──────────────────────────────────────────────────────────────────────────
- SBMP_SBLFARROW Scroll-bar left arrow.
-
- SBMP_SBRGARROW Scroll-bar right arrow.
-
- SBMP_SBUPARROW Scroll-bar up arrow.
-
- SBMP_SIZEBOX Symbol used to indicate an area of a window that a
- user can click to resize the window.
-
- SBMP_SYSMENU System menu.
-
- SBMP_TREEMINUS Symbol used by File System to indicate that an
- entry in the directory tree is empty.
-
- SBMP_TREEPLUS Symbol used by File System to indicate that an
- entry in the directory tree contains more files.
- ──────────────────────────────────────────────────────────────────────────
-
-
- WinLoadPointer Loads a pointer resource from a resource file into the
- system and returns a mouse-pointer handle. A new copy of the pointer is
- created each time this function is called. Once used, the pointer created
- by this function must be explicitly destroyed by using the
- WinDestroyPointer function.
-
- WinQueryPointer Returns a mouse-pointer handle for the current mouse
- pointer and can be used to restore the mouse pointer after any temporary
- changes.
-
- WinQueryPointerInfo Retrieves information about a specific mouse pointer,
- including its bitmap and its hot-spot coordinates.
-
- WinQueryPointerPos Retrieves the current mouse-pointer position in screen
- coordinates.
-
- WinQuerySysPointer Returns a handle to the specified system mouse
- pointer. You can specify whether you want a handle to the system's copy of
- the mouse pointer or if you want a separate copy for modification.
-
- WinSetPointer Sets the current mouse pointer.
-
- WinSetPointerPos Sets the mouse-pointer position in screen coordinates.
-
- WinShowPointer Shows or hides the mouse pointer.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 23 Cursors
-
- 23.1 Introduction
- 23.2 About Cursors
- 23.3 Using Cursors in an Application
- 23.3.1 Creating a Cursor
- 23.3.2 Destroying a Cursor
- 23.3.3 Showing the Cursor
- 23.3.4 Positioning the Cursor
- 23.4 Summary
-
- 23.1 Introduction
-
- This chapter describes the functions that allow you to use cursors in your
- applications. You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Window activation and deactivation
-
- ■ Keyboard focus
-
-
- 23.2 About Cursors
-
- A cursor is a rectangle that can be shown at any location in a window. It
- is usually used to mark a text-insertion point or to indicate when a
- control window has the keyboard focus. For example, entry-field controls
- use a flashing vertical bar to show the insertion point when the control
- has the keyboard focus. A button control, on the other hand, appears as a
- halftone rectangle the size of the button when the button has the keyboard
- focus. MS OS/2 draws and flashes the cursor, freeing the application from
- handling these details. Note that the cursor has no direct relationship
- with the mouse pointer.
-
-
- 23.3 Using Cursors in an Application
-
- Typically, applications use cursors to mark the text-insertion point in a
- text window or to indicate that a window has the keyboard focus.
-
- There can be only one cursor in use by the system at one time, so windows
- must create and destroy cursors as they gain and lose the keyboard focus.
- The following code fragment shows how an application should respond to a
- WM_SETFOCUS message when using a cursor in a particular window:
-
- case WM_SETFOCUS:
- if (SHORT1FROMMP(mp2)) {
-
- /* gain focus */
-
- WinCreateCursor(...);
- WinShowCursor(hwnd, TRUE);
- } else {
-
- /* lose focus */
-
- WinDestroyCursor(hwnd);
- }
- return 0L;
-
- 23.3.1 Creating a Cursor
-
- An application creates a cursor by calling the WinCreateCursor function.
- Generally, this is done when a window gains the keyboard focus. An
- application specifies the window in which the cursor will be displayed.
- This window may be HWND_DESKTOP, an application window, or a control
- window.
-
- An application specifies the cursor position, in window coordinates, and
- the cursor height and width. It also specifies whether the cursor
- rectangle should be filled, framed, flashing, or halftone.
-
- The cursor width is usually zero (nominal border width is used) for
- text-insertion cursors. This is preferable to a value of 1, since such a
- fine width is almost invisible on a high-resolution monitor. The cursor
- width may also be related to the window size; for example, when a button
- control uses a dotted-line cursor around the button text to indicate
- focus.
-
- Finally, an application can specify a clipping rectangle, in window
- coordinates, that controls the cursor clipping region. Typically, the most
- efficient strategy is to specify NULL, causing the rectangle to clip the
- cursor to the window rectangle.
-
- 23.3.2 Destroying a Cursor
-
- Applications should destroy cursors by calling the WinDestroyCursor
- function when they lose the keyboard focus. It is important that they be
- destroyed when they lose the focus. Manipulating two cursors in MS OS/2
- simultaneously can have unpredictable results and affect other
- applications.
-
- 23.3.3 Showing the Cursor
-
- MS OS/2 maintains a "show level" for the cursor. The cursor is visible
- when the show level is zero. Each time the cursor is hidden, its show
- level is incremented. Each time the cursor is shown, its show level is
- decremented. Because the show/hide relationship is one for one, the show
- level can never go below zero.
-
- An application should show the cursor when it is first created since the
- cursor is created with a show level of 1.
-
- MS OS/2 automatically hides the cursor when the WinBeginPaint function is
- called, and shows the cursor when the WinEndPaint function is called.
- Therefore, there is no conflict with the cursor during WM_PAINT
- processing.
-
- 23.3.4 Positioning the Cursor
-
- An application can set the position of an existing cursor by calling the
- WinCreateCursor function with the CURSOR_SETPOS flag set. This function
- can also be used to move a cursor around a window. Position arguments are
- given in window coordinates. To change the cursor size, destroy the
- current cursor and then create a new one with the desired size.
-
-
- 23.4 Summary
-
- The following section summarizes the functions related to cursor
- management.
-
- WinCreateCursor Creates a new cursor or changes the position of an
- existing cursor. The cursor is created when the window gains the keyboard
- focus (receives a WM_SETFOCUS message with the fFocus parameter set to
- TRUE).
-
- WinDestroyCursor Destroys the cursor. The cursor is destroyed when the
- window loses the keyboard focus (receives a WM_SETFOCUS message with the
- fFocus parameter set to FALSE).
-
- WinShowCursor Shows or hides the cursor. The cursor is visible if its
- show level is zero. Hiding the cursor increments its show level. Showing
- the cursor decrements the show level. The show level cannot go below zero
- (so the cursor can be shown an infinite number of times).
-
- WinQueryCursorInfo Fills in a supplied CURSORINFO data structure with
- information about the cursor, including its size, position, and current
- show level.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 24 Printing
-
- 24.1 Introduction
- 24.2 About Printing
- 24.2.1 The Print Queue and the Spooler
- 24.3 Printing
- 24.3.1 Specifying the Default Printer
- 24.3.2 Opening a Device Context for a Printer
- 24.3.2.1 Logical Address
- 24.3.2.2 Printer-Driver Name
- 24.3.2.3 The Driver-Data Field
- 24.3.2.4 The Data-Type Field
- 24.3.2.5 Using the Print Queue
- 24.3.2.6 Creating a Device Context
- 24.3.3 Starting a Print Job
- 24.3.4 Associating a Presentation Space
- 24.3.5 Drawing for Printing
- 24.3.5.1 Determining Page Size
- 24.3.5.2 Printing a Page
- 24.3.5.3 Finishing a Print Job
- 24.3.6 Destroying the Printer Device Context
- 24.4 Special Printing Topics
- 24.4.1 Page Setup
- 24.4.2 Using a Thread to Print
- 24.4.3 Printing to a File
- 24.4.4 Printing a Bitmap
- 24.4.5 Optimizing Printing for a Particular Printer
- 24.5 Summary
-
- 24.1 Introduction
-
- This chapter describes how to print graphics and text to printers and
- plotters. You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Device contexts and presentation spaces
-
- ■ Window painting
-
- ■ Graphics programming interface (GPI)
-
- ■ Extracting information from the os2.ini file
-
-
- 24.2 About Printing
-
- The graphics model in MS OS/2 is based on presentation spaces and device
- contexts. Applications draw in a presentation space by using Gpi graphics
- functions. The presentation space is associated with a device context that
- translates graphics commands into device-specific operations that display
- graphics on a device. By associating a presentation space with different
- device contexts, an application can direct output to different devices,
- ranging from screen displays to printers and plotters.
-
- The central concept when printing in MS OS/2 is device independence. The
- same graphics commands used to draw on the screen can be used to draw
- graphics. For example, a word processor can display its text in a window
- by calling Gpi character and string-drawing functions. When printing, the
- same application can use the same Gpi functions to draw the text, the only
- difference being that the presentation space is associated with a printer
- instead of with a window. Printing can be thought of as drawing in a
- window the size of a sheet of paper. Figure 24.1 shows how output goes
- through a presentation space to a device context and finally to an output
- device.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 24.1 can be found in Section 24.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 24.1 Application to Device Path
-
- Choosing the appropriate presentation-space units is an important
- consideration in achieving device independence for an application. If you
- use device-independent units, such as LOENGLISH, HIENGLISH, LOMETRIC, or
- HIMETRIC, your graphics commands will produce nearly the same results on
- all devices. If you use the PELS unit, you must explicitly allow for the
- pel size and aspect ratio of the output device.
-
- For example, if you use LOENGLISH units (each unit is 0.01 inch), a call
- to the GpiBox function asking for a 100-unit box produces a 1-inch box on
- any output device, regardless of the pel size or aspect ratio. In
- contrast, if you issue the same command using the PELS unit, the box will
- be one size on the screen (approximately 72 pels per inch) and much
- smaller on a laser printer (300 pels per inch). Additionally, the box will
- not be square on an EGA display because its pels are not square.
-
- Of course, there are limits to the device-independence of MS OS/2
- graphics, depending on the physical limitations of the output device.
- Output typically looks better on a laser printer with 300 pels per inch
- than on a dot-matrix printer with lower resolution. The value of device
- independence is that you do not have to be concerned with the different
- capabilities of each device. Instead, images are drawn in a virtual page
- and the device context makes the best use of the available resolution.
-
- If you use the PELS units, you can do scaling by querying the device
- context to determine the horizontal and vertical resolution. But it is
- much better to use a device-independent measurement unit and allow MS OS/2
- to scale your drawings to the selected device.
-
- 24.2.1 The Print Queue and the Spooler
-
- MS OS/2 provides the means for applications to spool printing jobs so that
- applications do not wait for printing to finish before proceeding with
- other processing. The main components of the spooling capability of MS
- OS/2 are the spooler (pmspool.exe) and the queue processor (pmprint.qpr).
- When an application submits a queued printing job, the graphics commands
- that comprise the print job are output in a device-independent metafile
- format. The queue processor takes the metafile output and sends it to the
- printer, translating the contents into printer-specific commands. (The
- queue processor calls the printer driver to help translate the metafile
- commands into printer-specific commands.)
-
- The spooler may or may not be involved in this process. If it is active,
- the spooler manages the metafile output as a spool file and coordinates a
- queue of spool files waiting to be processed by the queue processor. If
- the spooler is not active, the metafile is passed directly from the
- application to the queue processor. The spooler is an optional
- intermediary between the application and the queue processor.
-
- It is irrelevant to an application whether or not the spooler is active.
- The user determines if the spooler is running by using Control Panel. An
- application should always queue its printing output because this takes
- advantage of the device-independent features of metafiles and the queue
- processor. If the spooler is active, the queued output will be managed by
- the spooler. If the spooler is not active, the spooled output will go
- directly to the queue processor. An application might need to wait longer
- before printing finishes when the spooler is not active.
-
-
- 24.3 Printing
-
- The following sections describe the typical steps for printing from an MS
- OS/2 application. The procedures described here allow you to print to the
- widest range of output devices. Special printing strategies are described
- later in this chapter. The following topics will be discussed:
-
- ■ Specifying the default printer
-
- ■ Opening a device context for a printer
-
- ■ Starting a print job
-
- ■ Associating a presentation space for printing
-
- ■ Drawing the print job in the presentation space
-
- ■ Finishing a print job
-
- ■ Destroying the printer device context
-
- 24.3.1 Specifying the Default Printer
-
- A user specifies each printer attached to a particular system by making
- choices in Control Panel that is part of the user shell. A user can
- install new printer drivers and associate printers with print queues.
- Information about available printers can be found in the os2.ini file. You
- can access this information by calling the WinQueryProfileString function,
- specifying the appropriate sections and keywords.
-
- An application should not set the default printer directly. Applications
- should use the printer specified as the default in the os2.ini file.
-
- Before using a printer with an application, you should know its driver
- name and the logical address. To find this information, find the name of
- the default printer by calling the WinQueryProfileString function for the
- "PM_SPOOLER" section and the "PRINTER" keyword, as shown in the following
- code fragment:
-
- /* Get the default printer name, for example, "PRINTER1." */
-
- cb = WinQueryProfileString(hab,
- "PM_SPOOLER", /* section name */
- "PRINTER", /* keyname */
- "", /* default */
- szPrinter, /* profile string */
- 32); /* maximum characters */
-
- szPrinter[cb-2] = 0; /* remove terminating ";" */
-
- The call to the WinQueryProfileString function fills the supplied string
- variable with the name of the installed printer. A typical printer name is
- "PRINTER1". You use this name of the printer as the keyword specifier and
- "PM_SPOOLER_PRINTER" as the section name, and then call the
- WinQueryProfileString function again to get a string, called the "printer
- details," containing several substrings. The substrings contain the name
- of the printer driver and the name of the logical port that the printer is
- attached to. The following code fragment shows how to use the
- WinQueryProfileString function to extract this information. The code
- fragment assumes that the name of the default printer in the variable
- szPrinter has been filled in by a call to WinQueryProfileString.
-
- /* Get the printer details.
- * Fill in a supplied string with substrings:
- * <physical port>;<driver name>;<queue port>;<network params>;
- * typically "LPT1;IBM4201;LPT1Q;;"
- */
- cb = WinQueryProfileString(hab,
- "PM_SPOOLER_PRINTER", /* section name */
- szPrinter, /* keyname */
- "", /* default */
- szDetails, /* profile string */
- 256); /* maximum characters */
-
- Once you extract the long string of substrings from os2.ini, you must
- parse the string to find the substrings. The string contains four
- substrings: the name of the physical-printer port (for example, LPT1), the
- name of the printer driver (for example, IBM4201), the name of the logical
- port (for example, LPT1Q), and network information (if any). Each
- substring is separated from the next by a semicolon (;), so you can use
- the library function strchr to search for semicolons and return pointers
- to the positions in the string.
-
- There can be more than one driver name. For example, the string might look
- like the following:
-
- LPT1;IBM4201,PSCRIPT;LPT1Q;;
-
- When more than one name is included, the first name is the default name.
- You should always check for a comma (,) in the driver name to make sure
- only one name is returned. Control Panel sometimes appends other
- information to the driver name. You should always parse the driver name
- and strip off text beginning at the period.
-
- Once you determine the name of the driver and the logical address of the
- printer, you can open a device context and a presentation space for the
- printer.
-
- 24.3.2 Opening a Device Context for a Printer
-
- Calls to the WinQueryProfileString function to produce the name of the
- installed-printer driver and logical address. Using this information, you
- can open a device context for a printer. The main role of the device
- context is to translate graphics calls from an application into
- device-specific operations. The device context is associated with a
- presentation space. All drawing in the presentation space is directed to
- the device rather than to the screen.
-
- You open a device context for a printer by calling the DevOpenDC function
- and passing it a pointer to a DEVOPENSTRUC data structure. There are eight
- pointers in DEVOPENSTRUC, but typically only the first four fields must be
- filled (the logical address, the printer-driver name, driver data, and
- data type) to open a device context.
-
- 24.3.2.1 Logical Address
-
- The logical address of a printer is the destination for the print data.
- Generally, you use the third substring of the printer-detail string
- returned by the WinQueryProfileString function, as explained earlier in
- this chapter. You can also print directly to a physical port, such as
- LPT1, by specifying the name of the physical port as the logical address.
- You can also supply a filename to direct print output to a file.
-
- 24.3.2.2 Printer-Driver Name
-
- The printer-driver name identifies the driver that controls the printing
- device. The printer-driver name is usually extracted from the
- printer-detail string in the os2.ini file, as explained earlier in this
- chapter. MS OS/2 adds a filename extension (.drv) to the name you supply.
-
- 24.3.2.3 The Driver-Data Field
-
- The driver-data field points to a printer-specific data structure that
- describes aspects of the page, such as the page layout (portrait or
- landscape) and the default data format (PM_Q_STD or PM_Q_RAW). If you set
- this field to NULL, the printer driver uses the default settings
- established by the user when the printer driver was installed with Control
- Panel. The user can also use Control Panel at any time to change printer
- settings.
-
- If NULL is passed for the driver-data pointer, the settings most recently
- set in Control Panel will be used. Because Control Panel is always
- available, it is not necessary for an application to provide the means to
- change these settings. However, it is possible to change the driver data
- for a particular print job from an application by calling the
- DevPostDeviceModes function.
-
- 24.3.2.4 The Data-Type Field
-
- The data-type field is a string that specifies the print-data format. The
- two possibilities supported by MS OS/2 version 1.1 are PM_Q_STD and
- PM_Q_RAW. You can supply NULL for this field to obtain the default data
- type for the printer.
-
- ■ The PM_Q_STD format contains data generated by Gpi graphics calls,
- including graphics calls to draw text. This format is generally used
- and is the most versatile and printer-independent.
-
- ■ The PM_Q_RAW format contains a printer-specific data stream generated
- by the application rather than by the translated graphics commands of
- the PM_Q_STD format. You should use the PM_Q_RAW format only if you
- know the exact capabilities of the printer. For example, this format
- might be useful for an application that produces its own PostScript
- output directly rather than relying on Gpi commands to be translated by
- the device context. It might also be useful for sending a text stream
- to a printer that does not support graphics. If you use the PM_Q_RAW
- format, you can send the data to the printer by calling DevEscape with
- the DEVESC_RAWDATA control code.
-
- 24.3.2.5 Using the Print Queue
-
- One of the arguments to the DevOpenDC function specifies the type of
- device context to open. The possibilities that are applicable to
- printing-device contexts are OD_QUEUED, OD_DIRECT, and OD_INFO. Generally,
- OD_QUEUED is used to take advantage of the spooling capabilities of MS
- OS/2. If a user has the spooler turned on, graphics calls are captured as
- a spool file and placed in the print queue. The spooler passes the spool
- file to the queue processor for actual printing. Once a queued file has
- been written to its spool file, the application is free to continue with
- other tasks. This means that a user can continue working without waiting
- for a document to print.
-
- Even if the spooler is turned off, you should use a OD_QUEUED device
- context. If the spooler is absent, printing data is passed directly from
- the application to the queue processor where it is processed for final
- output to the device. It does not matter if the spooler is running or not.
- You should always queue your printing output, except when you want to
- bypass the print queue or when you want to open a device context for
- information only. You can use OD_DIRECT when you want to bypass the print
- queue, such as when printing to a file.
-
- You can use OD_INFO to open a device context for information only, such as
- during program initialization when determining the page size of the
- current printer. Knowing the page size of the printer can be used to
- provide on-screen pagination information. However, an application should
- always check the page dimensions before printing because the user may have
- changed the default printer.
-
- 24.3.2.6 Creating a Device Context
-
- Once the device-specific information described earlier in this chapter is
- obtained, you can open the device context. In the DEVOPENSTRUC structure,
- the first three fields point to the driver name, the logical-address name,
- and the DRIVDATA structure, respectively. The device-context type is set
- to OD_QUEUED so that the output will be queued. The following code
- fragment shows how to open a device context, assuming that the
- printer-driver name and the logical-address name have been obtained:
-
- /*
- * Fill in the DEVOPENSTRUC structure
- *
- * The name of the driver and logical address were obtained by calling
- * WinQueryProfileString. The driver data came from DevPostDeviceModes.
- */
-
-
- DEVOPENSTRUC dop;
- PSZ pszDriverName;
- PSZ pszLogAddress;
-
- /*
- * Use WinQueryProfileString to fill in pszDriverName
- * and pszLogAddress.
- */
-
- dop.pszDriverName = pszDriverName; /* from os2.ini */
- dop.pszLogAddress = pszLogAddress; /* from os2.ini */
- dop.pdriv = NULL;
- dop.pszDataType = "PM_Q_STD";
-
- /* Now open the device context. */
- hdcPrinter = DevOpenDC(hab,
- OD_QUEUED,
- "*",
- 4L, /* use first four fields */
- (PDEVOPENDATA) &dop,
- (HDC) NULL);
-
- 24.3.3 Starting a Print Job
-
- Once a device context is successfully opened using a printer driver, a
- "start doc" message must be issued to the device context to tell it a new
- document is starting. The start-doc escape call includes a string that is
- displayed by the queue manager as the print-job name. Typically, a
- filename is supplied as the document name, as shown in the following code
- fragment:
-
- LONG lrc;
-
- /* Start a document. */
-
- lrc = DevEscape(hdcPrinter,
- DEVESC_STARTDOC,
- strlen(pszDocName),
- pszDocName,
- NULL,
- NULL);
-
- 24.3.4 Associating a Presentation Space
-
- The device-context handle returned by the DevOpenDC function is used to
- create a presentation space for drawing. You specify zero for the x- and
- y- dimensions of the presentation space so that the system can make the
- presentation space large enough to include a single page using the
- specified device context. You cannot use a cached-micro presentation space
- for printing. If you use an absolute-measurement environment──for example,
- PU_LOENGLISH or PU_HIMETRIC, graphics will automatically be the same size
- on screen and when printed. If you use PU_PELS, you must scale the
- graphics commands to match the different resolutions of the screen and the
- printer.
-
- SIZEL sizl;
-
- sizl.cx = 0L;
- sizl.cy = 0L;
-
- hpsPrinter = GpiCreatePS(hab, hdcPrinter, &sizl,
- PU_LOENGLISH | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
-
- Another strategy is to use for printing the same presentation space used
- for window painting. This saves creating a new presentation space. In this
- case, the presentation space must be a GPIT_NORMAL presentation space. The
- presentation space must first be disassociated from the device context
- that it has been associated with (usually a window device context), and
- then associated with the printer device context, as shown in the following
- code fragment:
-
- GpiAssociate(hpsWindow, NULL); /* disassociate first */
- .
- .
- .
- GpiAssociate(hpsWindow, hdcPrinter); /* associate with printer */
-
- You must be cautious of the WM_PAINT message during printing operations if
- you use the same presentation space for printing and window drawing. The
- presentation space cannot be used to respond to the paint message while
- the presentation space is associated with the printer device context. For
- more information, see Section 24.4.2.
-
- Once a printer device context has been associated with a presentation
- space, graphics functions can be called to draw each document page.
-
- 24.3.5 Drawing for Printing
-
- Application data images are usually expressed in "world space." This is
- the coordinate system in which all graphics commands are expressed. The
- units of the world space are typically application-convenient units, such
- as 0.01-inch (LOENGLISH). Images are drawn in windows by expressing
- graphics commands in convenient units. The system scales and converts
- these units to the device-specific units of the display so that the image
- appears correct in the window.
-
- If an image is larger than a window, a matrix translation is used to slide
- the coordinate system of the world space to match the coordinate system of
- the window. Figure 24.2 illustrates how a translation might be used to
- map a portion of the world space to a window display space.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 24.2 can be found in Section 24.3.5 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 24.2 World-Space to Device-Space Translation
-
- The central idea behind drawing for printing is that it is very similar to
- drawing for a window that is the size of a piece of paper. The system
- performs the same scaling transformation to convert world-space units to
- device units. This automatic scaling allows the same imaging code to draw
- for both a 72-dot-per-inch impact printer and a 300-dot-per-inch laser
- printer.
-
- 24.3.5.1 Determining Page Size
-
- In order to print images to a printer or plotter, the page size must be
- expressed in convenient units. For example, if you do all your drawing in
- 0.01-inch (LOENGLISH) units, you will need the page size in 0.01-inch
- units rather than in device units (PELS). To determine the page size, call
- the DevQueryCaps function for the given device to get the width and height
- of the device page in device units. These units can be converted to
- presentation-space units by calling the GpiConvert function, as shown in
- the following code fragment:
-
- SIZEL sizl;
-
- /* page size */
-
- DevQueryCaps(hdcPrinter, CAPS_WIDTH, 2L, (PLONG) &sizl);
-
- GpiConvert(hpsWindow, CVTC_DEVICE, CVTC_WORLD, 1L, (PPOINTL) &sizl);
-
- Once the page size has been determined, the image can be divided and drawn
- into pages for printing. Figure 24.3 shows how a multiple-page document
- might be broken into pages, assuming a user has selected portrait mode
- during printer setup. The figure shows how the page size is used to divide
- the world space into pages.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 24.3 can be found in Section 24.3.5.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 24.3 Portrait-Mode Pages in World Space
-
- The page size returned reflects either portrait or landscape mode,
- depending on what the user selects in Control Panel. Figure 24.4 shows
- how these same pages are divided for landscape mode. Notice that no
- additional page rotation or extra support work must be done for landscape
- mode. As long as you use the x- and y-sizes returned by the DevQueryCaps
- and GpiConvert functions, a document will be correctly paginated.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 24.4 can be found in Section 24.3.5.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 24.4 Landscape-Mode Pages in World Space
-
- 24.3.5.2 Printing a Page
-
- Each page of a print job is drawn by making Gpi calls to the world space
- of the presentation space. If a document consists of only one page, then
- the origin of the world space probably corresponds to the origin of the
- device page, so no translation is necessary. To print a multi-page
- document, you must translate world-space coordinates so that they line up
- each page with the origin before drawing.
-
- For example, to print page 2 in Figure 24.4, you would apply a
- translation on the x- and y-axis to slide the desired page so that its
- lower-left corner sits at the origin. Assuming that a SIZEL structure
- holds the horizontal and vertical dimensions of the page, a call to the
- GpiSetDefaultViewMatrix function slides page 2 down and over to the
- origin. Notice that first you call the GpiQueryDefaultViewMatrix function
- to fill in the other values of the nine-element matrix, then the x- and
- y-translation fields are filled in, then the matrix is set.
-
- MATRIXLF matrix;
- SIZEL sizl; /* size of page, in world units */
-
- /* First get the current transformation matrix. */
-
- GpiQueryDefaultViewMatrix(hps, 9, &matrix);
-
- /* Change the x- and y-translation elements. */
-
- matrix.lM31 = -sizl.cx;
- matrix.lM32 = -sizl.cy;
-
- /* Call GpiSetDefaultViewMatrix to translate image to page. */
-
- GpiSetDefaultViewMatrix(hps, 9, &matrix, TRANSFORM_REPLACE);
-
- For a multi-page document, you must call the DevEscape function with the
- DEVESC_NEWFRAME escape at the end of each page to begin a new page. It is
- not necessary to send a DEVESC_NEWFRAME escape after the last page.
-
- 24.3.5.3 Finishing a Print Job
-
- After printing all pages in a print job, you must call the DevEscape
- function with the DEVESC_ENDDOC code telling the queue processor that the
- print job is finished.
-
- 24.3.6 Destroying the Printer Device Context
-
- Once drawing is finished, the presentation space should be disassociated
- from the printer device context. If a special presentation space was
- created for printing, it can be destroyed along with the device context,
- as shown in the following code fragment:
-
- GpiAssociate(hpsPrinter, NULL);
- DevCloseDC(hdcPrinter);
- GpiDestroyPS(hpsPrinter);
-
- However, if an existing presentation space was used for printing, you
- should disassociate the presentation space from the printing device
- context, reassociating the presentation space with its original window
- device context.
-
-
- 24.4 Special Printing Topics
-
- The following sections describe special printing techniques.
-
- 24.4.1 Page Setup
-
- One of the fields in the DEVOPENSTRUC structure, used when opening a
- device context, is pDriverData, a pointer to a DRIVDATA structure. This
- structure contains device-specific information about the page
- configuration (landscape or portrait), page size, default font, and other
- page-configuration details. The size and contents of the DRIVDATA
- structure depend on the printer being used. Typically, a user specifies
- the default configuration information from Control Panel. Control Panel
- stores this information for each printer in the os2.ini file. If NULL is
- supplied for the driver data when opening the device context, the printer
- driver retrieves the system-wide default driver data from os2.ini and uses
- it to configure page characteristics.
-
- An application can always use the page configuration specified by the user
- in Control Panel. If more control is required, calling the
- DevPostDeviceModes function displays a dialog window that can be used to
- specify new page characteristics for individual print jobs. Driver data
- retrieved by this dialog window applies to the current print job. It does
- not change the system default settings.
-
- Figure 24.5 shows a dialog window that fills in the DRIVDATA structure
- for an IBM4201 printer.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 24.5 can be found in Section 24.4.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 24.5 IBM4201 Page Setup
-
- The DevPostDeviceModes function displays the page-setup dialog window. Any
- changes in page setup are reflected in the DRIVDATA structure and passed
- to the DevOpenDC function to obtain a device context matching the page
- characteristics.
-
- The following code fragment shows how to call the DevPostDeviceModes
- function to fill the DRIVDATA structure. You call it first with a NULL
- structure pointer to determine the size of the device-specific structure.
- Using the size value returned, it is possible to allocate memory and pass
- a far pointer to the DevPostDeviceModes function, which in turn fills the
- device information in the structure.
-
- ULONG ulSize;
- PDRIVDATA pdriv;
-
- ulSize = DevPostDeviceModes(hab,
- NULL, /* NULL for data size only */
- pszDriverName, /* driver name */
- NULL, /* device name */
- szPrinter, /* printer name */
- 0L); /* not used here */
-
- /* Now allocate some memory. */
-
- usResult = DosAllocSeg(ulSize, &sel, 0);
-
- pdriv = MAKEP(sel, 0);
-
- ulSize = DevPostDeviceModes(hab,
- pdriv, /* buffer for drivdata */
- pszDriverName, /* driver name */
- NULL, /* device name */
- szPrinter, /* printer name */
- 0L); /* Display dialog. Do not change os2.ini. */
-
- Notice that the last argument to the DevPostDeviceModes function is a long
- word that determines whether or not the function changes the contents of
- the os2.ini file. The following values are valid:
-
- Value Meaning
- ──────────────────────────────────────────────────────────────────────────
- 0 Displays a dialog window for driver data without changing the
- defaults in the os2.ini file. This is appropriate for an
- application that configures a single print job without changing
- system-wide settings.
-
- 1 Displays a dialog window for driver data and writes the new
- driver data, which becomes the default, to the os2.ini file.
- This is appropriate for Control Panel because the new default
- settings affect the entire system. Generally, applications
- should not change the driver data for the entire system.
-
- 2 Does not display a dialog window; returns the default-driver
- data from the os2.ini file. This is useful for saving
- default-driver data with a particular document.
- ──────────────────────────────────────────────────────────────────────────
-
- If you use the DevPostDeviceModes function to set up the driver data for
- an individual document, you should save the driver data along with the
- document so that the settings are available to the user when the document
- is reopened. Be sure the printer driver is the same as it was when the
- driver data was created because the data format is unique to each printer
- driver.
-
- 24.4.2 Using a Thread to Print
-
- An MS OS/2 application should not be unresponsive to user input for an
- extended period of time. Any operation that takes longer than 1 second
- should be carried out in a separate thread, allowing the user-interface
- thread to continue to respond to user input.
-
- Printing typically begins when a user chooses a command from a menu in an
- application. A client window receives a WM_COMMAND message from the menu
- and begins the printing operation. No further mouse clicks or keystrokes
- are processed until the application calls the WinGetMsg or WinPeekMsg
- function again. Therefore, the user cannot interact with an application
- menu or switch to another application until one of these two functions is
- called.
-
- The following are two basic ways to allow an application to remain
- responsive during a lengthy printing operation:
-
- ■ Call the WinGetMsg or WinPeekMsg function at regular intervals during
- printing to handle user input.
-
- ■ Create a separate thread to handle printing. The main thread can
- continue to call the WinGetMsg function while the printing thread
- executes.
-
- Handling user input during printing can cause many problems with data
- integrity and synchronization. For example, should a user be allowed to
- modify a document while it is printing? Semaphores should be used to
- protect shared resources whenever there are potential conflicts.
-
- One simple solution to the data synchronization problem is to create a
- thread for printing and display a message box in the main thread that
- allows a user to cancel printing. The printing thread could periodically
- check a semaphore controlled by a message box to determine if printing has
- been cancelled. This way a user cannot modify data in an application while
- it is printing, but can switch to another application while printing
- continues.
-
- Another possible problem when handling messages during printing is
- receiving WM_PAINT messages. Because printing and window drawing typically
- use the same drawing functions and the same data, drawing routines must be
- reentrant. If the same presentation space is used for window painting and
- printing, an application should not draw in the window when the
- presentation space is associated with the printer device context.
-
- 24.4.3 Printing to a File
-
- Some printer drivers allow data to be sent to a file rather than to a
- device. In particular, a PostScript device driver and a plotter device
- driver direct print data to files if a filename is supplied in the
- pszLogAddress field of the DEVOPENSTRUC structure when opening a device
- context for printing. All output from printing is sent to this file. If
- the file already exists, its data is overwritten. If the file does not
- exist, the device driver creates it. These two device drivers support this
- feature because their data stream is ASCII text. The IBM4201 device
- driver, which sends mostly binary data to the printer, does not support
- printing to a file.
-
- You should open an OD_DIRECT device context when printing to a file.
-
- 24.4.4 Printing a Bitmap
-
- Printing a bitmap requires that the bitmap be converted from its original
- format, which is usually compatible with the video display, to a format
- for the current printing device. The GpiSetBitmap function converts
- bitmaps from one device format to another.
-
- You must perform the following steps to print a bitmap on a printer:
-
- 1. Create a device context and a presentation space for the screen.
-
- 2. Create a memory device context for the screen and associate it with a
- presentation space.
-
- 3. Create a bitmap and attach it to the memory presentation space and
- device context using the GpiSetBitmap function.
-
- 4. Draw the bitmap from the screen presentation space and device context
- to the memory presentation space and device context using the
- GpiBitBlt or GpiWCBitBlt function.
-
- 5. Create a device context and presentation space for the printer.
-
- 6. Create a memory device context for the printer and associate it with a
- presentation space.
-
- 7. Convert the bitmap from the display-memory presentation space and
- device context to the format of the printer-memory presentation space
- and device context.
-
- 8. Attach it to the printer-memory presentation space and device context
- by calling the GpiSetBitmap function.
-
- 9. Draw the bitmap from the printer-memory presentation space and device
- context to the printer presentation space and device context by using
- the GpiBitBlt or GpiWCBitBlt function. Do any scaling necessary to
- correct for resolution differences between the display and the
- printer.
-
- The GpiSetBitmap function converts the different device formats, such as
- color to monochrome, but does not correct for differences in pel
- resolution between devices. For example, if you are printing a screen
- bitmap (typically about 72 pels per inch to a laser printer with 300 pels
- per inch, you must scale the image when converting from the printer-memory
- device context to the device context. You can determine the differences in
- pel resolution by calling the DevQueryCaps function for each device.
-
- 24.4.5 Optimizing Printing for a Particular Printer
-
- You can optimize printing for certain printers not usually available
- through the API by using the DevEscape function. Escape calls are sent to
- the device driver, which must interpret them. The DevEscape function
- signals the beginning and end of documents of single pages, and sends
- printer-specific binary data to a printer.
-
-
- 24.5 Summary
-
- The following functions can be used in setting up a printing operation:
-
- DevCloseDC Closes a device context opened by the DevOpenDC function.
-
- DevEscape Sends escape codes to the specified device. Starts and stops
- printing, signals the end of a page, and sends printer-specific binary
- data to a printer.
-
- DevOpenDC Opens a device context for a printing device.
-
- DevPostDeviceModes Displays a dialog window for a user to specify various
- printer configuration information.
-
- DevQueryCaps Returns information about a specific device, such as the
- width and height of a page.
-
- GpiAssociate Associates a presentation space with a device context for a
- particular printer, or disassociates the presentation space from its
- current device context if a NULL device context is specified.
-
- GpiConvert Converts device units to world coordinates from one coordinate
- system to another.
-
- GpiCreatePS Creates a presentation space that can be associated with a
- printing-device context.
-
- GpiDestroyPS Destroys a presentation space created by the GpiCreatePS
- function.
-
- GpiQueryDefaultViewMatrix Queries the current viewing transformation
- matrix and fills in a supplied MATRIXL structure. This function retrieves
- the current viewing transformation matrix so that the x- and y-translation
- elements can be changed.
-
- GpiSetBitmap Connects a bitmap with a presentation space that is
- associated with a memory device context, converting a bitmap from one
- device format to another, such as converting between the screen and a
- printer.
-
- GpiSetDefaultViewMatrix Sets the viewing transformation matrix so that
- the x- and y-translation values can be used to move portions of a
- world-space image to the origin for printing.
-
- WinQueryProfileString Retrieves the name of the current default printer
- and printer driver from the os2.ini file.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 25 Heaps
-
- 25.1 Introduction
- 25.2 About Heaps
- 25.3 Using a Heap in an Application
- 25.3.1 Creating a Heap
- 25.3.2 Heaps in a Separate Data Segment
- 25.3.3 Moveable Heap Objects
- 25.3.3.1 Moveable Heaps in an Automatic Data Segment
- 25.3.3.2 Moveable Heaps in a Separate Data Segment
- 25.3.4 Allocating Memory from Heaps
- 25.3.5 Deallocating Memory from a Heap
- 25.3.6 Using Dedicated Free Lists
- 25.3.7 Destroying Heaps
- 25.4 Summary
-
- 25.1 Introduction
-
- This chapter describes the functions that allow you to use heaps for
- memory management in your applications. You should also be familiar with
- the following topic:
-
- ■ Memory management in MS OS/2
-
-
- 25.2 About Heaps
-
- A heap is a memory segment containing other memory-block objects that are
- allocated and deallocated by the functions of the heap manager (the group
- of functions that manage heaps in MS OS/2). The heap functions are
- provided to supplement, and in some cases replace, the basic
- memory-management functions of MS OS/2. The heap functions provide more
- functionality than the basic memory-management functions, including
- moveable objects within a segment and faster allocation implementation.
-
- A heap exists within a memory segment. The segment can be the automatic
- data segment of an application or dynamic-link module, or it can be
- another segment that has been allocated explicitly by using the
- DosAllocSeg function. Typically, the heap is part of an automatic data
- segment, and it shares that segment with the application's static data and
- stack. The combined size of the heap, static data, and stack cannot be
- larger than 64K──this is the maximum segment size in MS OS/2. Heaps in
- separate segments also cannot be larger than 64K.
-
- Figure 25.1 shows how a heap can share an automatic data segment with the
- static data and stack:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 25.1 can be found in Section 25.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 25.1 Heap in Automatic Data Segment
-
- A heap typically contains many memory-allocation objects. Each object is
- accessed by an offset (near pointer) from the beginning of the segment.
- Notice that the beginning of the heap is not necessarily at the beginning
- of the segment. For heaps in the automatic data segment, the application
- or dynamic-link module can use the near pointer to the memory object
- directly, because the data-segment selector is implicit. For heaps
- allocated in separate segments, the near pointer must be combined with the
- segment selector to make a far pointer.
-
- A heap can be created so that objects within the heap are moveable. This
- allows the system to rearrange objects on the heap to make more free
- memory available and avoid heap fragmentation.
-
- MS OS/2 attempts to make the heap larger if a memory-allocation request
- cannot be filled by using the existing heap. This growth is controlled by
- setting growth limits when the heap is created.
-
-
- 25.3 Using a Heap in an Application
-
- Applications typically create a heap, allocate and deallocate memory
- blocks in the heap as needed, and destroy the heap when terminating. A
- heap can be created using many different memory sources and it can have
- moveable or nonmoveable memory objects. The following sections discuss how
- to use heaps in applications and dynamic-link libraries.
-
- 25.3.1 Creating a Heap
-
- Applications and dynamic-link libraries create a heap by calling the
- WinCreateHeap function. The heap is created within an automatic data
- segment or in a separate segment, depending on the values of the
- selHeapBase and cbHeap parameters of WinCreateHeap. The possible values of
- these parameters are summarized in the following list:
-
- selHeapBase cbHeap Meaning
- ──────────────────────────────────────────────────────────────────────────
- Zero Zero The calling process is an application that places
- the heap at the end of its automatic data segment.
-
- Selector Nonzero The calling process is either a dynamic-link library
- that places a heap at the end of its automatic data
- segment, or an application or dynamic-link library
- that has explicitly allocated a segment and places
- the heap at the end of the segment.
-
- Selector Zero The calling process is either an application or
- dynamic-link library that has explicitly allocated a
- segment and places a heap in that segment.
-
- Zero Nonzero The calling process is either an application or
- dynamic-link library that places a heap of a
- specific size in a separate segment but does not
- call the DosAllocSeg function.
- ──────────────────────────────────────────────────────────────────────────
-
- In addition to the characteristics of the heap described by the preceding
- list, the creator of the heap may specify whether the heap contains
- moveable objects and whether the functions should check the validity of
- certain arguments to heap-manager functions. The HM_MOVEABLE attribute
- specifies that the heap can contain moveable objects. The HM_VALIDSIZE
- attribute, which can be used only in conjunction with HM_MOVEABLE,
- specifies that the heap manager should check the validity of size
- arguments in heap-deallocation calls. Moveable heap objects allow a more
- flexible memory-management scheme for applications with heavy memory
- requirements.
-
- You must specify the minimum amount the heap will grow each time it
- enlarges to satisfy a memory request. The default minimum is 512 bytes.
-
- The cbMinDed and cbMaxDed parameters of the WinCreateHeap function define
- how many dedicated free lists the heap manager should maintain for the
- heap. Dedicated free lists can make the allocation of fixed-size blocks
- significantly faster, but they are not essential to the operation of the
- heap. Zeros can be passed as values for these parameters to generate the
- default heap behavior without using dedicated free lists. More information
- about dedicated free lists is given later in this chapter.
-
- For more information on the WinCreateHeap function, see the Microsoft
- Operating System/2 Programmer's Reference, Volume 2.
-
- The following code fragment shows how to create a heap with the default
- behavior and the moveable attribute:
-
- hHeap = WinCreateHeap(0, /* uses automatic data segment */
- 0, /* uses HEAPSIZE from .def file */
- 1024, /* minimum size to grow heap */
- 0, /* minimum size of dedicated free list */
- 0, /* maximum size of dedicated free list */
- HM_MOVEABLE);
-
- The ability to share a heap depends upon the sharing attributes of the
- segment containing the heap. Heaps in an application's data segment are
- private to that application. Segments explicitly allocated with the
- DosAllocSeg function are shared or private, depending upon the value of
- the fsAlloc parameter. Segments allocated by using the WinCreateHeap
- function are shareable. Because shared segments cannot shrink, heaps
- within a shared segment also do not shrink.
-
- The heap manager does not prevent multiple threads from calling the heap
- manager with the same heap handle. The calling process must ensure that
- this does not occur.
-
- 25.3.2 Heaps in a Separate Data Segment
-
- One of the options you can specify when creating a heap is that the heap
- will be created in a data segment that is separate from the automatic data
- segment. You might choose this option if there is insufficient space in
- the automatic data segment for the static variables, the stack, and the
- heap. A heap in a separate data segment can occupy up to 64K.
-
- The pointer returned by the WinAllocMem function is an offset value that
- locates the allocated memory block relative to the beginning of the
- segment that contains the heap. If the heap is in a separate segment, you
- must use far pointers to access memory blocks that are allocated on the
- heap. You can determine the far pointer to a heap object by using the
- heap's segment selector and the offset. The WinLockHeap function returns a
- far pointer to the beginning of a specified heap. You can combine the
- selector from this far pointer with the offset to a memory block on the
- heap to produce a far pointer to the heap object, as shown in the
- following code fragment:
-
- HHEAP hHeap;
- SEL selHeap;
- NPBYTE npbObject;
- PBYTE pbObject;
- PVOID pvHeap;
-
- /* Allocate a heap in a separate segment. */
-
- hHeap = WinCreateHeap(0, /* uses a separate segment */
- 32*1024, /* allocates 32K for heap */
- 1024, /* minimum size to grow heap */
- 0, /* minimum size of dedicated free list */
- 0, /* maximum size of dedicated free list */
- HM_MOVEABLE);
-
- /* Allocate an object and retrieve a near pointer. */
-
- npbObject = WinAllocMem(hHeap,...);
-
- /* Retrieve a far pointer to the start of the heap. */
-
- pvHeap = WinLockHeap(hHeap);
-
- /* Make a far pointer to the heap object. */
-
- pbObject = MAKEP(SELECTOROF(pvHeap), npbObject);
-
- 25.3.3 Moveable Heap Objects
-
- A moveable heap allows the memory objects within the heap to move in order
- to reclaim fragmented heap space. All heaps are moveable in the sense that
- a segment that contains a heap can move as a result of the mapping of
- selectors to physical addresses that is provided by MS OS/2. Moveable
- heaps differ from regular heaps in that individual objects within a
- movable heap can change their positions relative to the beginning of the
- segment. The moveable-heap attribute is specified when the heap is created
- and lasts until the heap is destroyed.
-
- Allocated memory blocks in a moveable heap have a header structure that is
- attached to the beginning of the block. This header structure contains a
- pointer to the variable holding the pointer to the memory block and a
- field containing the size of the block (not including the header
- structure). The near pointer returned by the WinAllocMem function points
- to the first byte after the block-header words. The C definition of the
- header structure is as follows:
-
- typedef struct _MOVBLOCKHDR {
- NPBYTE *ppmem;
- USHORT cb;
- } MOVBLOCKHDR;
-
- The size parameter of the WinReallocMem and WinFreeMem functions is
- ignored for objects in a moveable heap and the value of the size word is
- used instead. However, if the HM_VALIDSIZE option is specified in the
- WinCreateHeap function when the heap is created, the WinReallocMem and
- WinFreeMem functions verify that the passed size matches the current size
- and return an error if it does not.
-
- Objects in a moveable heap can move whenever the WinAvailMem function is
- called. Because this function is also called by WinAllocMem and
- WinReallocMem, objects can also move when these functions are called.
- WinReallocMem and WinAvailMem move blocks that have a back pointer.
- Allocated objects whose back pointer is zero are considered fixed and do
- not move.
-
- When allocating memory blocks within a moveable heap, the calling process
- specifies that the block is moveable by altering the back pointer (ppmem)
- field of the header structure so that it points to the variable holding
- the pointer returned by the WinAllocMem function. When WinAllocMem creates
- a block on a moveable heap, it clears the back pointer to zero. As long as
- the back pointer remains zero, the heap manager cannot move the block. If
- the application alters the value of the back pointer so that it points to
- a valid variable address within the same segment (by using an offset from
- the beginning of the segment), the heap manager will move the block, when
- necessary, to compact the heap. Whenever the heap manager moves the
- moveable block it also updates the variable pointed to by the back pointer
- so that the variable points to the new location of the block. The back
- pointer ensures that the application's reference to the moveable block is
- updated when the block moves.
-
- Note that MS OS/2 alters only the variable pointed to by the back pointer
- when it moves a moveable block. If the application has made copies of this
- variable, those copies will be invalid if the memory object moves.
-
- The SETMEMBACKPTR macro sets the back pointer of a moveable block. (It is
- assumed that the MOVBLOCKHDR data structure described above is also
- defined.) SETMEMBACKPTR uses the variable that holds the pointer returned
- by the WinAllocMem function and sets the back pointer of that block to
- point to the variable. The SETMEMPACKPTR macro is shown below. Note that
- it should not be used on nonmoveable heaps.
-
- #define SETMEMBACKPTR(npb) (((PMOVBLOCKHDR) npb) -1) -> ppmem = &npb
-
- The back pointer of a moveable block should point to the variable that
- holds the pointer returned by the WinAllocMem function. Since the back
- pointer is a near pointer, the variable pointed to must be in the same
- data segment as the heap. If the heap is in the automatic data segment
- (the default case), you can use a static or stack-based variable to hold
- the pointer. If the heap is in a separate data segment, you must allocate
- space for the pointer variable as a nonmoveable block on the heap.
-
- Using moveable blocks allows an application to use memory more efficiently
- and to avoid most memory-fragmentation problems. Using moveable heap
- objects, however, requires that the pointer references to the objects
- remain valid even when the objects move. The back pointer allows MS OS/2
- to handle updating an application's pointer variables, but the application
- must use the macro SETMEMBACKPTR to set the original link between the
- moveable block and its pointer variable.
-
- 25.3.3.1 Moveable Heaps in an Automatic Data Segment
-
- Figure 25.2 shows the relationship of the pointer returned by the
- WinAllocMem function and the back pointer of the memory-block header when
- the heap is in the automatic data segment:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 25.2 can be found in Section 25.3.3.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 25.2 Back Pointer for Moveable Heap Object in Automatic Data
- Segment
-
- The following code fragment shows how to allocate a block and then make it
- moveable by altering the value of the back pointer. This code works only
- if the heap is in the automatic data segment (the default case for most
- applications).
-
- static NPBYTE pObject;
-
- /* Allocate the block for the object. */
-
- pObject = WinAllocMem(hHeap, sizeof(YOUR_OBJECT_TYPE));
-
- /* Make the block moveable. */
-
- SETMEMBACKPTR(pObject);
-
- You should avoid placing a pointer to a moveable heap object on the
- stack──that is, making it a local variable──if the heap object will
- continue to exist after the function has ended and the local variable has
- been cleared from the stack. This is dangerous because the heap manager
- could attempt to update the pointer variable, using the back pointer, and
- inadvertently write into the stack frame of another function.
-
- 25.3.3.2 Moveable Heaps in a Separate Data Segment
-
- The variable pointed to by the back pointer must be in the same segment as
- the moveable block. For most applications, in which the heap is in the
- application's automatic data segment, the pointer variable can be in the
- application's static-data area. If the heap is in a separate segment, the
- variable must also be allocated on the same heap, and it must be in a
- nonmoveable block.
-
- Figure 25.3 shows the relationship of the pointer returned by the
- WinAllocMem function and the back pointer of the memory-block header when
- the heap is in a separate data segment:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 25.3 can be found in Section 25.3.3.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 25.3 Back Pointer for Moveable Heap Object in Separate Data
- Segment
-
- Figure 25.3 shows a variable in the application's static-data area that
- points to the nonmoveable block containing the pointer to the moveable
- memory block. The variable that the application uses in its static-data
- area is a pointer to a pointer. Since the pointer to a pointer is pointing
- to another data segment, it must be a far pointer, consisting of the
- selector of the heap's data segment and the offset within that segment.
-
- The following code fragment shows how to allocate a block in a heap in a
- separate data segment and then make the block moveable by altering the
- value of the back pointer. The ppObject variable is declared with the
- static storage class so that it will be in the static area of the
- automatic data segment, rather than on the stack.
-
- static NPBYTE FAR *ppObject;
-
- /*
- * Allocate nonmoveable space for the pointer to the object
- * and make a far pointer to the pointer.
- */
-
- ppObject = MAKEP(SELECTOROF(WinLockHeap(hHeap)),
- WinAllocMem(hHeap, sizeof(NPBYTE)));
-
- /* Allocate the block for the object. */
-
- *ppObject = WinAllocMem(hHeap, sizeof(YOUR_OBJECT_TYPE));
-
- /* Make the block moveable. */
-
- SETMEMBACKPTR(*ppObject);
-
- Once the pointer to a pointer is set up correctly and the back pointer is
- initialized, the ppObject variable should be dereferenced twice whenever
- the moveable memory block is accessed, as shown in the following example:
-
- /* Put a value into the moveable block. */
-
- **ppObject = 2;
-
- 25.3.4 Allocating Memory from Heaps
-
- Once an application or dynamic-link library has created a heap, it can
- allocate blocks on the heap by calling the WinAllocMem function. The value
- returned by this function is a near pointer to the memory block, or NULL
- if the function is unsuccessful.
-
- All pointers to memory objects within a heap are 16-bit offsets from the
- start of the heap's segment. All memory objects in the heap are aligned on
- a 32-bit-word boundary──this means that the contents of the 2 low-order
- bits of a returned pointer are unused. The WinAllocMem function clears
- these bits. (The WinReallocMem and WinFreeMem functions require that they
- be zero.) The application can use these two bits for any purpose. The
- HEAP_MASK constant can be used to clear the bits when passing a parameter
- for a memory-block pointer to WinReallocMem or WinFreeMem.
-
- If the heap is created with the HM_MOVEABLE attribute, the size argument
- for the allocation is retained in the size word of the allocated block's
- header. The returned address is the address of the first byte after the
- header.
-
- The heap manager searches the heap for the first free block large enough
- to fulfill the allocation request. If the free block that is found is
- larger than what is needed to satisfy the request, the extra space is
- added to the appropriate dedicated free list. If no free block is found
- that is large enough, the heap manager attempts to combine free blocks by
- calling the WinAvailMem function. If this call does not generate a large
- enough free block, the heap manager attempts to enlarge the heap segment
- by the combined values of the size of the request and the minimum-growth
- parameter specified in the call to the WinCreateHeap function. If this
- attempt fails, the WinAllocMem function returns NULL, indicating that it
- could not allocate the memory block.
-
- 25.3.5 Deallocating Memory from a Heap
-
- Memory blocks on the heap can be deallocated by calling the WinFreeMem
- function. The calling process must specify the heap handle, the pointer to
- the block, and the size of the block. The size argument must be accurate
- because the heap manager does not normally validate this argument. Passing
- an incorrect size argument to WinFreeMem can damage other blocks on the
- heap.
-
- The WinFreeMem function returns NULL if it successfully deallocates the
- memory block. The return value is NULL for success because of the
- following idiom for deallocating a memory block and invalidating the
- variable that contains the pointer to the block, all in one line of code:
-
- pMem = WinAllocMem(...);
-
- /* Code that uses the block. */
-
- pMem = WinFreeMem(pMem);
-
- For nonmoveable heaps, the heap manager has no way to check the size of
- blocks that it deallocates. For moveable blocks on a heap created with the
- HM_MOVEABLE and HM_VALIDSIZE attributes, the heap manager checks the size
- argument against the size specification in the moveable block's header and
- returns the pointer (instead of NULL) if the size parameter is invalid.
-
- 25.3.6 Using Dedicated Free Lists
-
- A dedicated free list is a linked list of free blocks of a particular size
- on the heap. For example, the heap manager might maintain a dedicated free
- list of memory blocks that are 1024 bytes in length. It is much faster to
- search for a memory block in a dedicated free list than to do a straight
- linear search of all blocks on the heap. Thus, dedicated free lists are
- very useful if your application allocates many blocks with the same size.
-
- The size of memory blocks that should be maintained in dedicated free
- lists is specified when the heap is created. Two arguments to the
- WinCreateHeap function specify the minimum block size and the maximum
- block size to put into dedicated free lists. All memory sizes between the
- minimum and maximum sizes, in four-byte increments, are maintained in
- separate lists.
-
- For example, if you specify 1024 for the minimum size and 2048 for the
- maximum size, the heap manager creates dedicated free lists for memory
- blocks of 1024 bytes, 1028 bytes, 1032 bytes, and so on, through 2048
- bytes. The cost of each dedicated free list is an additional two bytes in
- the heap-control block for each size of memory block that is maintained in
- the list.
-
- Blocks that are not within the size limits of existing dedicated free
- lists are maintained in a single nondedicated free list. The heap manager
- first looks in the dedicated free lists, starting with the list whose
- memory-block size is greater than or equal to the requested size. It
- continues to look in the dedicated free lists until it either finds the
- smallest block that is greater than or equal to the requested size or it
- exhausts the dedicated free lists. If no block is found on the dedicated
- free lists that is large enough, the heap manager does a linear search of
- the nondedicated free list for the first block that satisfies the request.
- (This may not be the smallest free block that would satisfy the request,
- since the order of the nondedicated free list is
- implementation-dependent.) Dedicated free lists are organized in last-in,
- first-out (LIFO) order.
-
- To produce dedicated free lists in a heap, pass nonzero arguments for the
- cbMinDed and cbMaxDed parameters of the WinCreateHeap function.
-
- 25.3.7 Destroying Heaps
-
- The WinDestroyHeap function destroys a heap that was created by using the
- WinCreateHeap function. If WinCreateHeap calls the DosAllocSeg function to
- allocate space for the heap, then WinDestroyHeap calls DosFreeSeg to free
- the allocated segment. Otherwise, WinDestroyHeap frees only the heap
- handle that is passed to it.
-
- The return value is zero if the WinDestroyHeap function is successful.
- Otherwise, the return value is the heap handle that is passed to the
- function. (A reason this function could fail is if the heap handle is
- invalid.) This function is not affected by allocated memory objects within
- the heap.
-
- The return value is zero for success because of the following idiom for
- destroying a heap and invalidating the variable that contains the handle
- to the heap, all in one line of code:
-
- hHeap = WinCreateHeap(...);
-
- /* Code that manipulates the heap. */
-
- hHeap = WinDestroyHeap(hHeap);
-
-
- 25.4 Summary
-
- The following functions allow your application to manage heaps:
-
- WinAllocMem Returns a near pointer to a memory block of the specified
- size on the heap. Returns NULL if the memory cannot be allocated.
-
- WinAvailMem Returns the largest free block of memory on the heap.
-
- WinCreateHeap Creates a heap that can be used for memory management.
-
- WinDestroyHeap Destroys a heap. All memory objects on the heap are lost.
-
- WinFreeMem Frees a memory block that was allocated by using the
- WinAllocMem function.
-
- WinLockHeap Returns a far pointer to the beginning of the segment
- containing the heap and locks the heap. This is useful for a heap
- allocated in a separate segment.
-
- WinReallocMem Reallocates a heap memory block to a new size. If the new
- size is larger than the previous size, a new block is allocated by using
- the WinAllocMem function and the previous block is copied to the new
- block.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 26 Clipboard
-
- 26.1 Introduction
- 26.2 About the Clipboard
- 26.2.1 Cutting, Copying, and Pasting Data
- 26.2.2 Clipboard-Data Formats
- 26.2.3 Shared Memory and the Clipboard
- 26.3 Using the Clipboard
- 26.3.1 Putting Data on the Clipboard
- 26.3.2 Retrieving Data from the Clipboard
- 26.3.3 Becoming the Clipboard Viewer
- 26.3.4 Becoming the Clipboard Owner
- 26.3.5 Custom Clipboard Formats
- 26.3.5.1 Assigning a Unique Format ID
- 26.3.5.2 Display Formats
- 26.3.6 Delayed Rendering
- 26.4 Summary
- 26.4.1 Standard Clipboard Formats
- 26.4.2 Clipboard Functions
- 26.4.3 Clipboard Messages
-
- 26.1 Introduction
-
- This chapter describes how to use the clipboard to transfer data between
- applications. You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Window messages and message queues
-
- ■ MS OS/2 memory management and shared memory
-
-
- 26.2 About the Clipboard
-
- The clipboard is a set of functions that can be used by Presentation
- Manager applications for exchanging data. In particular, the clipboard
- provides support for the generalized cut, copy, and paste user-interface
- common to Presentation Manager applications. The clipboard supports data
- formats common to most applications, as well as allowing individual
- applications to define new formats for special purposes.
-
- The data on the clipboard is maintained in memory only. Clipboard data is
- lost when the computer is turned off.
-
- Data exchange on the clipboard is controlled by the user. An application
- should not perform any clipboard operations unless the user explicitly
- initiates them. Other MS OS/2 features, such as pipes, queues, and shared
- memory should be used when data exchange is needed without the knowledge
- of the user. For example, an application that continuously passes remotely
- collected data to a data-analysis application should not use the
- clipboard. Such an application should use the other interprocess data
- communication capabilities of MS OS/2 instead.
-
- 26.2.1 Cutting, Copying, and Pasting Data
-
- All Presentation Manager programs should support the cut, copy, and paste
- data exchange in a single application and between applications. These are
- all user-initiated operations. Typically, a user selects data in an
- application, called the "current selection." The application should
- provide visual feedback, such as inverting the data display, to indicate
- the current selection. The user can then initiate a cut, copy, or paste
- operation on the current selection.
-
- The standard cut, copy, and paste operations are summarized below:
-
- Operation Description
- ──────────────────────────────────────────────────────────────────────────
- Cut Copies the current selection to the clipboard and deletes the
- current selection from the application document. The previous
- contents of the clipboard are destroyed.
-
- Copy Copies the current selection to the clipboard. The current
- selection remains unchanged. The previous contents of the
- clipboard are destroyed.
-
- Paste Deletes the current selection and replaces it with the contents
- of the clipboard. The contents of the clipboard are not changed.
-
- Clear Deletes the current selection without putting the data on the
- clipboard. The contents of the clipboard are not changed.
- ──────────────────────────────────────────────────────────────────────────
-
- 26.2.2 Clipboard-Data Formats
-
- The clipboard accepts data in several formats. MS OS/2 supports three
- standard formats: text, bitmap, and metafile. Applications can use these
- predefined formats or create their own formats.
-
- Typically, all formats on the clipboard are simply different
- representations of the most recent selection on the clipboard. For
- example, a word processor that supports multiple fonts might write a
- selection to the clipboard in three formats: straight text, rich text, and
- metafile. Another application (pasting from the clipboard) could then
- choose the format most applicable to its own capabilities. All of these
- formats refer to the same data.
-
- 26.2.3 Shared Memory and the Clipboard
-
- Because data on the clipboard can be accessed by different applications,
- it is important that it be stored in shared memory. The clipboard uses two
- types of memory: selectors for shareable segments (allocated by the
- DosAllocSeg function), and Presentation Manager objects such as bitmaps
- and metafiles. Clipboard functions use two flag values, CFI_SELECTOR and
- CFI_HANDLE, to distinguish each memory type.
-
- When an application writes either a bitmap or a metafile to the clipboard,
- it passes a bitmap or metafile handle to the clipboard. The clipboard
- functions make the object "shareable." The application cannot access the
- object once it closes the clipboard. Once an object is passed to the
- clipboard, it can no longer be used in the application. Likewise, when an
- application requests a bitmap or metafile from the clipboard, it receives
- a handle to a bitmap or metafile object that is good only until the
- application closes the clipboard. Typically, the application either uses
- the object immediately before closing the clipboard, or it copies the
- object to local memory for future use, then closes the clipboard.
-
- To give a selector to the clipboard, an application must put data into a
- segment allocated by using the DosAllocSeg function with the SEG_GIVEABLE
- attribute. Once an application passes the selector for that segment to the
- clipboard and closes the clipboard, the clipboard owns the segment. The
- application cannot access the shared segment. When an application requests
- a selector from the clipboard, the clipboard gives the segment to the
- application. An application must use the selector before closing the
- clipboard or it must copy the data from the shared segment to a local
- segment before closing the clipboard.
-
- An application must use a shared segment when writing text to the
- clipboard. An application must also use shared segments for any
- application-defined clipboard formats. In this case, it is important to
- specify the CFI_SELECTOR flag when sending data to the clipboard.
-
-
- 26.3 Using the Clipboard
-
- Applications should use the clipboard when cutting, copying, or pasting
- data. Typically, an application places data on the clipboard for cut and
- copy operations and removes data from the clipboard for paste operations.
- An application can use the standard clipboard-data formats or create its
- own formats. An application that uses custom clipboard formats often
- becomes the clipboard owner, assuming control of drawing or freeing data
- on the clipboard.
-
- Clipboard data does not need to be generated, or rendered, when it is
- placed on the clipboard. Instead, an application can delay rendering,
- waiting until the data is requested by another application.
-
- Finally, an application can become the clipboard viewer, showing the
- clipboard contents, and receiving messages when the clipboard contents
- change.
-
- 26.3.1 Putting Data on the Clipboard
-
- To put data on the clipboard, an application must first call the
- WinOpenClipbrd function to verify that other applications are not trying
- to retrieve or set clipboard data. The WinOpenClipbrd function does not
- return if another thread has the clipboard open. The WinOpenClipbrd
- function waits until the clipboard is free or there is a message in the
- calling thread's message queue. In practice, this means that the
- WinOpenClipbrd function waits until the clipboard is available or until
- the calling application responds to a message. If the clipboard cannot be
- opened before a message arrives, the application receives the message and
- the WinOpenClipbrd function continues to try to open the clipboard. The
- WinOpenClipbrd function does not return until the clipboard is open.
- However, the application continues receiving messages.
-
- Once an application successfully opens the clipboard, it should remove any
- previously stored data on the clipboard by calling the WinEmptyClipbrd
- function. Although the clipboard supports many data formats, all the
- formats on the clipboard should represent the same data at any one time.
- For this reason, it is important to clear the clipboard of old data before
- writing new data. If the clipboard is not cleared, writing a format that
- already exists on the clipboard will replace the old data with the new
- data.
-
- When the clipboard is cleared, an application should write its data to the
- clipboard in as many standard formats as possible. For each format, the
- application should pass the data to the clipboard by calling the
- WinSetClipbrdData function, specifying the data format. Because the
- clipboard is not cleared when a new format is written to the clipboard,
- all new data formats coexist with each other until the clipboard is
- cleared by the next clipboard user.
-
- Data passed to the clipboard can take many forms, depending on the format
- of the data. For text data, the data handle is a selector to a shared
- segment containing the text. For bitmap data, the data handle is a bitmap
- handle. For a metafile format, the data handle is a metafile handle. If an
- application passes NULL for the data handle, it renders the data on
- request.
-
- Once an application passes a selector or a handle to the clipboard, the
- application should not alter the contents of that segment or handle. The
- clipboard owns that data from then on.
-
- Finally, when an application finishes writing the clipboard data, it
- should release the clipboard by calling the WinCloseClipbrd function so
- that other applications can use the clipboard.
-
- The following code fragment shows how an application places text data on
- the clipboard, how it opens the clipboard, copies the text to a shared
- segment, empties the clipboard, and passes the selector to the clipboard:
-
- if (WinOpenClipbrd(hab)) {
-
- /*
- * Allocate a shareable segment for the data szClipString in the
- * application's copy of the text.
- */
-
- if (usSuccess = DosAllocSeg(strlen(szClipString) + 1,
- &sel, SEG_GIVEABLE )) {
-
- /* Make a far pointer (selector:0) out of the selector. */
-
- pszDest = MAKEP(sel, 0);
-
- /* Set up the source pointer to point to text. */
-
- pszSrc = &szClipString[0];
-
- /* Copy the string to the segment. */
-
- while (*pszDest++ = *pszSrc++);
-
- /* Clear old data from the clipboard. */
-
- WinEmptyClipbrd(hab);
-
- /*
- * Pass the selector to the clipboard in CF_TEXT format. Note
- * that the selector must be a ULONG value.
- */
-
- fSuccess = WinSetClipbrdData(hab, (ULONG) sel,
- CF_TEXT, CFI_SELECTOR);
-
- /* Close the clipboard. */
-
- WinCloseClipbrd(hab);
- }
- }
-
- 26.3.2 Retrieving Data from the Clipboard
-
- To retrieve data from the clipboard, an application must first call the
- WinOpenClipbrd function to verify that no other applications are trying to
- retrieve or set the clipboard data.
-
- Once an application successfully opens the clipboard, it should call the
- WinQueryClipbrdData function, specifying a preferred format. If that
- format is not available, indicated by a NULL return from the
- WinQueryClipbrdData function, the application should repeat calls to the
- WinQueryClipbrdData function for other possible formats until it either
- receives the data or runs out of format choices.
-
- If the clipboard contains one of the requested formats, the
- WinQueryClipbrdData function returns a 32-bit integer, the meaning of
- which depends on the particular format. For text data, the return value is
- a selector (in the lower 16 bits of the long integer) to a shareable
- segment containing the text. For bitmap data, the return value is a bitmap
- handle. For metafile data, the return value is a metafile handle.
-
- Whatever the format, the handle or selector returned is valid only while
- the clipboard remains open. An application can use the data while the
- clipboard is open or copy the data to its own memory and use it after the
- clipboard is closed.
-
- It is important that an application close the clipboard as soon as
- possible so that other applications can access it.
-
- The following code fragment shows how to open the clipboard, retrieve data
- in the requested format, copy the data to a local segment, and close the
- clipboard:
-
- if (WinOpenClipbrd(hab)) {
- if (hText = WinQueryClipbrdData(hab, CF_TEXT)) {
-
- /* Turn the selector into a pointer. */
-
- pszClipText = MAKEP((SEL) hText, 0);
-
- /* Copy text from the selector segment to a local segment. */
-
- while (*pszLocalText++ = *pszClipText++);
- }
- WinCloseClipbrd(hab);
- }
-
- 26.3.3 Becoming the Clipboard Viewer
-
- A window can become a clipboard viewer and display the current contents of
- the clipboard. The clipboard viewer is informed whenever the clipboard
- contents change. Typically, the clipboard viewer is a window that can draw
- the standard clipboard formats. The clipboard viewer is a convenience for
- the user; it does not have any effect on the data-transaction functions of
- the clipboard.
-
- To create a clipboard viewer, an application calls the WinSetClipbrdViewer
- function, specifying the window in which the clipboard data will be
- displayed. This is usually the client window of an application. There can
- only be one clipboard viewer at any time in the system, so setting a
- clipboard viewer replaces any previous clipboard viewer. The
- WinQueryClipbrdViewer function receives the handle to the current
- clipboard viewer so that the application can reset it when finished with
- the clipboard viewer.
-
- Once a window becomes the clipboard viewer, it receives WM_DRAWCLIPBOARD
- messages whenever the contents of the clipboard change. The window should
- respond to these messages by drawing the contents of the clipboard.
-
- The clipboard viewer displays all the standard formats and should process
- CFI_OWNERDISPLAY items by sending the appropriate clipboard message to the
- clipboard owner.
-
- Three special formats exist for of the clipboard viewer: CF_DSPTEXT,
- CF_DSPBITMAP, and CF_DSPMETAFILE. Applications that write data to the
- clipboard in private formats should also write the data in one of these
- formats. These DSP formats should be a representation of the private
- formats. If the clipboard viewer does not find one of the standard formats
- (CF_TEXT, CF_BITMAP, or CF_METAFILE), it can search for one of the DSP
- formats. Display strategies for these formats are the same as for the
- corresponding standard formats.
-
- The following code fragment shows how a sample clipboard viewer responds
- to the WM_DRAWCLIPBOARD message, drawing text and bitmap data in its
- window. Note that the code uses the data retrieved from the clipboard
- before closing the clipboard. An alternate strategy would be to copy the
- data to a local segment and then close the clipboard. In any case, the
- original data from the clipboard cannot be used after the clipboard is
- closed.
-
- case WM_DRAWCLIPBOARD:
- if (!WinOpenClipbrd(hab))
- return 0L;
-
- if (hText = WinQueryClipbrdData(hab, CF_TEXT)) {
- pszText = MAKEP((SEL) hText, 0);
-
- hps = WinGetPS(hwnd);
- WinQueryWindowRect(hwnd, &rect);
-
- WinDrawText(hps,
- 0xFFFF, /* null-terminated string */
- pszText, /* the string */
- &rect, /* where to put the string */
- CLR_BLACK, /* foreground color */
- CLR_WHITE, /* background color */
- DT_CENTER | DT_VCENTER | DT_ERASERECT);
- WinValidateRect(hwnd, (PRECTL) NULL, FALSE);
- WinReleasePS(hps);
- }
- else if (hBitmap = WinQueryClipbrdData(hab, CF_BITMAP)) {
- hps = WinGetPS(hwnd);
- ptlDest.x = ptlDest.y = 0;
- WinQueryWindowRect(hwnd, &rect);
- WinFillRect(hps, &rect, CLR_WHITE);
- WinDrawBitmap(hps,
- hBitmap,
- (PRECTL) NULL, /* draws entire bitmap */
- &ptlDest, /* destination */
- CLR_BLACK, /* foreground color */
- CLR_WHITE, /* background color */
- DBM_NORMAL); /* bitmap flags */
- WinValidateRect(hwnd, (PRECTL) NULL, FALSE);
- WinReleasePS(hps);
- }
-
- WinCloseClipbrd(hab); /* closes the clipboard */
- return 0L;
-
- The clipboard viewer uses a similar sequence of calls to get clipboard
- data when responding to a WM_PAINT message.
-
- The clipboard viewer is also responsible for sending messages to the
- clipboard owner when clipboard data has the attribute CFI_OWNERDISPLAY.
- Typically, an application sets the attribute CFI_OWNERDISPLAY only for
- private clipboard formats and not for any standard formats. The clipboard
- viewer must send messages to the clipboard owner when the clipboard owner
- does not provide a standard clipboard format in addition to its private
- formats. In this case, the viewer sends messages to the clipboard owner of
- a CFI_OWNERDISPLAY format to draw, scroll, and resize the clipboard-image
- data.
-
- The clipboard viewer determines the attributes of a particular clipboard
- format by calling the WinQueryClipbrdFmtInfo function. The identity of the
- current owner can be found by calling the WinQueryClipbrdOwner function.
-
- 26.3.4 Becoming the Clipboard Owner
-
- The clipboard owner is any application window that is connected to the
- clipboard data. To become the clipboard owner, an application must call
- the WinSetClipbrdOwner function. The following are situations in which an
- application should call the WinSetClipbrdOwner function to become the
- clipboard owner:
-
- ■ The application calling the WinSetClipbrdData function passes a NULL
- selector or handle to the clipboard, indicating that the application
- renders the data in a particular format on request. As a result, the
- system sends rendering requests to the current clipboard owner.
-
- ■ The application calling the WinSetClipbrdData function passes data with
- the attribute CFI_OWNERFREE, indicating that the application frees
- memory for data when the clipboard is emptied. As a result, the system
- sends owner-free requests to the current clipboard owner.
-
- ■ The application calling the WinSetClipbrdData function passes data with
- the attribute CFI_OWNERDISPLAY, indicating that the owner application
- draws the data in the clipboard viewer. As a result, the clipboard
- viewer sends drawing-related requests to the current clipboard owner.
-
- The window specified in the call to the WinSetClipbrdOwner function should
- respond to the following messages:
-
- ╓┌─┌───────────────────────┌─────────────────────────────────────────────────╖
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_RENDERFMT Sent by the system to the clipboard owner when a
- particular format with delayed rendering must be
- rendered. The receiver should render the data in
- the specified format and pass it to the clipboard
- by calling the WinSetClipbrdData function. For
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- by calling the WinSetClipbrdData function. For
- more information, see Section 26.3.6.
-
- WM_RENDERALLFMTS Sent by the system to the clipboard owner just
- before the owner application terminates. The
- receiver should render the clipboard data in all
- formats on the clipboard with delayed rendering.
- It should pass the data for each format to the
- clipboard by calling the WinSetClipbrdData
- function. For more information, see Section
- 26.3.6.
-
- DESTROYCLIPBOARD Sent by the system to the clipboard owner when the
- clipboard is cleared by another application
- calling the WinEmptyClipbrd function. The receiver
- should free the memory occupied by any clipboard
- formats using the attribute CFI_OWNERFREE.
-
- WM_SIZECLIPBOARD Sent by the clipboard viewer to the clipboard
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_SIZECLIPBOARD Sent by the clipboard viewer to the clipboard
- owner when the clipboard contains the data handle
- with the attribute CFI_OWNERDISPLAY and when the
- clipboard-viewer changes size. When the clipboard
- viewer is being destroyed or reduced to an icon,
- this message is sent with the coordinates of the
- opposite corners set to (0,0), which permits the
- owner to free its display resources.
-
- WM_VSCROLLCLIPBOARD Sent by the clipboard viewer to the clipboard
- owner when the clipboard contains data with the
- attribute CFI_OWNERDISPLAY and when an event
- occurs in the clipboard-viewer scroll bars. The
- receiver should respond to this message by
- scrolling the image, invalidating the appropriate
- area of the clipboard viewer, and updating the
- scroll-bar position.
-
- WM_HSCROLLCLIPBOARD Sent by the clipboard viewer to the clipboard
- Message Description
- ──────────────────────────────────────────────────────────────────────────
- WM_HSCROLLCLIPBOARD Sent by the clipboard viewer to the clipboard
- owner when the clipboard contains data with the
- attribute CFI_OWNERDISPLAY and when an event
- occurs in the scroll bars of the clipboard viewer.
- The receiver should respond to this message by
- scrolling the image, invalidating the appropriate
- area of the clipboard viewer, and updating the
- scroll-bar position.
-
- WM_PAINTCLIPBOARD Sent by the clipboard viewer to the clipboard
- owner when the clipboard contains data with the
- attribute CFI_OWNERDISPLAY and when the
- clipboard-viewer client area needs repainting. The
- receiver should respond to this message by
- painting the requested format (by calling WinGetPS
- for the window handle of the clipboard viewer).
- ──────────────────────────────────────────────────────────────────────────
-
-
- An application automatically loses ownership of the clipboard when the
- clipboard data is cleared by the WinEmptyClipbrd function. Ownership is
- necessary only when data is present on the clipboard. Typically, an
- application loses ownership when another application places data on the
- clipboard.
-
- 26.3.5 Custom Clipboard Formats
-
- Applications often use custom clipboard formats when standard formats are
- insufficient for representing clipboard data. For example, a word
- processor might have a rich-text format that contains font and style
- information in addition to the usual text characters. Clearly, if the word
- processor uses the clipboard to support cut, copy, and paste operations
- for moving data in its documents, a standard text format would be
- inadequate.
-
- Such a word processor should write at least two formats to the clipboard
- for each cut or copy operation: a standard text format representing the
- text of the current selection, and a private rich-text format representing
- the true state of the selection. If the word processor performs a paste
- operation using clipboard data, it can use the rich-text format to retain
- all formatting. If another application requests the same data, it can use
- the standard-text format if it does not recognize the private format. The
- word processor should also be able to render data in CF_BITMAP and
- CF_METAFILE formats for painting or drawing applications.
-
- 26.3.5.1 Assigning a Unique Format ID
-
- Each private format must have an identification number when it is written
- to the clipboard. To obtain a unique ID number for a private clipboard
- format, the application should register the name of the format in the
- system atom table. The system assigns a unique ID number for the format
- name. Other applications that know the format name can query the system
- atom table for the format ID. An application can interpret its own private
- formats and can request them from the clipboard for cutting and pasting
- its own data. Other applications that know the private format ID can also
- interpret the formatted data. The following code fragment illustrates how
- an application obtains a unique identification number for a clipboard
- format. This technique can be used either by the application that creates
- the format or by another application.
-
- hatomtbl = WinQuerySystemAtomTable();
- formatID = WinAddAtom(hatomtbl, "SuperCAD_Format");
-
- 26.3.5.2 Display Formats
-
- Three standard display formats exist for applications that use private
- formats: CF_DSPTEXT, CF_DSPBITMAP, and CF_DSPMETAFILE. These three formats
- correspond to the standard text, bitmap, and metafile formats with the
- exception that they are intended only for use by the clipboard viewer. An
- application that uses a private format should write one of the DSP formats
- that approximates the appearance of the private data so that the clipboard
- viewer can display the data regardless of the format. For example, a word
- processor using the rich-text format should also write a CF_DSPBITMAP
- formatted picture of the selected text that contains all the type fonts
- and styles. Note that you might choose delayed rendering for DSP formats
- because there may not always be a clipboard viewer active on the screen.
- With delayed rendering, an application does not actually render the format
- unless it is requested to do so.
-
- 26.3.6 Delayed Rendering
-
- An application can pass NULL instead of a selector or a handle, indicating
- that the data is rendered only when another application requests it from
- the clipboard. This is useful if an application supports several clipboard
- formats that are time-consuming to render. With delayed rendering, an
- application can send NULL handles for each clipboard format that it
- supports, and render individual formats only when the format is actually
- requested from the clipboard. An application can either write data for
- standard formats or choose delayed rendering for more complex formats.
-
- When an application uses delayed rendering for one or more of its
- clipboard formats, it must become the clipboard owner. As long as the
- application is the clipboard owner, it receives a WM_RENDERFMT message
- whenever a request is received by the clipboard for a format using delayed
- rendering. When the application receives such a message, it should render
- the data and pass the selector or handle to the clipboard by calling the
- WinSetClipbrdData function. The rules for shared-memory access for
- rendered data are the same as those for standard clipboard data. This is
- simply a delayed execution of the operation that occurs if the data does
- not have delayed rendering.
-
- The clipboard owner with one or more delayed-rendering formats on the
- clipboard receives a WM_RENDERALLFMTS message just before the clipboard
- owner application terminates. This insures that the application renders
- all of its data before terminating.
-
-
- 26.4 Summary
-
- The following sections summarize the standard clipboard data formats, the
- functions that control the clipboard, and the window messages associated
- with the clipboard.
-
- 26.4.1 Standard Clipboard Formats
-
- The following are the standard clipboard-data formats used in MS OS/2:
-
- CF_BITMAP The handle returned by the WinQueryClipbrdData function is a
- bitmap handle.
-
- CF_DSPBITMAP A bitmap representation of a private-data format. The
- clipboard viewer uses this format to display a private format.
-
- CF_DSPMETAFILE A metafile representation of a private-data format. The
- clipboard viewer uses this format to display a private format.
-
- CF_DSPTEXT A text representation of a private-data format. The clipboard
- viewer uses this format to display a private format.
-
- CF_METAFILE The handle returned by the WinQueryClipbrdData function.
-
- CF_TEXT The handle returned by the WinQueryClipbrdData function has a
- selector (in the low word) to an array of text characters that can include
- newline characters indicating line breaks. The null character indicates
- the end of the text data.
-
- 26.4.2 Clipboard Functions
-
- The following are the MS OS/2 functions that control the clipboard:
-
- WinCloseClipbrd Closes the clipboard, allowing other applications to open
- and use it. This function sends a WM_DRAWCLIPBOARD message, causing the
- clipboard contents to be drawn in the clipboard viewer (if any). The
- clipboard must be open before this function is used.
-
- WinEmptyClipbrd Empties the clipboard, removing and freeing all handles
- to clipboard data.
-
- WinEnumClipbrdFmts Enumerates the available clipboard data formats. The
- fmtPrev argument specifies the index of the last clipboard-data format
- enumerated using this function. This index should start at zero, in which
- case the first available format is obtained. Subsequently, it should be
- set to the last format index value returned by this function. The return
- value is the index of the next available clipboard-data format on the
- clipboard. Enumeration is complete (no further formats are available) when
- zero is returned.
-
- WinOpenClipbrd Opens the clipboard and prevents other threads and
- processes from examining or changing the clipboard contents. If another
- thread or process already has the clipboard open, this function does not
- return until the clipboard is available. However, it passes messages to
- the application while it waits for the clipboard.
-
- WinQueryClipbrdData Retrieves data with a specified format from the
- clipboard. This function returns zero if no data with that format exists
- on the clipboard.
-
- WinQueryClipbrdFmtInfo Determines whether a particular data format is
- present on the clipboard. If it is, this function provides information to
- the caller about that format.
-
- WinQueryClipbrdOwner Returns the current clipboard owner (if any). The
- fLock argument specifies whether the clipboard-owner window should be
- locked. If the window is locked, the calling application must unlock the
- window. This window handle should be locked while being used because it
- may belong to another process. Locking prevents other processes from
- destroying the window.
-
- WinQueryClipbrdViewer Returns the current clipboard viewer (if any). The
- fLock argument specifies whether the clipboard viewer is locked. If the
- window is locked, the calling application must unlock the window. This
- window handle should be locked while being used because it may belong to
- another process. Locking prevents other processes from destroying the
- window.
-
- WinSetClipbrdData Puts data in a specified format on the clipboard.
-
- WinSetClipbrdOwner Sets the current clipboard owner. An application
- should become the clipboard owner when it sends delayed-rendering data to
- the clipboard or when it has data it must draw in the clipboard viewer.
-
- WinSetClipbrdViewer Sets the current clipboard viewer to a specified
- window. The clipboard viewer receives the WM_DRAWCLIPBOARD message when
- the clipboard contents change. This allows the clipboard viewer to display
- an up-to-date version of the clipboard contents. The clipboard must be
- open before this function is called.
-
- 26.4.3 Clipboard Messages
-
- The following are the window messages used with the clipboard:
-
- WM_DESTROYCLIPBOARD Sent by the system to the clipboard owner when the
- clipboard is emptied by the WinEmptyClipbrd function. If any of the
- formats have the CFI_OWNERFREE flag set, the clipboard owner must free the
- data when it receives the WM_DESTROYCLIPBOARD message.
-
- WM_DRAWCLIPBOARD Sent by the system to the clipboard viewer when the
- clipboard contents change. The clipboard viewer draws the contents of the
- clipboard.
-
- WM_HSCROLLCLIPBOARD Sent by the clipboard viewer to the clipboard owner
- when the clipboard data has the CFI_OWNERDISPLAY attribute and an event
- occurs in the clipboard-viewer scroll bars. The clipboard owner scrolls
- the clipboard image, invalidating the appropriate sections, and updates
- the scroll-bar values.
-
- WM_PAINTCLIPBOARD Sent by the clipboard viewer to the clipboard owner
- when a clipboard format with the CFI_OWNERDISPLAY flag set must be drawn
- in the clipboard viewer. The owner receives a window handle for the
- clipboard viewer and uses it as the destination window for drawing the
- clipboard data.
-
- WM_RENDERALLFMTS Sent by the system to the clipboard owner when the owner
- application is being destroyed. The clipboard owner should render all
- formats that it can generate and pass a handle or selector for each format
- to the clipboard by calling the WinSetClipbrdData function. This ensures
- that the clipboard contains valid data even though the application that
- rendered the data is destroyed.
-
- WM_RENDERFMT Sent by the system to the clipboard owner when clipboard
- data must be rendered. The receiver of this message renders the data and
- sends it to the clipboard by calling the WinSetClipbrdData function.
-
- WM_SIZECLIPBOARD Sent by the clipboard viewer to the clipboard owner when
- the clipboard viewer is resized and contains data with the attribute
- CFI_OWNERDISPLAY.
-
- WM_VSCROLLCLIPBOARD Same as the WM_HSCROLLCLIPBOARD message.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 27 Dynamic Data Exchange
-
- 27.1 Introduction
- 27.2 About Dynamic Data Exchange
- 27.2.1 Client and Server Interaction
- 27.2.2 Sample DDE Relationship
- 27.3 Using Dynamic Data Exchange
- 27.3.1 Detailed DDE Example
- 27.3.2 DDE Message Contents
- 27.3.3 Unique Data Formats
- 27.3.4 Sample DDE Transactions
- 27.3.4.1 Initiating an Exchange Between Two Applications
- 27.3.4.2 Positive WM_DDE_ACK Response
- 27.3.4.3 Negative WM_DDE_ACK Response
- 27.3.4.4 One-Time Data Transfer Between Two Applications
- 27.3.4.5 Permanent Data Link Between Two Applications
- 27.3.4.6 Executing Commands in a Remote Application
- 27.3.4.7 Terminating an Exchange Between Two Applications
- 27.3.5 Synchronization Rules
- 27.4 Summary
- 27.4.1 Functions
- 27.4.2 Messages
- 27.4.3 DDE Status Flags
-
- 27.1 Introduction
-
- This chapter describes how to use dynamic data exchange (DDE) messages to
- transfer data between applications. You should also be familiar with the
- following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Window messages and message queues
-
- ■ MS OS/2 memory management and shared memory
-
- ■ Clipboard data-exchange model
-
-
- 27.2 About Dynamic Data Exchange
-
- The dynamic data exchange (DDE) protocol is a set of messages and
- guidelines that allow MS OS/2 Presentation Manager applications to share
- data freely, using either one-time data transfers or ongoing exchanges, in
- which applications send updates to one another as new data becomes
- available.
-
- The DDE protocol uses messages for signaling between applications that
- share data. The DDE protocol uses shared memory as the means of
- transferring data from application to application. DDE defines some
- structures to store the shared memory objects.
-
- DDE is different from the clipboard data-transfer mechanism that is also
- part of MS OS/2. One difference is that the clipboard is almost always
- used as a one-time response to a specific action by the user (such as
- choosing Paste from a menu). DDE, on the other hand, is often initiated by
- a user but typically continues without the user's further involvement.
-
- 27.2.1 Client and Server Interaction
-
- DDE transactions always consist of a client application and a server
- application. The client initiates the exchange by requesting data from the
- server. The server responds to the data requests by providing data to the
- client. A server can have many clients at the same time, and a client can
- request data from multiple servers.
-
- An application can be both a client and a server. For instance, an
- application might receive data from another application as a client, and
- then act as a server by passing the data to another application.
-
- The important distinction between a client and a server is that the client
- initiates the DDE transaction.
-
- 27.2.2 Sample DDE Relationship
-
- There are many potential uses of DDE in real-time data-acquisition
- applications. This section discusses an example of one such use: a
- DDE-based real-time system for tracking portfolios. Two hypothetical
- Presentation Manager applications cooperate in this example. One
- application, named "Collector," is a specialized interface that draws data
- from an on-line data service. The other application is a spreadsheet. Both
- applications use the DDE protocol. In the described transactions the
- spreadsheet application is the client──that is, the application that
- initiates DDE transactions──and the on-line data-collection application is
- the server.
-
- The sample spreadsheet has the following layout:
-
- A B C D
-
- 1 Stock Shares Price Extension
-
- 2 BTRX 1000 148 148000
-
- 3 HLOW 2000 26 52000
-
- 4 WRLD 200 24 4800
-
- 5 ZMXI 2000 93 186000
-
- 6 390800
-
- Without DDE, this spreadsheet could be updated by using the clipboard to
- manually copy numbers from the screen display of the Collector application
- into the spreadsheet. This would require screen sharing or switching
- between applications, and would also require that the user pay attention
- to the price data and personally undertake the data exchange.
-
- With DDE, this system could be much more automatic, providing the
- spreadsheet with the current values for multiple data items without
- intervention by the user. DDE would allow the user to set up an exchange
- between the server and client applications that would keep the spreadsheet
- up-to-date whenever a change occurred in the value of specified stocks.
- Once this connection was established, the cell values in the spreadsheet
- would always reflect the most current data available from the server. This
- system would facilitate the timely analysis of real-time data.
-
- The usefulness of the DDE protocol is not restricted to specialized
- real-time data-acquisition applications. Productivity software in general
- can benefit significantly from the protocol. For example, suppose a
- monthly report is prepared using a graphics-and-text word processor, and
- that the report includes graphs generated in a separate business-graphics
- package. Without DDE, it would be necessary to manually copy and paste
- each month's new graphs into each month's report. With DDE, the word
- processor can establish a permanent link to the charting application, so
- that any changes made by the user to the charting document are reflected
- in the word-processing document, either automatically or on request. This
- makes the routine of document preparation much simpler for the user.
-
-
- 27.3 Using Dynamic Data Exchange
-
- A DDE transaction between two applications actually takes place between
- two windows, one for each of the participating applications. Applications
- open a window for each conversation they engage in. (Note that such
- windows are typically not visible.) A window is identified by its handle.
- The window belonging to the server application is the server window; the
- window belonging to the client application is the client window.
-
- After a conversation has been initiated by the client, the client
- interacts with the server by issuing transactions. When issuing a
- transaction, the client requests that the server perform a particular
- action. There are six types of transactions: request, advise, unadvise,
- poke, execute, and terminate. These transactions are permitted only within
- an exchange begun by using the WM_DDE_INITIATE message. DDE transactions
- are one-way: The client application always issues the transactions. If the
- server issues a transaction to the client, the server must initiate a new
- exchange for that purpose. The server becomes the client in this new
- exchange. (The only exception to the one-way rule is the terminate
- transaction, which can be issued by either the client or the server.)
-
- 27.3.1 Detailed DDE Example
-
- This section presents a more detailed view of the workings of the DDE
- protocol. It discusses the example of the Collector and spreadsheet
- interaction and illustrates forwarding stock quotes from the Collector
- application to the spreadsheet. For the sake of simplicity, this example
- will be limited to the exchange of quotes for a single stock, BTRX.
-
- The Collector DDE server application is started first. Typically,
- applications designed to operate as dedicated DDE servers have some user
- interface for initialization and then run as icons at the bottom of the
- Presentation Manager screen. As part of the initialization process, the
- Collector DDE server application goes through whatever steps are necessary
- (entering passwords, testing, etc.) to ensure that data can be provided to
- clients.
-
- The spreadsheet is started next, and the stock-portfolio document is
- loaded. At this time, the spreadsheet calls the WinDdeInitiate function,
- which sends a WM_DDE_INITIATE message to all current top-level frame
- windows.
-
- The WM_DDE_INITIATE message is a request to initiate an exchange with an
- application on a specified topic──in this case, NYSE. An application can
- accept this message by responding with a positive WM_DDE_INITIATEACK
- message, or can decline it by passing the message on to the
- WinDefWindowProc function. If no application accepts the request, the
- spreadsheet assigns an error value to the external reference and its DDE
- activity concludes.
-
- If the Collector application acknowledges the request, the spreadsheet can
- use the newly established exchange to request the Collector application to
- provide continuous updates on a specified data item. To make this request,
- the spreadsheet posts a WM_DDE_ADVISE message to the Collector application
- (actually, to a window within the Collector application that is acting as
- the message recipient for DDE messages), indicating that updates should be
- sent every time there is a new value available for the data item named
- "BTRX," and that the updates should be in a particular format──for
- example, DDEFMT_TEXT. Upon receiving this message, the Collector
- application records the request in its database and posts a WM_DDE_ACK
- message to the spreadsheet. From then on, the Collector application posts
- a WM_DDE_DATA message to the spreadsheet application (actually, to the
- window in the spreadsheet that initiated the exchange) whenever it
- receives a new BTRX stock quote from the server. Each of these messages
- carries a selector for a shared memory object. The object itself contains
- the data, rendered in the requested format. Whenever the spreadsheet
- receives such a message, it retrieves the data from the referenced memory
- object and uses the data to update the value of the cell containing the
- external reference.
-
- The periodic updates continue until the spreadsheet document is closed. At
- that point the spreadsheet application posts a WM_DDE_UNADVISE message to
- the Collector application, indicating that further updating is not
- necessary. Upon receipt of this message, the Collector application removes
- the corresponding data request from its database and posts a positive
- WM_DDE_ACK message back to the spreadsheet.
-
- Finally, unless the spreadsheet initiates other data exchanges under this
- same topic, it posts a WM_DDE_TERMINATE message to the Collector
- application, indicating the end of the DDE transaction. The Collector
- application responds with a WM_DDE_TERMINATE message.
-
- 27.3.2 DDE Message Contents
-
- DDE uses the three-level hierarchy──application, topic, and item──to
- uniquely identify a unit of data. An item is a data object that can be
- passed in a DDE transaction. For example, an item might be a single
- integer, a string, several paragraphs of text, or a bitmap. A topic is a
- logical data context. For applications that operate on file-based
- documents, topics are usually filenames; for other applications they are
- other application-specific strings. Using the Collector and spreadsheet
- model described earlier, the application name is collector, the topic name
- is NYSE, and the item name is BTRX.
-
- There are two data structures used for DDE transactions: the DDEINIT
- structure and the DDESTRUCT structure. The DDEINIT structure is used for
- the WM_DDE_INITIATE and WM_DDE_INITIATEACK messages. DDEINIT contains
- pointers to the application-name and topic-name strings. The DDEINIT
- structure has the following form:
-
- typedef struct _DDEINIT {
- USHORT cb;
- PSZ pszAppName;
- PSZ pszTopic;
- } DDEINIT;
-
- An application typically does not need to fill in a DDEINIT structure,
- since the operating system fills it in automatically when the application
- calls the WinDdeInitiate or WinDdeRespond function. It is important,
- however, to understand the organization of the DDEINIT structure when
- receiving a WM_DDE_INITIATE or WM_DDE_INITIATEACK message, so that you can
- extract the application name and the topic name. The DDESTRUCT structure
- is passed with all DDE messages except WM_DDE_INITIATE and
- WM_DDE_INITIATEACK. It contains a byte count of the data, the format of
- the data, the item name, a status word, and the data being transferred.
- The DDESTRUCT structure has the following form:
-
- typedef struct _DDESTRUCT {
- ULONG cbData;
- USHORT fsStatus;
- USHORT usFormat;
- USHORT offszItemName;
- USHORT offabData;
- } DDESTRUCT;
-
- The data in a DDE message is contained in a shared memory segment. The
- sender allocates a segment large enough to hold one of the two data
- structures described above and the actual data to be transferred, and
- passes the selector for the memory as part of the message. The layout of a
- typical DDE segment is shown in Figure 27.1. The first part of the DDE
- segment is occupied by the DDESTRUCT structure. Next comes the item-name
- string. Following the name string is the actual data to be transferred.
- The offset fields of the DDESTRUCT structure must be set to point to the
- name string and the beginning of the data. The cbData field must also be
- set to indicate the number of bytes of data.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 27.1 can be found in Section 27.3.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 27.1 Typical DDE Segment
-
- The sender must allocate the segment as SEG_GIVEABLE and call the
- DosGiveSeg function to share the segment with the receiving application.
- To share a segment, the sender needs to know the process identifier of the
- recipient. The process identifier can be obtained by calling the
- WinQueryWindowProcess function for the recipient's window handle.
-
- The sender should call the DosFreeSeg function to free its copy of the
- segment selector as soon as it has given the shared segment selector to
- the recipient. The recipient should call DosFreeSeg when it is finished
- using the segment. The sender should not try to access the segment once it
- has been sent to the recipient in a DDE message. The following code
- fragment shows a function that creates a shared segment for a DDE
- transaction. The function parameters include the destination window for
- the DDE message, the item name for the transaction, the status word, the
- format of the data, the actual data to be transferred (if any), and the
- length of the data. The segment allocated by this function must be big
- enough to hold the DDESTRUCT structure, the item name, and the actual data
- to be transferred. The function returns a pointer (PDDESTRUCT) to a shared
- segment that is ready to post as part of a DDE message.
-
- PDDESTRUCT MakeDDESegment(hwndDest, pszItemName, fsStatus, usFormat,
- pabData, usDataLen)
- HWND hwndDest;
- PSZ pszItemName;
- USHORT fsStatus;
- USHORT usFormat;
- PVOID pabData;
- USHORT usDataLen;
-
- {
- PDDESTRUCT pddes; /* pointer to DDESTRUCT */
- USHORT usItemLen; /* length of item name */
- USHORT usTotalLen; /* total length of segment */
- SEL selBuf; /* local selector for segment */
- SEL selShared; /* shared selector for segment */
- USHORT receiverPID; /* process ID of server */
- USHORT receiverTID; /* thread ID of server */
-
- usItemLen = FarStrLen(pszItemName) + 1;
-
- usTotalLen = sizeof(DDESTRUCT) + usItemLen + usDataLen;
-
- if (! DosAllocSeg(usTotalLen, &selBuf, SEG_GIVEABLE)) {
-
- /* Initialize DDESTRUCT. */
-
- pddes = SELTOPDDES(selBuf);
- pddes->cbData = usTotalLen;
- pddes->fsStatus = fsStatus;
- pddes->usFormat = usFormat;
- pddes->offszItemName = sizeof(DDESTRUCT);
- if ((usDataLen) && (pabData))
- pddes->offabData = sizeof(DDESTRUCT) + usItemLen;
- else
- pddes->offabData = 0;
-
- /* Copy item name immediately following DDESTRUCT. */
-
- FarStrCopy(DDES_PSZITEMNAME(pddes), pszItemName);
-
- /* Copy data immediately following item name. */
-
- FarStructCopy(DDES_PABDATA(pddes), pabData, usDataLen);
-
- /* Get process identifier of server. */
-
- WinQueryWindowProcess(hwndDest, &receiverPID, &receiverTID);
-
- /* Give the segment away. */
-
- if (!DosGiveSeg(selBuf, receiverPID, &selShared)) {
- pddes = SELTOPDDES(selShared);
- return (pddes);
- }
- }
-
- /* Else could not allocate or share segment. */
-
- return (NULL);
- }
-
- This function is used in many examples in the following sections to
- demonstrate the creation of DDE shared segments. You may want to define a
- similar function in your own programs as well.
-
- 27.3.3 Unique Data Formats
-
- Whenever you exchange data by using the DDE protocols you must specify the
- format of the data in the usFormat field of the DDESTRUCT structure. The
- system-defined standard format is DDEFMT_TEXT, which indicates text data.
-
- Applications can define their own data formats. Each nonstandard DDE
- format must have a unique identification number. The application should
- register the name of the format in the system atom table, receiving an
- identification number for that format name. Other applications that have
- the name of the format can also query the system atom table for the
- format's identification number. This method ensures that all applications
- use the same atom to identify a format.
-
- The following code fragment shows how an application can obtain a unique
- identification number for a DDE format. This technique can be used by the
- application that creates the format and by an application that is able to
- use the format.
-
- hatomtbl = WinQuerySystemAtomTable();
- formatID = WinAddAtom(hatomtbl, "SuperCAD_Format");
-
- 27.3.4 Sample DDE Transactions
-
- This section discusses beginning and ending a DDE transaction and the five
- basic types of interchange supported by DDE. Each of the following
- subsections provides a detailed description of the message protocols that
- are associated with the transactions it discusses.
-
- 27.3.4.1 Initiating an Exchange Between Two Applications
-
- To initiate a DDE transaction, the client calls the WinDdeInitiate
- function, specifying the server application-name and topic-name strings.
- This function sends a WM_DDE_INITIATE message to all frame windows whose
- parent is HWND_DESKTOP. Because the message is sent rather than posted,
- WinDdeInitiate requires all of the message's recipients to respond to the
- message before control is returned. Either the application name or the
- topic name can be a null string, in which case the server ignores that
- name. For example, a client could send a valid application name with a
- null topic name to request an exchange on all available topics for that
- application.
-
- The server applications that respond to the WM_DDE_INITIATE message will
- call the WinDdeRespond function, as shown in the following pseudocode:
-
- If ((specific app requested and server is instance of app) or
- (specific app not requested){
-
- If (specific topic requested)
- If (server can support topic)
-
- acknowledge the requested topic
-
- Else
- acknowledge each supported topic
- }
-
- To acknowledge a specific topic, the server responds with the following
- code fragment:
-
- WinDdeRespond(hwndClient, hwndServer, pszAppName, pszTopicName);
-
- To acknowledge more than one topic, the server makes one such response for
- each topic. This initiates an exchange on each topic. The client should
- post a WM_DDE_TERMINATE message for all unneeded transactions.
-
- The System Topic
-
- Applications are encouraged to support the "System" topic at all times.
- This topic provides a context for information that may be of general
- interest to any partners in a DDE transaction. DDE applications should
- request an exchange on the System topic with a NULL application name when
- they start up, to find out what kinds of information other DDE-capable
- programs can provide.
-
- The System topic should support the following terms, as well as any other
- items the application may use:
-
- Item Description
- ──────────────────────────────────────────────────────────────────────────
- SysItems A list of the items supported under the System topic by
- this application.
-
- Topics A list of the topics supported by the application at the
- current time (this may vary from moment to moment).
-
- ReturnMessage Supporting detail for the most recently issued WM_DDE_ACK
- message. (This is useful when more than eight bits of
- application-specific return code are required.)
-
- Status An indication of the current status of the application.
-
- Formats A list of DDE format numbers that the application can
- render.
- ──────────────────────────────────────────────────────────────────────────
-
- Individual elements of lists should be delimited by tabs (the DDEFMT_TEXT
- format).
-
- 27.3.4.2 Positive WM_DDE_ACK Response
-
- A client or server often must positively acknowledge a DDE message that it
- receives by posting a WM_DDE_ACK message with the DDE_FRESPONSE flag set
- in the status word of the DDESTRUCT structure. Sending a positive
- WM_DDE_ACK message means that the sender will respond to the previous
- message. The following code fragment is an example of a positive
- acknowledgment message:
-
- pddeStruct = MakeDDESegment(hwndDest, /* handle of destination */
- "BTRX", /* item name */
- DDE_FACKREQ, /* status flags */
- DDEFMT_TEXT, /* data format */
- NULL, /* no data for request */
- 0); /* data length */
-
- WinDdePostMsg(hwndDest, /* handle of destination */
- hwndSource, /* handle of source */
- WM_DDE_ACK, /* message */
- pddeStruct, /* shared-segment pointer */
- 1); /* retry */
-
- 27.3.4.3 Negative WM_DDE_ACK Response
-
- When an application receives a DDE message that it cannot respond to (such
- as a request for data in a format that it does not support), the
- application must post a WM_DDE_ACK message with the DDE_NOTPROCESSED flag
- set in the status word of the DDESTRUCT structure. The following code
- fragment is an example of a negative acknowledgment message:
-
- pddeStruct = MakeDDESegment(hwndDest, /* handle of destination */
- "BTRX", /* item name */
- DDE_NOTPROCESSED, /* status flags */
- DDEFMT_TEXT, /* data format */
- NULL, /* no data for request */
- 0); /* data length */
-
- WinDdePostMsg(hwndDest, /* handle of destination */
- hwndSource, /* handle of source */
- WM_DDE_ACK, /* message */
- pddeStruct, /* shared-segment pointer */
- 1); /* retry */
-
- If an application is busy when it receives a DDE message, it can post a
- WM_DDE_ACK message with the DDE_FBUSY flag set.
-
- 27.3.4.4 One-Time Data Transfer Between Two Applications
-
- A client application can use the DDE protocol to obtain a data item from a
- server (WM_DDE_REQUEST), or to submit a data item to a server
- (WM_DDE_POKE). In either case, the client must have already initiated an
- exchange with the server, as described earlier.
-
- The client posts a WM_DDE_REQUEST message to the server, specifying an
- item and format by allocating a shared segment and filling in a DDESTRUCT
- structure and passing the structure to the WinDdePostMsg function. For
- example, if a DDE exchange has been started on the NYSE topic, the client
- could request data for the BTRX item by using the following code fragment.
- (For an example of how to allocate and initialize a shared memory segment,
- see Section 27.3.2.)
-
- pddeStruct = MakeDDESegment(hwndServer, /* handle of server */
- "BTRX", /* item name */
- 0, /* status flags */
- DDEFMT_TEXT, /* data format */
- NULL, /* no data for request */
- 0); /* data length */
-
- WinDdePostMsg(hwndServer, /* handle of server */
- hwndClient, /* handle of client */
- WM_DDE_REQUEST, /* message */
- pddeStruct, /* shared-segment pointer */
- 1); /* retry */
-
- If the server is unable to satisfy the request, it sends the client a
- negative WM_DDE_ACK message. If the server can satisfy the request, it
- renders the item in the requested format and includes it with a DDESTRUCT
- structure in a shared memory object and posts a WM_DDE_DATA message to the
- client, as shown in the following code fragment:
-
- pddeStruct = MakeDDESegment(hwndClient, /* handle of client */
- "BTRX", /* item name */
- 0, /* status flags */
- DDEFMT_TEXT, /* data format */
- pabData, /* pointer to data */
- usDataLen); /* data length */
-
- WinDdePostMsg(hwndClient, /* handle of client */
- hwndServer, /* handle of server */
- WM_DDE_DATA, /* message */
- pddeStruct, /* shared-segment pointer */
- 1); /* retry */
-
- Upon receiving a WM_DDE_DATA message, the client processes the data item.
- The DDESTRUCT structure at the beginning of the shareable segment contains
- a status word indicating whether the sender has requested an
- acknowledgment message. If the DDE_FACKREQ bit of the status word is set,
- the client should send the server a positive WM_DDE_ACK message.
-
- Upon receiving a negative WM_DDE_ACK message, the client can ask for the
- same item again, specifying a different DDE format. Typically, a client
- will first ask for the most complex format it can support, then step down,
- if necessary, through progressively simpler formats until it finds one the
- server can provide.
-
- 27.3.4.5 Permanent Data Link Between Two Applications
-
- A client application can use DDE to establish a link to an item in a
- server application. When such a link is established, the server sends
- periodic updates about the linked item to the client (typically, whenever
- the data that is associated with the item in the server application has
- changed). A permanent "data stream" is established between the two
- applications and remains in place until it is explicitly disconnected.
-
- The client sends the server a WM_DDE_ADVISE message to set up the data
- link. (Of course, the client must have first initiated an exchange by
- using the WM_DDE_INITIATE message, as described previously.) The advise
- message contains a shared-memory pointer containing a DDESTRUCT structure
- with the item name, format information, and status information, as shown
- in the following code fragment:
-
- pddeStruct = MakeDDESegment(hwndServer, /* handle of server */
- "BTRX", /* item name */
- DDE_FACKREQ, /* status flags */
- DDEFMT_TEXT, /* data format */
- NULL, /* no data for advise */
- 0); /* data length */
-
- WinDdePostMsg(hwndServer, /* handle of server */
- hwndClient, /* handle of client */
- WM_DDE_ADVISE, /* message */
- pddeStruct, /* shared-segment pointer */
- 1); /* retry */
-
- If the server has access to the requested item and can render it in the
- desired format, the server records the new link and then sends the client
- a positive WM_DDE_ACK message. Until the client issues a WM_DDE_UNADVISE
- message, the server sends data messages to the client every time the
- source data changes that is associated with the item in the server
- application.
-
- If the server is unable to satisfy the request, it sends the client a
- negative WM_DDE_ACK message.
-
- When a link is established with the DDE_FNODATA status bit cleared, the
- client is sent the data each time the data changes. In such cases, the
- server renders the new version of the item in the previously specified
- format and posts a WM_DDE_DATA message to the client, as shown in Section
- 27.3.4.4.
-
- When the client receives a WM_DDE_DATA message, it extracts data from the
- shared memory segment by using the DDESTRUCT structure at the beginning of
- the segment. If the DDE_FACK status bit is set in the status word of the
- DDESTRUCT structure, the client must post a positive WM_DDE_ACK message to
- the server.
-
- When a link is established with the DDE_FNODATA status flag set, a
- notification, not the data itself, is posted to the client each time the
- data changes. In this case, the server does not render the new version of
- the item when the source data changes, but simply posts a WM_DDE_DATA
- message with zero bytes of data and the DDE_FNODATA status flag set, as
- shown in the following code fragment:
-
- pddeStruct = MakeDDESegment(hwndClient, /* handle of client */
- "BTRX", /* item name */
- DDE_FNODATA, /* status flags */
- DDEFMT_TEXT, /* data format */
- NULL, /* no data */
- 0); /* data length */
-
- WinDdePostMsg(hwndClient, /* handle of client */
- hwndServer, /* handle of server */
- WM_DDE_DATA, /* message */
- pddeStruct, /* shared-segment pointer */
- 1); /* retry */
-
- The client can request the latest version of the data by performing a
- regular one-time WM_DDE_REQUEST transaction, or it can simply ignore the
- data-change notice from the server. In either case, if the DDE_FACK status
- bit is set, the client should send a positive WM_DDE_ACK message to the
- server.
-
- To terminate a specific item link, the client posts a WM_DDE_UNADVISE
- message to the server, as shown in the following code fragment:
-
- pddeStruct = MakeDDESegment(hwndServer, /* handle of server */
- "BTRX", /* item name */
- DDE_FACKREQ, /* status flags */
- DDEFMT_TEXT, /* data format */
- NULL, /* no data for unadvise */
- 0); /* data length */
-
- WinDdePostMsg(hwndServer, /* handle of server */
- hwndClient, /* handle of client */
- WM_DDE_UNADVISE, /* message */
- pddeStruct, /* shared-segment pointer */
- 1); /* retry */
-
- The server checks that the client currently has a link to the specified
- item in this exchange. If the link exists, the server sends a positive
- WM_DDE_ACK message to the client and no longer sends updates on the item
- in this exchange. If the server has no such link, it sends a negative
- WM_DDE_ACK message.
-
- To terminate all links for a particular exchange, the client application
- posts a WM_DDE_UNADVISE message with a null item name to the server. The
- server checks that the exchange has at least one link currently
- established. If so, the server posts a positive WM_DDE_ACK message to the
- client, and no longer sends any updates in the exchange. If the server has
- no links in the exchange, it posts a negative WM_DDE_ACK message.
-
- 27.3.4.6 Executing Commands in a Remote Application
-
- A Presentation Manager application can use the DDE protocol to cause a
- command or series of commands to be executed in another application. Such
- remote executions are performed by means of the WM_DDE_EXECUTE
- transaction.
-
- To execute a remote command, the client application posts to the server a
- WM_DDE_EXECUTE message containing a selector for a shared-memory object
- that contains a DDESTRUCT structure and a command string, as shown in the
- following code fragment:
-
- pddeStruct = MakeDDESegment(hwndServer, /* handle of server */
- "BTRX", /* item name */
- DDE_FACKREQ, /* status flags */
- DDEFMT_TEXT, /* data format */
- pabData, /* pointer to command string */
- usDataLen); /* data length */
-
- WinDdePostMsg(hwndServer, /* handle of server */
- hwndClient, /* handle of client */
- WM_DDE_EXECUTE, /* message */
- pddeStruct, /* shared-segment pointer */
- 1); /* retry */
-
- The server attempts to execute the specified string according to some
- agreed-upon protocol. If successful, the server posts a positive
- WM_DDE_ACK message to the client; if unsuccessful, a negative WM_DDE_ACK
- message is posted.
-
- 27.3.4.7 Terminating an Exchange Between Two Applications
-
- At any time, either the client or the server may terminate an exchange by
- using the following procedure to issue a WM_DDE_TERMINATE message.
- Similarly, both the client application and server application should be
- able to receive a WM_DDE_TERMINATE message at any time.
-
- An application must end its exchanges before terminating. The application
- posts a WM_DDE_TERMINATE message with a NULL shared-segment pointer, as
- shown in the following code fragment. A WM_DDE_TERMINATE message stops all
- transactions for a given exchange.
-
- WinDdePostMsg(hwndDest, /* handle of destination */
- hwndSource, /* handle of source */
- WM_DDE_TERMINATE, /* message */
- NULL, /* no shared-segment pointer */
- 1); /* retry */
-
- The WM_DDE_TERMINATE message means that the sender will send no further
- messages in that exchange and that the recipient may destroy its DDE
- window. The recipient must always send a WM_DDE_TERMINATE message promptly
- in response; it is not permissible to send a negative, busy, or positive
- WM_DDE_ACK message instead.
-
- If the sender of the original termination request receives any other
- message before the WM_DDE_TERMINATE message arrives from the recipient of
- the request, no response should be sent to this other message; the sender
- of the other message may already have destroyed the window to which the
- response would be sent.
-
- 27.3.5 Synchronization Rules
-
- A window processing DDE requests from another window must process them
- strictly in the order in which the requests were received.
-
- A window does not need to apply this first-in, first-out rule between
- requests from different windows──that is, it may provide asynchronous
- support for multiple processes. For example, a window might have the
- following requests in its queue:
-
- ■ 1: Request Message from window x
-
- ■ 2: Request Message from window y
-
- ■ 3: Request Message from window x
-
- The window must process request 1 before 3, but it does not need to
- process 2 before 3. If y has a lower priority than x, the window follows
- the order 1, 3, 2.
-
- If a server is unable to process an incoming request because it is waiting
- for an external process, it must post a busy WM_DDE_ACK message to the
- client, to prevent deadlock. A busy WM_DDE_ACK message can also be sent if
- the server is unable to process an incoming request quickly.
-
-
- 27.4 Summary
-
- This section describes the functions, messages, and status flags
- associated with the DDE protocol.
-
- 27.4.1 Functions
-
- Three functions simplify the use of DDE messages:
-
- WinDdeInitiate Sends a WM_DDE_INITIATE message containing the specified
- application name and topic name to all top-level frame windows in the
- system.
-
- WinDdePostMsg Posts a DDE message to the specified recipient window.
-
- WinDdeRespond Sends a WM_DDE_INITIATEACK message in response to a
- WM_DDE_INITIATE message.
-
- 27.4.2 Messages
-
- The predefined DDE messages are summarized below:
-
- WM_DDE_ACK Sent as acknowledgment to many DDE messages.
-
- WM_DDE_ADVISE Sent from the client to the server, requesting the server
- to provide a data update whenever the specified data item changes.
-
- WM_DDE_DATA Sent from the server to the client to notify the client that
- the data is available.
-
- WM_DDE_EXECUTE Sent from the client to the server, containing a text
- string that the server should execute as a command or series of commands.
-
- WM_DDE_INITIATE Sent by a client application to initiate an exchange with
- one or more server applications. This message is often sent to all current
- applications by calling the WinBroadcastMsg function.
-
- WM_DDE_INITIATEACK Sent by a server application as a positive response to
- a WM_DDE_INITIATE message. This message specifies the server application
- name and the topic on which the server will open a DDE transaction.
-
- WM_DDE_POKE Sent as an unsolicited data message for the recipient, which
- should reply with a WM_DDE_ACK message to indicate whether or
- not it accepted the data.
-
- WM_DDE_REQUEST Sent from the client to the server to request that a data
- item be sent to the client.
-
- WM_DDE_TERMINATE Sent by either the client or the server to terminate the
- exchange.
-
- WM_DDE_UNADVISE Sent from the client to the server to indicate that the
- specified item should no longer be updated. This message requests the
- server to remove the link to the data item set up by the WM_DDE_ADVISE
- message.
-
- 27.4.3 DDE Status Flags
-
- The following constant values control various aspects of a DDE
- transaction. They can be combined in the fsStatus word of the DDESTRUCT
- structure by using the OR operator.
-
- DDE_FACK Set for positive acknowledgment.
-
- DDE_FACKREQ Set to acknowledge DDE messages for the application.
-
- DDE_FAPPSTATUS Upper eight bits of status word are reserved for the
- application-specific data.
-
- DDE_FBUSY Set if application is busy.
-
- DDE_FNODATA Set if there is no data transfer for the WM_DDE_ADVISE
- message.
-
- DDE_FRESERVED Reserved; must be zero.
-
- DDE_FRESPONSE Set if there is a response to a WM_DDE_REQUEST message.
-
- DDE_NOTPROCESSED Set if the message is not supported.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 28 Hooks
-
- 28.1 Introduction
- 28.2 About Hooks
- 28.3 Types of Hooks
- 28.3.1 Input Hook
- 28.3.2 Send-Message Hook
- 28.3.3 Message-Filter Hook
- 28.3.4 Journal-Record Hook
- 28.3.5 Journal-Playback Hook
- 28.3.6 Help Hook
- 28.4 Using Hooks
- 28.5 Hook Example
- 28.5.1 Installing a System Hook
- 28.5.2 System-Hook Code
- 28.6 Summary
- 28.6.1 Functions
- 28.6.2 Hook Types
-
- 28.1 Introduction
-
- This chapter describes how to use hooks in your applications. You should
- also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Window messages and message queues
-
- ■ Focus window and input guidelines
-
-
- 28.2 About Hooks
-
- MS OS/2 is based on a message-passing model. The behavior of most programs
- depends on the messages that the program receives. Messages can be
- generated by input devices, such as the keyboard and mouse, or they can
- originate within the system as a way of managing and communicating between
- system resources.
-
- MS OS/2 provides hooks to allow applications to monitor and modify the
- message stream. Hooks can be installed in either the system queue, so that
- they affect all applications, or in an individual thread's message queue,
- so that only messages for that queue are affected.
-
- Because many applications may install hooks at the same time, most hooks
- are arranged in chains. The system passes a message to the first hook in
- the chain, and then to the next hook in the chain, and so on until the
- message is delivered to the destination application. Each hook may modify
- the message or stop its progress through the chain, preventing it from
- reaching the application. Hooks in a chain are called in last-installed,
- first-called order.
-
-
- 28.3 Types of Hooks
-
- There are six different types of hooks. You can install the different
- types of hooks in any combination, although some of the hook types can be
- installed only in the system queue.
-
- The following sections describe the available types of hooks. Each type of
- hook is expressed as a function with a unique syntax.
-
- 28.3.1 Input Hook
-
- This hook monitors the input queue and is called whenever a message is
- about to be returned by the WinGetMsg or WinPeekMsg function. Typically,
- the input hook is used to monitor mouse and keyboard input and other
- messages that are posted to a queue.
-
- The syntax for the input hook is as follows:
-
- BOOL CALLBACK InputHook(HAB hab, PQMSG pQmsg, USHORT fs)
-
- The pQmsg parameter is a far pointer to a QMSG structure that contains
- information about the message. The QMSG structure has the following form:
-
- typedef struct _QMSG {
- HWND hwnd;
- USHORT msg;
- MPARAM mp1;
- MPARAM mp2;
- ULONG time;
- POINTL ptl;
- } QMSG;
-
- The fs parameter of the InputHook function can contain the following flags
- from the WinPeekMsg function, indicating whether or not the message is
- removed from the queue:
-
- PM_NOREMOVE
- PM_REMOVE
-
- If this hook function returns TRUE, the message is not passed to the rest
- of the hook chain or to the application──effectively ending the message.
- If the function returns FALSE, the message is passed to the next hook in
- the chain, or to the application if no other hooks exist.
-
- The input hook can modify a message by changing the contents of the QMSG
- structure, then return FALSE to pass the modified message to the rest of
- the chain. The following problems may occur when a hook modifies a
- message:
-
- ■ If the caller uses the WinPeekMsg or WinGetMsg function with a message
- filter range (msgFilterFirst through msgFilterLast), the message is
- checked before the hooks are called, not after the hooks are called.
- This means the caller may receive messages that are not in the range of
- the caller's message filter.
-
- ■ If the hook changes a WM_CHAR message from one character into
- another──for example, if the hook modifies all TAB messages into F6
- messages──a program that depends on the key state will be unable to
- interpret the result. (When the TAB key is translated into the F6 key,
- the application receives the F6 keystroke and enters a process loop,
- waiting for the F6 key to be released; the application calls the
- WinGetKeyState function with the HWND_DESKTOP and VK_F6 arguments).
-
- 28.3.2 Send-Message Hook
-
- This hook is called whenever a message is sent by using the WinSendMsg
- function. The hook chain is called before the message is delivered to the
- recipient window. Typically, the send-message hook is used to monitor
- messages that are not posted to a queue. By installing an input hook and a
- send-message hook, you can effectively monitor all window messages.
-
- The syntax for the send-message hook is as follows:
-
- VOID CALLBACK SendMsgHook(HAB hab, PSMHSTRUCT psmh,
- BOOL fInterTask)
-
- The psmh parameter is a far pointer to an SMHSTRUCT structure that
- contains information about the message. The SMHSTRUCT structure has the
- following form:
-
- typedef struct _SMHSTRUCT {
- MPARAM mp2;
- MPARAM mp1;
- USHORT msg;
- HWND hwnd;
- } SMHSTRUCT;
-
- The fInterTask parameter of the SendMsgHook function is TRUE if the
- message is sent between two threads, or FALSE if the message is sent
- within a thread.
-
- The send-message hook does not return a value, and the next hook in the
- chain is always called. This hook can modify values in the SMHSTRUCT
- structure before returning.
-
- 28.3.3 Message-Filter Hook
-
- This hook is called during system modal loops, which include tracking the
- window size and window movement, displaying a dialog box or message box,
- scroll-bar tracking, menu-selection tracking, and window-enumeration
- operations. The message-filter hook is typically used to provide
- input-message filtering (such as monitoring hot keys) during modal dialog
- processing.
-
- The syntax of the message-filter hook is as follows:
-
- BOOL CALLBACK MsgFilterHook(HAB hab, USHORT msgf, PQMSG pQmsg)
-
- The msgf parameter has the following three values:
-
- Value Meaning
- ──────────────────────────────────────────────────────────────────────────
- MSGF_DIALOGBOX Message originated while processing a modal dialog
- window.
-
- MSGF_MESSAGEBOX Message originated while processing a message box.
-
- MSGF_TRACK Message originated while tracking a control (such
- as a scroll bar).
- ──────────────────────────────────────────────────────────────────────────
-
- The pQmsg parameter of the MsgFilterHook function is a far pointer to a
- QMSG structure containing information about the message.
-
- If this hook returns TRUE, the message is not passed to the rest of the
- hook chain or to the application. If it returns FALSE, the message is
- passed to the next hook in the chain, or to the application if no other
- hooks exist.
-
- This hook allows applications to perform message filtering during modal
- loops that is equivalent to the typical filtering for the main message
- loop. For example, applications often examine a new message in the main
- event loop between the time they retrieve the message from the queue and
- the time they dispatch it, performing special processing as appropriate.
- The following code fragment shows a main message loop that tests for the
- ENTER key and the ESC key before dispatching an event:
-
- while (WinGetMsg(hab, (PQMSG) &qmsg, (HWND) NULL, 0, 0)) {
-
- if ((qmsg.msg == WM_CHAR) && !(LOUSHORT(qmsg.mp1) & KC_KEYUP)
- && !hwndQueue) {
- switch (HIUSHORT(qmsg.mp2)) {
- case VK_ESC:
-
- /* Use the ESC key. */
-
- continue;
-
- case VK_NEWLINE:
-
- /* Use the newline event. */
-
- continue;
-
- default:
- break;
- }
- }
- WinDispatchMsg(hab, (PQMSG) &qmsg);
- }
-
- You cannot usually do this sort of filtering during a modal loop, since
- the loop created by the WinGetMsg and WinDispatchMsg functions is executed
- by the system. If you install a message-filter hook, the hook is called by
- the system between WinGetMsg and WinDispatchMsg in the modal processing
- loop.
-
- Your application can also call the message-filter loop directly by calling
- the WinCallMsgFilter function. By using this function, you can use the
- same code to filter messages in your main message loop and during modal
- loops. In the example shown previously for processing main message loops,
- you would encapsulate the filtering operations in a message-filter hook
- and call WinCallMsgFilter between the calls to the WinGetMsg and
- WinDispatchMsg functions, as shown in the following code fragment:
-
- while (WinGetMsg(hab, (PQMSG) &qmsg, (HWND) NULL, 0, 0)) {
- if (!WinCallMsgFilter(hab, (PQMSG) &qmsg, 0))
- WinDispatchMsg(hab, (PQMSG) &qmsg);
- }
-
- The last argument of the WinCallMsgFilter function is simply passed to the
- hook; the application can enter any value. This value can be used by the
- hook to determine where the hook was called from, by defining a constant
- such as MSGF_MAINLOOP.
-
- 28.3.4 Journal-Record Hook
-
- This hook monitors the system queue and allows the application to record
- input events. Typically, it is used to record a set of mouse and keyboard
- events that can be played back later by using the journal-playback hook.
- The journal-record hook can be installed only in the system queue.
-
- The syntax for the journal-record hook is as follows:
-
- VOID CALLBACK JournalRecordHook(HAB hab, PQMSG pQmsg)
-
- The pQmsg parameter is a far pointer to a QMSG structure containing
- information about the message. The hook is called after the raw input has
- been processed enough to create valid WM_CHAR or double-click mouse
- messages and the window-handle field of the QMSG structure has been set.
-
- The journal-record hook does not return a value, and the next hook in the
- chain is always called. Typically, this hook saves the input event to the
- disk, to be played back later. The hwnd field of the QMSG structure is not
- important and is ignored when the message is read back.
-
- Character messages are passed to the journal-record hook as WM_VIOCHAR
- messages. The format of the WM_VIOCHAR message is as follows:
-
- fsKeyFlags = (USHORT) SHORT1FROMMP(mp1); /* key flags */
- uchRepeat = (UCHAR) CHAR3FROMMP(mp1); /* repeat count */
- uchScanCode = (UCHAR) CHAR4FROMMP(mp1); /* scan code */
- usChr = LOBYTE(LOWORD(mp2)); /* character */
- uschKbdScan = HIBYTE(LOWORD(mp2)); /* virtual key */
-
- The WM_VIOCHAR message was chosen over the WM_CHAR message because it
- preserves that raw information from the keyboard driver that is needed for
- video input and output.
-
- The following mouse messages are passed to the journal-record hook:
-
- WM_MOUSEMOVE
- WM_BUTTON1DOWN
- WM_BUTTON1UP
- WM_BUTTON2DOWN
- WM_BUTTON2UP
- WM_BUTTON3DOWN
- WM_BUTTON3UP
-
- The positions stored in the mouse messages are in screen coordinates. The
- system does not combine mouse clicks into double clicks before calling the
- hook, since there is no guarantee that both clicks will be in the same
- window when they are read back.
-
- A WM_JOURNALNOTIFY message is passed to the journal-record hook whenever a
- program calls the WinGetPhysKeyState or WinQueryQueueStatus function. This
- message is necessary because the system is reduced to a queue that is only
- one message deep while a playback hook is active. For example, the user
- might press the A, B, and C keys while in record mode. While the program
- is processing the "A" character message, the B key might be down;
- WinGetPhysKeyState will return this information. However, during playback
- mode, the system only knows that it is currently processing the A key.
-
- The format of the WM_JOURNALNOTIFY message is as follows:
-
- For the WinGetPhysKeyState function:
-
- ulCmd = LONGFROMMP(mp1); /* calling function */
- sc = SHORT1FROMMP(mp2); /* virtual key */
- fsPhysKeyState = SHORT2FROMMP(mp2); /* physical-key state */
-
- For the WinQueryQueueStatus function:
-
- ulCmd = LONGFROMMP(mp1); /* calling function */
- ulQueStatus = LONGFROMMP(mp2); /* queue status */
-
- 28.3.5 Journal-Playback Hook
-
- The journal-playback hook allows an application to insert messages into
- the system queue. Typically, this hook is used to play back a series of
- mouse and keyboard events that were recorded earlier by using the
- journal-record hook. This hook can be installed only in the system queue.
-
- Regular mouse and keyboard input is disabled as long as a journal-playback
- hook is installed. It is important to note that, since mouse and keyboard
- input are disabled, this hook can easily hang the system.
-
- The syntax for the journal-playback hook is as follows:
-
- ULONG CALLBACK JournalPlaybackHook(HAB hab, PQMSG pQmsg,
- BOOL fSkip)
-
- The pQmsg parameter is a far pointer to a QMSG structure that the hook
- fills in with the message to be played back. If the fSkip parameter is
- FALSE, the hook should fill in the QMSG structure with the current
- recorded message. The same message should be returned each time the hook
- is called, until fSkip is TRUE. The same message may be returned many
- times if an application is examining the queue but not removing the
- message. If fSkip is TRUE, the hook should advance to the next message
- without attempting to fill in the QMSG structure, since the pQmsg
- parameter is NULL when fSkip is TRUE.
-
- The journal-playback hook returns a ULONG time-out value. This value tells
- the system how many milliseconds to wait before processing the current
- message from the playback hook. This allows the hook to control the timing
- of the events it plays back.
-
- The time field of the QMSG structure is filled in with the current time
- before the playback hook is called. The hook should use the time stored in
- this field instead of the system clock to set up the delays.
-
- The discussion of different types of messages in Section 28.3.4 is also
- applicable to the journal-playback hook. The only exception has to do with
- character processing. The journal-record hook is always passed a
- WM_VIOCHAR message for each character processed by the system. The
- journal-playback hook, on the other hand, has the option of playing back
- either WM_VIOCHAR or WM_CHAR messages. The preferred method is to play
- back WM_VIOCHAR messages, since they contain the information required to
- function in a video-input-and-output window. If WM_CHAR messages are
- returned, the appropriate KC bits must be set or cleared.
-
- 28.3.6 Help Hook
-
- The help hook is called during the default processing of the WM_HELP
- message. Help processing is done in two stages: creating the WM_HELP
- message and calling the help hook. The WM_HELP message can come from the
- following sources:
-
- ■ From a WM_CHAR message, after translation by an ACCEL structure with
- the AF_HELP style. The default system accelerator table translates the
- F1 key into a help message. The WM_HELP message is posted to the
- current focus window, which can be a menu, a button, a frame, or your
- client window.
-
- ■ From a menu-bar selection, when the MIS_HELP style is specified for the
- menu-bar item. The WM_HELP message is posted to the current focus
- window.
-
- ■ From a dialog-box push button, when the BS_HELP style is specified for
- the push button. The WM_HELP message is posted to the button's owner
- window, which is normally the dialog window.
-
- ■ From a message box, when the MB_HELP style is specified for the message
- box. The WM_HELP message is posted to the message-box dialog window.
-
- The WM_HELP message is posted to the current focus window. The default
- processing in the WinDefWindowProc function is to pass the message up to
- the parent window. If the message reaches the client window, it can be
- processed there. If the message reaches a frame window, the default
- frame-window procedure calls the help hook. The help hook is also called
- if a WM_HELP message is generated while the application is in menu
- mode──that is, while a selection is being made from a menu.
-
- The syntax for the help hook is as follows:
-
- BOOL CALLBACK HelpHook(HAB hab, USHORT usMode, USHORT idTopic,
- USHORT idSubTopic, PRECTL prcPosition)
-
- If this hook function returns TRUE, the message is not passed to the rest
- of the hook chain or to the application. If it returns FALSE, the message
- is passed to the next hook in the chain. The arguments of the help hook
- provide context information, such as the screen coordinates of the focus
- window and whether the message originated in a message box or a menu.
-
- The WM_HELP message often goes to a frame window instead of to the client
- window. The frame window (including dialog boxes and message boxes)
- processes a WM_HELP message as follows:
-
- ■ If the window with the focus is the FID_CLIENT window, the frame window
- passes the WM_HELP message to the FID_CLIENT window.
-
- ■ If the parent of the window with the focus is the FID_CLIENT
- frame-control window, the frame window calls the help hook, specifying
- the following:
-
- Mode = HLPM_FRAME
- Topic = frame-window identifier
- Subtopic = focus-window identifier
- Position = screen coordinates of focus window
-
- ■ If the parent of the focus window is not an FID_CLIENT window (it could
- be the frame window or a second-level dialog window), the frame window
- calls the help hook, specifying the following:
-
- Mode = HLPM_WINDOW
- Topic = identifier of parent of focus window
- Subtopic = focus-window identifier
- Position = screen coordinates of focus window
-
- An application receives the WM_HELP message in its dialog-window
- procedure. The application can ignore the message, in which case the
- frame-manager action occurs as described, or the application can handle
- the WM_HELP message directly.
-
- Menu windows receive a WM_HELP message when the user presses the help
- accelerator key (F1 by default) while a menu is displayed. Menu windows
- process WM_HELP messages by calling the help hook, specifying the
- following:
-
- Mode = HLPM_MENU
- Topic = identifier of pull-down menu
- Subtopic = identifier of selected item in pull-down menu
- Position = screen coordinates of selected item
-
- The help hook should respond to the help message by displaying information
- about the selected menu item.
-
- The WinDefWindowProc function processes WM_HELP messages by passing the
- message to the parent window. The message typically moves up the parent
- chain until it arrives at a frame window.
-
-
- 28.4 Using Hooks
-
- Applications install hooks by calling the WinSetHook function, specifying
- the type of hook, whether it should go into the system queue or into the
- queue of a particular thread, and a far pointer to a function entry point.
-
- Procedures installed as hooks in a thread's queue are called only in the
- context of that thread. This kind of hook is typically a locally defined
- function.
-
- Procedures installed as hooks in the system queue can be called in the
- context of any application. System-queue hooks must be defined in separate
- dynamic-link-library (DLL) modules, because it is not possible to call
- application-module procedures from other applications. For a sample
- system-queue DLL module, see Section 28.5.
-
- A hook can be released by calling the WinReleaseHook function with the
- same arguments used when installing the hook. All hooks should be released
- before the application terminates, although the system automatically
- releases them if the application does not.
-
- A system hook can be released by using the WinReleaseHook function, but
- the DLL function containing the hook procedure is not freed. This is
- because system hooks are called in the process context of every
- Presentation Manager application in the system, causing an implicit call
- to the DosLoadModule function for all of those processes. Since a call to
- the DosFreeModule function cannot be made for another process, there is no
- way to free the dynamic-link libraries. (However, since the hook procedure
- is no longer called, the DLL segments may be discarded or swapped.)
-
-
- 28.5 Hook Example
-
- This section shows the main elements of installing and using a
- system-input-queue hook, although many of the details of the hook are
- omitted. The example code comes from a larger program that uses a hook to
- monitor the input queue and display all input messages in an application
- window on the screen. This example has two main parts: the installing
- application and the hook DLL. The installing application identifies a hook
- procedure in the DLL and installs it in the system-queue hook chain. The
- application then controls the hook through other function calls to the
- DLL, performing such actions as turning the hook on and off and asking it
- for the most recent messages.
-
- The system hook is more than a single hook procedure; it is typically a
- DLL with several support procedures and entry points. This allows the
- installing application to control and communicate with the hook procedure.
-
- 28.5.1 Installing a System Hook
-
- Since this example is a system hook, the hook procedure must be in a
- separate DLL from the application that installs it. The installing
- application needs the module handle of the DLL before it can install the
- hook. The DosLoadModule function, given the name of the DLL, returns the
- handle of the module. Once the module handle is known, the application
- calls the WinSetHook function, passing the module handle, a far pointer to
- the hook-procedure entry point, and NULL for the message-queue argument,
- indicating that the hook should go into the system queue. This sequence is
- shown in the following code fragment:
-
- CHAR achFailName[128];
- HMODULE hmodSpy;
- BOOL fRet;
-
- /*
- * This example assumes that there is a hook procedure named
- * "SpyInputHook" that resides in a DLL file named "spyhook.dll,"
- * and that "spyhook.dll" is in a directory defined by the LIBPATH
- * command in the config.sys file.
- */
-
- if (DosLoadModule(achFailName, /* failure-name buffer */
- sizeof(achFailName), /* size of failure buffer */
- "spyhook", /* module name */
- &hmodSpy) == 0) { /* address of handle */
-
- fRet = WinSetHook(hab, /* anchor-block handle */
- (HMQ) NULL, /* system queue */
- HK_INPUT, /* hook type */
- (PFN) SpyInputHook, /* far pointer to function */
- hmodSpy); /* module handle for DLL */
- }
-
- An alternative method for installing a system queue is to provide an
- installation function in the DLL along with the hook procedure. With this
- method, the installing application does not need the module handle for the
- DLL. By linking with the DLL, the application gains access to the
- installation function. The installation function can supply the module
- handle and other details in the call to the WinSetHook function. The DLL
- can also contain a function that removes the system-hook procedure; the
- application can call this function when it terminates.
-
- 28.5.2 System-Hook Code
-
- The hook procedure is part of the DLL module. As such, it has access to
- the resources of the module: its global variables, other support
- procedures, and any memory allocated by the module. The following code
- template shows the structure of a typical input-hook procedure. It uses a
- static variable to control whether or not it should examine the input
- messages. Although it is not required, the DLL would typically provide
- another procedure to toggle the state of the variable, so that an
- application that installs the hook can turn the hook on and off.
-
- This example could save each message in a buffer allocated during the
- initialization of the DLL module. The DLL module would also provide a
- calling interface, so that the installing application could periodically
- request the messages from the buffers.
-
- BOOL CALLBACK PASCAL SpyInputHook(hab, lpqmsg)
- HAB hab;
- PQMSG lpqmsg;
- {
- static BOOL fRecording;
-
- /*
- * The lpqmsg parameter points to a queue-message structure.
- * Returns FALSE to let the message through to the rest of the
- * hook chain. Returns TRUE to prevent further message processing.
- */
-
- if (!fRecording)
- return FALSE; /* pass message to rest of chain */
-
- /* Else examine message and process as appropriate. */
-
- return FALSE;
-
- }
-
-
- 28.6 Summary
-
- This section summarizes the six types of hooks and the functions related
- to hooks.
-
- 28.6.1 Functions
-
- The following functions are used with hooks:
-
- WinCallMsgFilter Calls the currently installed message-filter chain of
- hooks. This call is useful if the same message filtering is used in the
- main message loop and the modal system-message loops.
-
- WinReleaseHook Removes a specified procedure from the input-hook chain.
-
- WinSetHook Installs a specified procedure in either the system or queue
- chain of hooks.
-
- 28.6.2 Hook Types
-
- The following constants are used to identify the type of hook being
- installed or released by the WinSetHook or WinReleaseHook function:
-
- HK_HELP Monitors the WM_HELP message. Returns BOOL. If FALSE, the next
- hook in the chain is called. If TRUE, the next hook in the chain is not
- called.
-
- HK_INPUT Monitors messages in the specified message queue. Returns BOOL.
- If FALSE, the next hook in the chain is called. If TRUE, the message is
- not passed to the next hook in the chain.
-
- HK_JOURNALPLAYBACK Allows applications to insert events into the
- system-input queue. Returns a LONG time-out value. This value is the
- number of milliseconds to wait before processing the current message. This
- type never calls the next hook in the chain.
-
- HK_JOURNALRECORD Allows applications to record system-input-queue events.
- Returns VOID. The next hook in the chain is always called.
-
- HK_MSGFILTER Monitors input events during system modal loops. Returns
- BOOL. If FALSE, the next hook in the chain is called. If TRUE, the message
- is not passed to the next hook in the chain.
-
- HK_SENDMSG Monitors messages sent by using the WinSendMsg function.
- Returns VOID. The next hook in the chain is always called.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 29 Help
-
- 29.1 Introduction
- 29.2 About Help
- 29.3 Using Help in an Application
- 29.3.1 Help Menu Item
- 29.3.2 Help in a Dialog Box
- 29.3.3 Help in a Message Box
- 29.3.4 Help for a Menu Item
- 29.3.5 The Help Hook
- 29.3.5.1 Installing a Help Hook
- 29.3.5.2 Help Hook for a Menu Item
- 29.4 Summary
- 29.4.1 Functions
- 29.4.2 Messages
- 29.4.3 Syntax of the Help Hook
-
- 29.1 Introduction
-
- This chapter describes how to use the WM_HELP message in your
- applications. You should also be familiar with the following topics:
-
- ■ Standard user-interface guidelines
-
- ■ Window messages and message queues
-
- ■ Focus window and input guidelines
-
- ■ Help hook
-
-
- 29.2 About Help
-
- One of the key elements of user-friendly software is readily available
- on-line help. MS OS/2 provides functions and messages to support the
- implementation of a help system in your application. This chapter
- discusses the features of MS OS/2 that support on-line help and suggests
- techniques for implementing a help system. The two main components of the
- system support for help are the WM_HELP message and the help hook.
-
- The WM_HELP message is defined by the system to notify an application when
- the user wants help. The WM_HELP message contains context information that
- allows the application to respond with information appropriate to current
- conditions. The system posts a WM_HELP message in the following
- situations:
-
- ■ During accelerator-table translation for a keyboard event, if the
- keystroke corresponds to an accelerator-table entry with the AF_HELP
- attribute. The system default accelerator table translates the F1 key
- into a WM_HELP message. The WM_HELP message is posted to the focus
- window. If the F1 key is pressed while a menu has the focus, the help
- message goes to the menu, which calls the help hook.
-
- ■ When a menu item with the MIS_HELP style is chosen. All applications
- should define at least one menu item with the MIS_HELP style in the
- menu bar. This menu item is typically labeled "F1=Help," as shown in
- Figure 29.1. The WM_HELP message is posted to the focus window.
-
- ■ When a push button with the BS_HELP style is pressed. (Note that this
- includes the case in which the Help button is pressed in a message box
- that has the MB_HELP style.) The WM_HELP message is posted to the
- button's owner window, which is typically a dialog frame window.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 29.1 can be found in Section 29.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 29.1 Help Menu Item
-
- The Help menu item and the F1 accelerator key provide a standard
- user-interface to the help system. They allow the user to get general help
- about the application. The BS_HELP push button style allows applications
- to provide help within dialog boxes. You should provide a Help push button
- in every dialog box; the help message should explain the purpose and
- consequence of any action that could be taken by using that dialog box.
-
- Your application should process the WM_HELP message to provide
- context-appropriate help to the user. In the case of the Help menu item or
- the F1 accelerator key, the WM_HELP message is posted to the focus window.
- The focus window can process the message or it can pass it to the
- WinDefWindowProc function, which sends the message to the parent window.
- If you have a client window with several child windows that can accept the
- focus, you can intercept the WM_HELP message in the client window
- procedure as the message is passed up from the child window with the
- focus. The state of the application when the help message is received
- determines the appropriate help, which may be a list of help topics or
- information about the window that has the focus.
-
- There are limits to what can be accomplished by intercepting the WM_HELP
- message. In particular, the application does not receive WM_HELP messages
- generated while a menu item is selected. For example, if the user presses
- the F1 key while selecting a menu item, the WM_HELP message goes to the
- menu window. The menu window does not pass the message on; instead, it
- calls the help hook.
-
- The help hook allows you to install code that is called by menu windows
- and frame windows when they receive WM_HELP messages. You must install a
- help hook for your application if you want to provide help for selected
- menu items, since there is no way to intercept the WM_HELP message that
- originates while a menu item is selected. In addition, if you don't
- process a WM_HELP messages in your client window, the message is passed to
- the frame window, which calls the help hook.
-
- The following sections describe in more detail how to handle WM_HELP
- messages and when to install a help hook.
-
-
- 29.3 Using Help in an Application
-
- There are two methods of providing help in an application. The simplest
- method provides general information to the user by processing the WM_HELP
- message in the client window. The second method, installing a help hook,
- provides help in situations in which the WM_HELP message is not available
- to the client window. Since installing a help hook is not difficult, most
- applications use both methods.
-
- 29.3.1 Help Menu Item
-
- Every application should have a Help menu item in the menu bar of its main
- window. The text of the Help item should be "F1=Help" and it should have a
- menu-item identifier of zero. The Help menu item should have the MIS_HELP
- and MIS_BUTTONSEPARATOR styles. The following resource-definition file
- shows how to place a Help item in the menu bar.
-
- MENU ID_MENU_RSRC
- BEGIN
- SUBMENU "~File", IDM_FILE
- BEGIN
- MENUITEM "~Quit", IDM_FI_QUIT
- MENUITEM "", IDM_FI_SEP3, MIS_SEPARATOR
- MENUITEM "~About Sample...", IDM_FI_ABOUT
- END
- SUBMENU "~Edit", IDM_EDIT
- BEGIN
- MENUITEM "~Undo", IDM_ED_UNDO, 0,MIA_DISABLED
- MENUITEM "", IDM_ED_SEP1, MIS_SEPARATOR
- MENUITEM "~Cut", IDM_ED_CUT, 0,MIA_DISABLED
- MENUITEM "C~opy", IDM_ED_COPY, 0,MIA_DISABLED
- MENUITEM "~Paste", IDM_ED_PASTE, 0,MIA_DISABLED
- MENUITEM "C~lear", IDM_ED_CLEAR, 0,MIA_DISABLED
- END
- MENUITEM "F1=Help", 0x00, MIS_HELP | MIS_BUTTONSEPARATOR
- END
-
- If the user clicks the Help item in the menu bar, the system posts a
- WM_HELP message to the current focus window. If the client window has the
- focus, it can process the WM_HELP message to provide general help
- information for the user. If a child window of the client has the focus,
- the child window passes the message up the parent-window chain to the
- client window (by default). In this case, the client window can process
- the WM_HELP message appropriately for the child window that has the focus.
-
- If the client window passes the WM_HELP message on to the WinDefWindowProc
- function, this function passes the message up the parent-window chain
- until it finds a frame window. The default frame window processes the
- WM_HELP message by calling the help hook.
-
- 29.3.2 Help in a Dialog Box
-
- You should provide a Help button in each dialog box that your application
- displays. The Help button should have the BS_HELP style. When the user
- presses the Help button, a WM_HELP message is posted to the button's
- owner, which is usually the dialog window. The dialog procedure can
- process the message and give the user help pertaining to the dialog box.
- Alternatively, if you pass the WM_HELP message on to the WinDefDlgProc
- function, it will call the help hook; this means you can choose whether to
- process dialog help in the dialog procedure or in the help hook.
-
- 29.3.3 Help in a Message Box
-
- A message box can be given a Help button by specifying MB_HELP when
- creating the message box. Message boxes are like dialog boxes, except that
- you do not specify your own dialog procedure. If a message box contains a
- Help button, the program does not process the WM_HELP message. The default
- window procedure for the message box responds to the WM_HELP message by
- calling the help hook. To provide help for message boxes, you must install
- a help hook. Because the window identifier that you specify for the
- message box is passed to the help hook, you must use unique identifiers if
- you want to provide help for multiple message boxes.
-
- 29.3.4 Help for a Menu Item
-
- One of the most important functions of a help system is to provide
- information about individual menu items. The user requests help for a menu
- item by pressing the F1 key while the menu item is selected. The menu
- receives the WM_HELP message, since the menu has the focus while the item
- is selected. The menu responds to the message by calling the help hook,
- supplying the identifier of the selected item.
-
- You must install a help hook to provide this kind of help for individual
- menu items. For an example of a help hook that supplies information about
- menu items, see Section 29.3.5.2.
-
- A method of supplying less comprehensive help for menu items is to use the
- WM_MENUSELECT message. The menu system sends a WM_MENUSELECT message every
- time the menu selection changes. The low word of the mp1 parameter of this
- message contains the identifier of the item that is changing state, and
- the high word is a 16-bit Boolean value that describes whether or not the
- item is chosen; the mp2 parameter contains the handle of the menu.
-
- If the Boolean value is FALSE, the menu item is selected but not
- chosen──for example, if the user moves the cursor or mouse pointer over
- the item while the button is down. An application can use this message to
- display brief help information at the bottom of the application window.
-
- 29.3.5 The Help Hook
-
- You must install a help hook if you want to provide help for message boxes
- or menu items. You can also use the help hook to provide help when WM_HELP
- messages are passed up to a frame window. You can install more than one
- help hook; the system will call them in last-installed, first-called
- order.
-
- The parameters for a sample help hook are shown in this code fragment:
-
- BOOL CALLBACK HelpHook(HAB hab,
- USHORT usMode,
- USHORT idTopic,
- USHORT idSubTopic,
- PRECTL prcPosition);
-
- The usMode parameter has three possible values:
-
- Value Description
- ──────────────────────────────────────────────────────────────────────────
- HLPM_MENU The help message originated in a menu window when the
- user pressed the F1 key while a menu item was selected.
-
- HLPM_FRAME The frame window received a WM_HELP message, and the
- parent of the focus window is the client window of the
- frame window.
-
- HLPM_WINDOW The frame window received a WM_HELP message, and the
- parent of the focus window is not the client window of
- the frame window.
- ──────────────────────────────────────────────────────────────────────────
-
- The value of the idTopic parameter depends on the value of the usMode
- parameter. The following list shows the values of the idTopic parameter:
-
- Value Description
- ──────────────────────────────────────────────────────────────────────────
- HLPM_MENU Identifier of submenu containing selected item.
-
- HLPM_FRAME Identifier of frame window that called the help hook.
-
- HLPM_WINDOW Identifier of parent of focus window.
- ──────────────────────────────────────────────────────────────────────────
-
- The value of the idSubTopic parameter depends on the value of the usMode
- parameter. The following list shows the values of the idSubTopic
- parameter:
-
- Value Description
- ──────────────────────────────────────────────────────────────────────────
- HLPM_MENU Identifier of selected menu item (-1 if menu-bar item is
- selected).
-
- HLPM_FRAME Identifier of focus window.
-
- HLPM_WINDOW Identifier of focus window.
- ──────────────────────────────────────────────────────────────────────────
-
- The prcPosition parameter of the help hook indicates the screen area from
- which the help was requested. This argument may be the bounding rectangle
- of a menu item or the bounding rectangle of the focus window. You should
- use this information when displaying your help window to avoid covering up
- the corresponding screen area.
-
- The following code fragment shows a template for a help hook that handles
- the three possible calling modes:
-
- BOOL CALLBACK HelpHook(HAB hab,
- USHORT usMode,
- USHORT idTopic,
- USHORT idSubTopic,
- PRECTL prcPosition);
- {
- CHAR szMessage[256];
- switch(usMode){
- case HLPM_MENU:
- /*
- * idTopic: submenu identifier
- * idSubTopic: item identifier
- * prcPosition: boundary of item
- */
-
- break;
-
- case HLPM_FRAME:
- /*
- * idTopic: frame identifier
- * idSubTopic: focus-window identifier
- * prcPosition: boundary of focus window
- */
-
- break;
-
- case HLPM_WINDOW:
- /*
- * idTopic: identifier of parent of focus window
- * idSubTopic: focus-window identifier
- * prcPosition: boundary of focus window
- */
-
- break;
- }
- }
-
- 29.3.5.1 Installing a Help Hook
-
- Typically, you define a help hook as a function in your program's source
- code. At run time you install the help hook by calling the WinSetHook
- function, specifying the message queue and a pointer to the help function,
- as shown in the following code fragment:
-
- /* Install the help hook. */
-
- WinSetHook(hab, /* anchor block */
- hmq, /* message queue */
- HK_HELP, /* hook type */
- (PFN) HelpHook, /* function pointer */
- NULL); /* module = NULL => in our .exe */
-
- If you install a help hook you must release it by using the WinReleaseHook
- function before your program terminates. The following code fragment shows
- how to release a help hook:
-
- /* Release the help hook. */
-
- WinReleaseHook(hab, /* anchor block */
- hmq, /* message queue */
- HK_HELP, /* hook type */
- (PFN) HelpHook, /* function pointer */
- NULL); /* module = NULL => in our .exe */
-
- 29.3.5.2 Help Hook for a Menu Item
-
- If the user presses the F1 key while a menu item is selected, the menu
- receives a WM_HELP message. The menu responds to the help message by
- calling the help hook with the HLPM_MENU argument to the usMode parameter
- of the HelpHook function. The idTopic parameter contains the identifier of
- the submenu containing the selected item. The idSubTopic parameter
- contains the identifier of the selected item. If the selected item is in
- the menu bar instead of a submenu, idTopic contains the identifier of the
- menu-bar item and idSubTopic contains 0xFFFF.
-
- Your help hook can use this information to determine which menu item was
- selected when the F1 key was pressed. Using this information, the help
- hook should display information that explains the function of the menu
- item. The following code fragment shows a help hook that is capable of
- giving information about a file menu with two items and an edit menu with
- five items:
-
- BOOL CALLBACK HelpHook(HAB hab,
- USHORT usMode,
- USHORT idTopic,
- USHORT idSubTopic,
- PRECTL prcPosition);
- {
- /*
- * idTopic: submenu identifier
- * idSubTopic: item identifier
- */
- switch(usMode){
-
- case HLPM_MENU:
-
- switch(idTopic){
-
- case IDM_FILE:
- /* One of the File menu items is selected. */
- switch(idSubTopic){
- case 0xFFFF:
- /*
- * A menu-bar item is selected; display
- * information on all items in File menu.
- */
- break;
-
- case IDM_FI_QUIT:
- /* Display information on Quit item. */
- break;
-
- case IDM_FI_ABOUT:
- /* Display information on About item. */
- break;
-
- } /* ends idSubTopic switch */
- break;
-
- case IDM_EDIT:
- /* One of the Edit menu items is selected. */
- switch(idSubTopic) {
- case 0xFFFF:
- /*
- * A menu-bar item is selected; display
- * information on all items in Edit menu.
- */
- break;
-
- case IDM_ED_UNDO:
- /* Display information on Undo item. */
- break;
-
- case IDM_ED_CUT:
- /* Display information on Cut item. */
- break;
-
- case IDM_ED_COPY:
- /* Display information on Copy item. */
- break;
-
- case IDM_ED_PASTE:
- /* Display information on Paste item. */
- break;
- case IDM_ED_CLEAR:
- /* Display information on Clear item. */
- break;
-
- } /* ends idSubTopic switch */
-
- break; /* ends IDM_EDIT case */
-
- } /* ends idTopic switch */
-
- break; /* ends HLPM_MENU case */
- }
- }
-
-
- 29.4 Summary
-
- This section lists the functions and messages associated with providing
- help to the user, as well as a syntax description of the help hook.
-
- 29.4.1 Functions
-
- The following functions work with the help hooks:
-
- WinSetHook Installs a help hook in an application's message queue.
-
- WinReleaseHook Releases a hook installed by using the WinSetHook
- function.
-
- 29.4.2 Messages
-
- The following message is sent to notify an application that the user wants
- help:
-
- WM_HELP Sent when a user requests help by pressing the F1 key or choosing
- a menu item or button with the help style.
-
- 29.4.3 Syntax of the Help Hook
-
- The following syntax description is for the help hook, which is used to
- provide help for message boxes and menu items:
-
- BOOL CALLBACK HelpHook (HAB hab, USHORT usMode, USHORT idTopic, USHORT
- idSubTopic, PRECTL iprcPosition)
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- PART 3 GRAPHICS PROGRAMMING INTERFACE
- ────────────────────────────────────────────────────────────────────────────
- Chapter 30 Presentation Spaces and Device Contexts
- Chapter 31 Coordinate Spaces and Transformations
- Chapter 32 Line and Arc Primitives
- Chapter 33 Fonts and Character Primitives
- Chapter 34 Color and Mix Modes
- Chapter 35 Paths
- Chapter 36 Area Primitives
- Chapter 37 Marker Primitives
- Chapter 38 Bitmaps
- Chapter 39 Regions
- Chapter 40 Clipping
- Chapter 41 Metafiles
- Chapter 42 Segments and Retained Graphics
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 30 Presentation Spaces and Device Contexts
-
- 30.1 Introduction
- 30.2 About Presentation Spaces and Device Contexts
- 30.2.1 Presentation Spaces
- 30.2.1.1 Normal Presentation Spaces
- 30.2.1.2 Micro Presentation Spaces
- 30.2.1.3 Saving and Restoring Presentation Spaces
- 30.2.1.4 Destroying Presentation Spaces
- 30.2.2 Device Contexts
- 30.2.2.1 Normal Device Contexts
- 30.2.2.2 Cached Device Contexts
- 30.2.2.3 Closing Device Contexts
- 30.2.3 Linking Presentation Spaces with Devices
- 30.2.4 The Presentation Page
- 30.2.5 Determining Device Capabilities
- 30.3 Using Presentation Spaces and Device Contexts
- 30.3.1 Creating a Normal Presentation Space
- 30.3.2 Creating a Standard Device Context for a Printer
- 30.3.3 Creating a Standard Device Context for a Metafile
- 30.3.4 Reassociating a Normal Presentation Space
- 30.3.5 Associating a Device Context with a Presentation Space
- 30.4 Summary
-
-
- 30.1 Introduction
-
- This chapter describes Microsoft Operating System/2 presentation spaces
- and device contexts. You should also be familiar with the following
- topics:
-
- ■ Coordinate spaces and transformations
-
- ■ Segments
-
-
- 30.2 About Presentation Spaces and Device Contexts
-
- A presentation space is a data structure maintained by MS OS/2 that
- describes an application's device-independent drawing environment. A
- device context links a presentation space to a device and gives an
- application access to important device information.
-
- 30.2.1 Presentation Spaces
-
- There are two kinds of presentation spaces: normal and micro. You must use
- a normal presentation space to display and print output on multiple
- devices (a video display and a printer, for instance) or if your
- application uses the segment and retained-drawing functions to generate
- complex drawings. You should use a micro presentation space only to
- display and print output on a single device or if your application's
- output is a simple drawing. For a list of the segment and retained-drawing
- functions that are not supported by a micro presentation space, see
- Section 30.2.1.2.
-
- There are two kinds of micro presentation spaces: standard and cached. Use
- a standard micro presentation space to send output to a printer, a
- plotter, or any device; use a cached-micro presentation space to send
- output to a window on the display device.
-
- Table 30.1 summarizes the features and restrictions of each type of
- presentation space:
-
- Table 30.1
- Presentation-Space Features and Restrictions
- ──────────────────────────────────────────────────────────────────────────
- Presentation-space Retained-drawing Multiple-device support
- type support
- ──────────────────────────────────────────────────────────────────────────
- Normal Yes Yes
-
- Micro No No
-
- Cached-micro No No (restricted to a video-display
- window)
- ──────────────────────────────────────────────────────────────────────────
-
- 30.2.1.1 Normal Presentation Spaces
-
- Because normal presentation spaces use more memory than micro presentation
- spaces, you should use them only when they are required. To create a
- normal presentation space, use the GpiCreatePS function. You can then
- associate the normal presentation space with a device and reassociate it
- later with a new device when you need to direct output to that second
- device. To associate a normal presentation space with a device when you
- create the presentation space, use the GPIA_ASSOC flag when you call
- GpiCreatePS. To associate a normal presentation space with a second or a
- third device later while your application is running, call the
- GpiAssociate function.
-
- 30.2.1.2 Micro Presentation Spaces
-
- You can create a standard micro presentation space by calling the
- GpiCreatePS function and specifying the GPIT_MICRO flag. You must
- associate a standard micro presentation space with a device when you
- create the presentation space by specifying the GPIA_ASSOC flag as one of
- the options to GpiCreatePS and by supplying a handle that identifies a
- device context. You cannot reassociate a micro presentation space with
- another device.
-
- The window manager maintains a cache of micro presentation spaces for
- windows on a video display. You can access a cached-micro presentation
- space by calling the WinGetPS or WinBeginPaint function. You need not
- associate a cached-micro presentation space with the display; the window
- manager takes care of this for you.
-
- The following functions are not allowed in a micro presentation space:
-
- ■ GpiAssociate
-
- ■ GpiBeginElement
-
- ■ GpiCallSegmentMatrix
-
- ■ GpiCloseSegment
-
- ■ GpiCorrelateChain
-
- ■ GpiCorrelateFrom
-
- ■ GpiCorrelateSegment
-
- ■ GpiDeleteElement
-
- ■ GpiDeleteElementRange
-
- ■ GpiDeleteElementsBetweenLabels
-
- ■ GpiDeleteSegment
-
- ■ GpiDeleteSegments
-
- ■ GpiDrawChain
-
- ■ GpiDrawDynamics
-
- ■ GpiDrawFrom
-
- ■ GpiDrawSegment
-
- ■ GpiErase
-
- ■ GpiElement
-
- ■ GpiEndElement
-
- ■ GpiErrorSegmentData
-
- ■ GpiGetData
-
- ■ GpiLabel
-
- ■ GpiOffsetElementPointer
-
- ■ GpiOpenSegment
-
- ■ GpiPutData
-
- ■ GpiQueryBoundaryData
-
- ■ GpiQueryDrawControl
-
- ■ GpiQueryDrawingMode
-
- ■ GpiQueryEditMode
-
- ■ GpiQueryElement
-
- ■ GpiQueryElementPointer
-
- ■ GpiQueryElementType
-
- ■ GpiQueryInitialSegmentAttrs
-
- ■ GpiQueryPickAperturePosition
-
- ■ GpiQueryPickApertureSize
-
- ■ GpiQuerySegmentAttrs
-
- ■ GpiQuerySegmentNames
-
- ■ GpiQuerySegmentPriority
-
- ■ GpiQueryStopDraw
-
- ■ GpiQueryTag
-
- ■ GpiRemoveDynamics
-
- ■ GpiResetBoundaryData
-
- ■ GpiSetDrawControl
-
- ■ GpiSetDrawingMode
-
- ■ GpiSetEditMode
-
- ■ GpiSetElementPointer
-
- ■ GpiSetElementPointerAtLabel
-
- ■ GpiSetInitialSegmentAttrs
-
- ■ GpiSetPickAperturePosition
-
- ■ GpiSetPickApertureSize
-
- ■ GpiSetSegmentAttrs
-
- ■ GpiSetSegmentPriority
-
- ■ GpiSetStopDraw
-
- ■ GpiSetTag
-
- 30.2.1.3 Saving and Restoring Presentation Spaces
-
- You can save the contents of a presentation space, modify its fields, draw
- in the modified presentation space, and then restore it to its original
- state. The GpiSavePS function saves the contents of a presentation space
- and the GpiRestorePS function restores them. When you call GpiSavePS, MS
- OS/2 copies the following items from the current presentation space onto a
- special stack:
-
- ■ Primitive attributes
-
- ■ Transformation matrices
-
- ■ Viewing limit
-
- ■ Clip path
-
- ■ Clip region
-
- ■ Current position
-
- ■ Loaded logical color table
-
- ■ Loaded logical font
-
- You can push the contents of a presentation space on the stack, and you
- can do so as many times as is necessary. The GpiRestorePS function pops
- the contents of a presentation space off the stack.
-
- 30.2.1.4 Destroying Presentation Spaces
-
- Because presentation spaces consume a considerable amount of memory, you
- should destroy them whenever your application no longer needs them. To
- destroy a normal or micro presentation space, call the GpiDestroyPS
- function. Once you finish using a cached-micro presentation space that was
- accessed by using the WinGetPS function, you can release it by calling the
- WinReleasePS function. You need not destroy a presentation space that you
- accessed by using the WinBeginPaint function; MS OS/2 does this for you
- when you call the WinEndPaint function.
-
- 30.2.2 Device Contexts
-
- Device contexts link presentation spaces to devices by converting
- device-independent presentation-space information into device-dependent
- information. (This conversion occurs in the device driver, a low-level
- program that is transparent at the API level.) Device contexts also give
- applications access to important device information such as screen
- dimensions or printer capabilities.
-
- There are two kinds of device contexts: normal and cached. A normal device
- context links a presentation space with any type of device. A cached
- device context can link a presentation space only with a window on a video
- display.
-
- 30.2.2.1 Normal Device Contexts
-
- There are five types of normal device contexts:
-
- ■ Queued
-
- ■ Direct
-
- ■ Information
-
- ■ Memory
-
- ■ Metafile
-
- Each of these device contexts serves a specific purpose. A queued device
- context links a presentation space with a printer or plotter shared by
- multiple users. Queued devices store print jobs by using a program called
- a print spooler that keeps track of the order in which jobs arrive at the
- printer and the order in which they are printed. A direct device context
- links a presentation space with a printer or a plotter controlled by a
- single user and does not queue print jobs or other output. An information
- device context is a special device context that forms a one-way link to a
- device. An application can use an information device context to query a
- device but cannot send output to the device. A memory device links a
- presentation space with system memory. Memory device contexts are useful
- in applications that keep a "shadow" bitmap of the client area in a
- window. A metafile device context links a presentation space with a
- metafile. Applications that create complex drawings use metafiles to store
- the drawings.
-
- You can create a normal device context by calling the DevOpenDC function.
- This function requires you to specify one of the five types. It also
- requires that you pass important device-initialization data, including a
- logical address, the device-driver name, device-driver data, a description
- of the device type, and information about the queue (if the device is a
- queued device). The device-initialization data is passed in a DEVOPENSTRUC
- structure. This structure has the following form:
-
- typedef struct _DEVOPENSTRUC { /* dop */
- PSZ pszLogAddress; /* logical-device address */
- PSZ pszDriverName; /* device-driver name */
- PDRIVDATA pdriv; /* pointer to add'l driver data */
- PSZ pszDataType; /* type of queued data */
- PSZ pszComment; /* optional spooler info */
- PSZ pszQueueProcName; /* queue-processor name */
- PSZ pszQueueProcParams; /* queue-processor arguments */
- PSZ pszSpoolerParams; /* spooler arguments */
- PSZ pszNetworkParams; /* network arguments */
- } DEVOPENSTRUC;
-
- The last six fields in this structure apply only to queued devices. For
- more information about the DEVOPENSTRUC structure, see the Microsoft
- Operating System/2 Programmer's Reference, Volume 2.
-
- 30.2.2.2 Cached Device Contexts
-
- You can obtain a handle to one of the cached device contexts by calling
- the WinOpenWindowDC function. A cached device context is a direct device
- context that links a presentation space with a window in a video display.
- You should use a cached device context whenever a task will send output
- only to a window.
-
- 30.2.2.3 Closing Device Contexts
-
- To close a device context that your application opened by calling the
- DevOpenDC function, you can call the DevCloseDC function. However, you
- should not try to close a device context that you opened by using the
- WinOpenWindowDC function; MS OS/2 will do this for you automatically when
- you destroy the associated window.
-
- 30.2.3 Linking Presentation Spaces with Devices
-
- When you call the GpiCreatePS function and pass it the GPIA_ASSOC flag or
- when you call the GpiAssociate function, MS OS/2 requires that you pass
- the device-context handle returned by the DevOpenDC or WinOpenWindowDC
- function. This handle identifies the device context that links a
- presentation space to a device. Once you have established this link, any
- drawing operations performed using the presentation-space handle will also
- be performed on the associated device. Once an application is through
- using a particular device, it should disassociate the presentation space
- and the device by calling GpiAssociate and passing NULL as the second
- argument. A presentation space can be associated with a new device only
- after it has been disassociated from the original device, since it is not
- possible to associate a presentation space with more than one device at a
- time.
-
- 30.2.4 The Presentation Page
-
- One of the arguments to the GpiCreatePS function is a SIZEL structure that
- specifies the dimensions of the presentation space's presentation page. A
- presentation page is a representation of a page on a printer or a plotter
- or a representation of a maximized window on a video display. MS OS/2 uses
- presentation pages to scale and position output on a device. For more
- information about presentation pages, see Chapter 31, "Coordinate Spaces
- and Transformations."
-
- The page-unit constant PS_UNITS, which is another argument to GpiCreatePS,
- is related to the SIZEL structure. This constant can be one of seven
- values:
-
- ■ PU_ARBITRARY
-
- ■ PU_PELS
-
- ■ PU_LOMETRIC
-
- ■ PU_HIMETRIC
-
- ■ PU_LOENGLISH
-
- ■ PU_HIENGLISH
-
- ■ PU_TWIPS
-
- The page-unit constant defines the dimensions of each unit on the
- presentation page. For example, if you specify PU_PELS, the length of each
- page unit in the x-direction will be identical to the width of a pel, and
- the length of each page unit in the y-direction will be identical to the
- height of a pel on the selected output device. If you specify
- PU_LOENGLISH, each page unit will measure 0.01 inches in the x- and
- y-directions.
-
- If you link a presentation space to a device when you call GpiCreatePS, MS
- OS/2 automatically assigns page dimensions to your presentation page. If
- you do not link a presentation space to a device when you call
- GpiCreatePS, you must assign the page dimensions.
-
- 30.2.5 Determining Device Capabilities
-
- Once you have created a device context for a particular output device, you
- can determine the capabilities of that device by calling the DevQueryCaps
- function. This function retrieves the following information:
-
- ■ Device technology (whether the device is a raster or vector device)
-
- ■ Maximized window dimensions (if the device is a video display)
-
- ■ Page dimensions (if the device is a printer or plotter)
-
- ■ Character-box dimensions
-
- ■ Marker-box dimensions
-
- ■ Pel resolution
-
- ■ Color capabilities
-
- ■ Mix-mode capabilities
-
- You can use this information to, for example, select fonts, set up the
- presentation page, or create a new logical color table.
-
-
- 30.3 Using Presentation Spaces and Device Contexts
-
- You can use presentation-space and device-context functions to perform the
- following tasks:
-
- ■ Create a normal, micro, or cached-micro presentation space.
-
- ■ Delete, save, or restore a presentation space.
-
- ■ Create a standard or cached device context.
-
- ■ Associate a presentation space or device context.
-
- ■ Destroy a device context.
-
- ■ Retrieve information about a device's capabilities.
-
- 30.3.1 Creating a Normal Presentation Space
-
- The following code fragment shows how to create a presentation space with
- page units of 0.01 inches and associate it with a printer device context:
-
- HAB hab; /* anchor-block handle */
- HPS hpsNormal; /* presentation-space handle */
- HDC hdcPrinter; /* device-context handle */
- SIZEL sizlPage; /* page structure */
- .
- .
- .
- hpsNormal = GpiCreatePS(hab, hdcPrinter, &sizlPage,
- PU_LOENGLISH | GPIA_ASSOC);
-
- 30.3.2 Creating a Standard Device Context for a Printer
-
- The following code fragment shows how to create a printer device context:
-
- HDC hdcPrinter; /* handle of printer device context */
- HAB hab; /* anchor-block handle */
- DEVOPENSTRUC dop; /* device information */
-
- dop.pszLogAddress = "lpt1"; /* logical-device address */
- dop.pszDriverName = "PSCRIPT"; /* device-driver name */
- dop.pdriv = NULL; /* pointer to driver data */
- dop.pszDataType = "PM_Q_STD"; /* standard queued data */
-
- hdcPrinter = DevOpenDC(hab,
- OD_DIRECT, /* direct device type */
- "*", /* no data in os2.ini */
- 4L,
- (PDEVOPENDATA) &dop,
- (HDC) NULL);
-
- 30.3.3 Creating a Standard Device Context for a Metafile
-
- The following code fragment shows how to create a standard device context:
-
- HDC hdcMeta, hdcWin; /* handles of metafile and window DC */
- HAB hab; /* anchor-block handle */
- DEVOPENSTRUC dop; /* device information */
-
- dop.pszLogAddress = NULL; /* logical-device address */
- dop.pszDriverName = "DISPLAY"; /* device-driver name */
- dop.pdriv = NULL; /* pointer to driver data */
- dop.pszDataType = NULL; /* no queued data */
-
- hdcMeta = DevOpenDC(hab,
- OD_METAFILE, /* metafile DC */
- "*", /* ignores os2.ini */
- 4L, /* uses first 4 fields in dop */
- (PDEVOPENDATA) &dop, /* structure for system info */
- NULL); /* compatible with screen */
-
- 30.3.4 Reassociating a Normal Presentation Space
-
- The following code fragment shows how to break the link between a normal
- presentation space and a device context and reassociate the presentation
- space with a metafile device context:
-
- if (!GpiAssociate(hps, NULL)) /* breaks link between PS and DC */
- ReportError(...);
- if (!GpiAssociate(hps, hdcMeta)) /* reassociates PS and metafile DC */
- ReportError(...);
-
- 30.3.5 Associating a Device Context with a Presentation Space
-
- The following code fragment shows how to open a cached device context and
- associate it with a normal presentation space:
-
- HDC hdcWin; /* cached-device-context handle */
- HPS hpsWin; /* normal-presentation-space handle */
- HWND hwndClient; /* client-window handle */
- HAB hab; /* anchor-block handle */
- SIZEL sizlPage; /* presentation page */
-
- hdcWin = WinOpenWindowDC(hwndClient);
- hpsWin = GpiCreatePS(hab, hdcWin, &sizlPage,
- PU_LOENGLISH | GPIA_ASSOC);
-
-
- 30.4 Summary
-
- The following list summarizes the MS OS/2 presentation-space and
- device-context functions:
-
- DevCloseDC Closes a device context opened by the DevOpenDC function.
-
- DevOpenDC Opens a device context for a printer or plotter.
-
- DevQueryCaps Retrieves information about an output device.
-
- GpiAssociate Associates a presentation space with a device context. This
- function is only valid if the presentation-space type is normal; it is
- invalid for micro and cached-micro presentation spaces. Remember that a
- presentation space can be associated with only one device at a time. To
- associate a presentation space with a second device, you should do the
- following:
-
- ■ Disassociate the presentation space and the original device by calling
- GpiAssociate and passing it NULL as the second argument.
-
- ■ Associate the presentation space with the second device by calling
- GpiAssociate, passing it a handle that identifies the device context of
- the new device.
-
- GpiCreatePS Creates a normal or a micro presentation space. A normal
- presentation space is required if your application's output is sent to
- more than one device or if your application's output is complex. A micro
- presentation space is more useful if your application's output is sent to
- a single device and if the output is not complex.
-
- GpiDestroyPS Destroys a presentation space created by the GpiCreatePS
- function. Do not use this function to destroy a presentation space that
- was retrieved by calling the WinGetPS or WinBeginPaint function.
-
- GpiQueryPS Retrieves the dimensions of the presentation page.
-
- GpiResetPS Resets the attributes in a presentation space to one of the
- following states:
-
- ■ The original state of the presentation space.
-
- ■ The original state with one exception: Any resources such as regions,
- loaded color tables, or loaded fonts are saved and will not be
- destroyed.
-
- ■ The state of the presentation space prior to the creation of any
- retained segments.
-
- GpiRestorePS Restores the attributes of a presentation space that were
- saved by calling the GpiSavePS function.
-
- GpiSavePS Saves the attributes of a presentation space onto a special
- stack.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 31 Coordinate Spaces and Transformations
-
- 31.1 Introduction
- 31.2 About Coordinate Spaces and Transformations
- 31.2.1 Single-Coordinate-Space Systems
- 31.2.2 Multiple-Coordinate-Space Systems
- 31.2.3 Transformations
- 31.2.3.1 The MATRIXLF Structure and Fixed Values
- 31.2.3.2 Scaling Transformations
- 31.2.3.3 Rotation Transformations
- 31.2.3.4 Translation Transformations
- 31.2.3.5 Shear Transformations
- 31.2.3.6 Reflection Transformations
- 31.2.3.7 Combining Transformations
- 31.2.3.8 Round-off Error
- 31.2.4 World Coordinate Space
- 31.2.5 Model Coordinate Space
- 31.2.5.1 World-to-Model-Space Transformations
- 31.2.6 Page Coordinate Space
- 31.2.6.1 Model-to-Page-Space Transformations
- 31.2.7 Device Coordinate Space
- 31.2.7.1 Page-to-Device-Space Transformations
- 31.3 Using Coordinate Spaces and Transformations
- 31.3.1 Setting Convenient Drawing Units
- 31.3.2 Zooming a Picture
- 31.3.3 Rotating an Object in a Picture
- 31.4 Summary
-
-
-
- 31.1 Introduction
-
- This chapter describes coordinate spaces and transformations. You should
- also be familiar with the following topics:
-
- ■ Presentation spaces
-
- ■ Device contexts
-
- ■ Retained drawing
-
- ■ Clipping
-
-
- 31.2 About Coordinate Spaces and Transformations
-
- A coordinate space is a two-dimensional set of points. A point is the
- smallest definable location in a coordinate space. There are four
- coordinate spaces in Microsoft Operating System/2 Presentation Manager:
-
- ■ World coordinate space
-
- ■ Model coordinate space
-
- ■ Page coordinate space
-
- ■ Device coordinate space
-
- A coordinate system is a means of specifying the location of a point in a
- coordinate space. For each of the four coordinate spaces in MS OS/2, there
- is a corresponding coordinate system. The four coordinate systems for MS
- OS/2 are two-dimensional systems with x- and y-axes, an origin, and
- dimensions. The x-axis extends horizontally across the system; the y-axis,
- vertically across the system. The origin is located at the intersection of
- the x- and y-axes and lies at the center of the system. The world, model,
- and page coordinate systems' x- and y-axes extend from 0 to 134,217,727 in
- the positive direction and from 0 to -134,217,728 in the negative
- direction. The device coordinate system's x- and y-axes extend from 0 to
- 32,767 in the positive direction and from 0 to -32,768 in the negative
- direction. Figure 31.1 shows the device coordinate system, with its
- origin, axes, and dimensions:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.1 can be found in Section 31.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.1 Device Coordinate System
-
- When you specify a coordinate in MS OS/2, the values you use are long
- integers (32-bits).
-
- 31.2.1 Single-Coordinate-Space Systems
-
- All graphics systems use at least one coordinate space and system to
- generate output on a video display or printer. The simplest systems use a
- single coordinate space, whose points are the pels on the display. In
- single-coordinate-space, or single-space, systems, one corner of the
- display (usually the lower-left) corresponds to the origin of the
- coordinate system; the positive x-axis extends from the origin to the
- lower-right corner of the display; and the positive y-axis extends from
- the origin to the upper-left corner of the display. Figure 31.2 shows how
- the axes correspond to the display:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.2 can be found in Section 31.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.2 Video Display and Single-Coordinate-Space System
-
- When drawing, applications written for single-coordinate-space systems
- must specify distances and locations in pels. For example, when the
- application draws a straight line, it specifies starting and ending points
- in pels. So if the display measures 100 pels by 100 pels and the
- application supplies a line-drawing command with a starting point of (0,0)
- and an ending point of (50,50), the line shown in Figure 31.3 would
- appear on the display:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.3 can be found in Section 31.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.3 Diagonal Line in a Single-Coordinate-Space System
-
- There are two fundamental drawbacks to a graphics system with a single
- coordinate space:
-
- ■ Any application written for the graphics system is device dependent.
-
- ■ It is difficult to draw output in convenient units like centimeters,
- feet, inches, or twips.
-
- Since the coordinate space in a simple system is made up of pels, and
- since the shape of pels varies from device to device, the output from an
- application written for one device may look different on another device.
- Figure 31.4 demonstrates this principle: The display on the left measures
- 100 pels by 100 pels, the display on the right 640 pels by 350 pels. In
- each case, a rectangle has been drawn with a lower-left corner at (10,10)
- and an upper-right corner at (90,90). Note the different shapes of each
- rectangle.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.4 can be found in Section 31.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.4 One Rectangle Displayed on Two Different Devices
-
- Single-coordinate-space systems are difficult to use for drawing or
- computer-aided-design (CAD) applications since these applications work in
- units of inches, feet, meters, and so on. For example, to draw a simple
- horizontal line that is 1 inch long, you must perform the following tasks:
-
- 1. Determine the width (in inches) of the video display or printer paper.
-
- 2. Determine the width (in pels) of the video display.
-
- 3. Divide the width in pels by the width in inches to determine the ratio
- of pels to inches.
-
- 4. Using this ratio, perform the line-drawing command.
-
- 31.2.2 Multiple-Coordinate-Space Systems
-
- Single-coordinate-space systems do not provide the flexibility that most
- applications and application developers need. An application written for a
- single-space system will create meaningful output only on a device on
- which the pels are a certain width and height. Since spreadsheet,
- word-processing, desktop-publishing, and CAD applications normally draw
- output on video displays and printers or plotters, it is obvious that a
- single-space system is impractical. In Presentation Manager, however, you
- can avoid the limitations of a single-coordinate-space system by using
- additional coordinate spaces and other operations, called transformations.
- Transformations require two coordinate spaces──a source coordinate space
- and a target coordinate space.
-
- 31.2.3 Transformations
-
- When copying objects from one coordinate space to another, MS OS/2 applies
- one or more of five operations, called transformations, to the points that
- define the object. These five transformations──scaling, rotation,
- translation, shear, and reflection──enable you to write applications that
- can do the following tasks:
-
- ■ Run on a variety of video displays, printers, and plotters.
-
- ■ Use convenient units of measurement (centimeters, inches, feet,
- kilometers, miles, etc.).
-
- ■ Scroll and zoom pictures.
-
- ■ Rotate and scale objects in pictures.
-
- ■ Shift the positions of objects in pictures.
-
- ■ Display mirror images of objects in pictures.
-
- ■ Display sheared objects in pictures.
-
- When your application copies an object from the source coordinate space to
- the target coordinate space, the five transformations work as follows:
-
- ■ The scaling transformation makes the object look bigger or smaller.
-
- ■ The rotation transformation rotates the object.
-
- ■ The translation transformation shifts the object with respect to the
- origin of the coordinate system.
-
- ■ The shear transformation rotates either all the vertical or all the
- horizontal lines in an object.
-
- ■ The reflection transformation creates a mirror image of an object with
- respect to the x- or y-axis.
-
- Presentation Manager uses three-by-three matrices to represent the three
- transformations. For any point (x,y) in a source coordinate space, you can
- determine the corresponding point (x',y') in the target coordinate space
- by using the following matrix multiplication:
-
- ┌ ┐
- │ M11 M12 M13 │
- │ │
- [x y 1] X │ M21 M22 M23 │ = [x' y' 1]
- │ │
- │ M31 M32 M33 │
- └ ┘
-
- In the following example, the transformations are set to unity
- (represented by the identity matrix). In such cases, the original point in
- the source coordinate space is always identical to its corresponding point
- in the target coordinate space.
-
- ┌ ┐
- │ 1 0 0 │
- │ │
- [3 100 1] X │ 0 1 0 │ = [3 100 1]
- │ │
- │ 0 0 1 │
- └ ┘
-
- In the next example, the identity matrix is replaced with a new matrix
- that translates the point when the point is copied from the source
- coordinate space to the target coordinate space:
-
- ┌ ┐
- │ 1 0 0 │
- │ │
- [3 100 1] X │ 0 1 0 │ = [100 3 1]
- │ │
- │ 97 -97 1 │
- └ ┘
-
- In this example, the point (3,100) was translated to (100,3) by exchanging
- the values of M31 and M32.
-
- 31.2.3.1 The MATRIXLF Structure and Fixed Values
-
- A special data structure called the MATRIXLF structure contains nine
- fields that correspond to the nine elements in a three-by-three
- transformation matrix. Five of these fields are 32-bit long integer
- values; the remaining four are special 32-bit fixed values.
-
- A fixed value is a binary representation of a floating-point number. A
- fixed value has two parts: the high-order 16-bits and the low-order
- 16-bits. The high-order 16-bits contain a signed integer in the range
- -32,768 through 32,767; the low-order 16-bits contain the numerator of a
- fraction, in the range 0 through 65,535 (the denominator for this fraction
- is 65,536). Figure 31.5 shows the two parts of a fixed value:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.5 can be found in Section 31.2.3.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.5 Fixed Value
-
- You use fixed values to store the sines and cosines of angles for the
- rotation transformation. You also use fixed values to store scaling
- factors for the scaling transformation. To store the cosine of 60 degrees
- in a fixed value, you would multiply 0.5 by 65,536. The result, 32,768, is
- the value you would assign to a fixed value in the MATRIXLF structure. To
- store a scaling factor of, for example, 3 in a fixed value, you would
- multiply 3 by 65,536. Again, the result, 196,608, is the value you would
- assign to a fixed value in the MATRIXLF structure.
-
- The MAKEFIXED macro provides a quick and convenient method for determining
- fixed values. This macro requires two arguments: The first is the integer
- part of the fixed value, and the second is the fraction part of the fixed
- value. In the following example, MAKEFIXED is used to determine the
- fixed-value equivalent of 1-and-1/8:
-
- matlf.fxM11 = MAKEFIXED(1, 8192)
-
- The first argument, 1, is the integer part of the fixed value. The second
- argument, 8192, is the result of multiplying 65,536 by 1/8.
-
- The following type definition shows each of the fields in the MATRIXLF
- structure. Fields with an fx prefix contain fixed values; fields with an l
- prefix contain long values.
-
- typedef struct _MATRIXLF { /* matlf */
- FIXED fxM11; /* M11 */
- FIXED fxM12; /* M12 */
- LONG lM13; /* M13 */
- FIXED fxM21; /* M21 */
- FIXED fxM22; /* M22 */
- LONG lM23; /* M23 */
- LONG lM31; /* M31 */
- LONG lM32; /* M32 */
- LONG lM33; /* M33 */
- } MATRIXLF;
-
- 31.2.3.2 Scaling Transformations
-
- When you scale an object by using the scaling transformation, the matrix
- element M11 contains the horizontal scaling component (horz), and the
- matrix element M22 contains the vertical scaling component (vert):
-
- ┌ ┐
- │ horz 0 0 │
- │ │
- │ 0 vert 0 │
- │ │
- │ 0 0 1 │
- └ ┘
-
- 31.2.3.3 Rotation Transformations
-
- When you rotate an object clockwise by using the rotation transformation,
- the matrix element M11 contains the cosine of the rotation angle; M12, the
- negative sine of the rotation angle; M21, the sine of the rotation angle;
- and M22, the cosine of the rotation angle:
-
- ┌ ┐
- │ cos -sin 0 │
- │ │
- │ sin cos 0 │
- │ │
- │ 0 0 1 │
- └ ┘
-
- Remember that MS OS/2 applies a transformation to all points in the source
- coordinate space. This means that unless an object is drawn about the
- origin of the source coordinate space, translation will occur when the
- object is rotated or scaled. Figure 31.6 shows a triangle, first in its
- source coordinate space and then in its target coordinate space, rotated
- 45 degrees clockwise. Note the translation with respect to the origin.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.6 can be found in Section 31.2.3.3 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.6 Rotating an Object
-
- 31.2.3.4 Translation Transformations
-
- When you translate an object by using the translation transformation, the
- matrix element M31 contains the horizontal translation component, and the
- matrix element M32 contains the vertical translation component, as
- follows:
-
- ┌ ┐
- │ 1 0 0 │
- │ │
- │ 0 1 0 │
- │ │
- │ horz vert 1 │
- └ ┘
-
- 31.2.3.5 Shear Transformations
-
- There are two shear transformations: vertical and horizontal. When an
- application uses the vertical shear transformation, it affects only the
- vertical lines in the object. In the matrix of the vertical shear
- transformation, the element M21 contains a horizontal shear component, and
- the element M22 contains a vertical shear component, as follows:
-
- ┌ ┐
- │ 1 0 0 │
- │ │
- │ horz vert 0 │
- │ │
- │ 0 0 1 │
- └ ┘
-
- When an application uses the horizontal shear transformation, it affects
- only the horizontal lines in the object. In the matrix of the horizontal
- shear transformation, the element M11 contains a horizontal shear
- component, and the matrix element M12 contains a vertical shear component,
- as follows:
-
- ┌ ┐
- │ horz 0 0 │
- │ │
- │ vert 1 0 │
- │ │
- │ 0 0 1 │
- └ ┘
-
- If an application shears an object that contains two orthogonal vectors
- (two perpendicular lines), the vectors will no longer be orthogonal.
-
- 31.2.3.6 Reflection Transformations
-
- The reflection transformation creates a mirror image of an object with
- respect to the x- or the y-axis. The matrix element M11 contains the
- horizontal reflection component, which causes reflection about the y-axis.
- The matrix element M22 contains the vertical reflection component, which
- causes reflection about the x-axis. The reflection components are always
- negative.
-
- ┌ ┐
- │ horz 0 0 │
- │ │
- │ 0 vert 0 │
- │ │
- │ 0 0 1 │
- └ ┘
-
- 31.2.3.7 Combining Transformations
-
- Each time you call a Gpi function that sets a transformation, you can
- specify whether you want to combine it with existing transformations and,
- if so, whether you want MS OS/2 to apply the existing transformation
- before or after the new transformation.
-
- If you want MS OS/2 to replace any existing transformations with the new
- transformation, use the TRANSFORM_REPLACE flag when you set the
- transformation. If you want MS OS/2 to apply the new transformation before
- it applies the existing transformation, use the TRANSFORM_PREEMPT
- flag when you set the new transformation. If you want MS OS/2 to apply
- the new transformation after it applies the existing transformation, use
- the TRANSFORM_ADD flag when you set the new transformation.
-
- 31.2.3.8 Round-off Error
-
- Whenever you use transformations in your application, you should check for
- any round-off error that occurs after multiple scaling, rotation, shear,
- or reflection transformations. For example, if your application uses a
- rotation transformation to rotate the hands of a clock, the accuracy of
- the clock will diminish due to rounding off after the transformation. In
- order to prevent the loss of accuracy, your application should check the
- results of each transformation.
-
- 31.2.4 World Coordinate Space
-
- A world coordinate space, or world space, is where all Presentation
- Manager drawing operations begin. Whenever you draw with one of the line,
- arc, character, area, or image primitives, the coordinates that you
- specify are world coordinates. World-coordinate units can be inches,
- fractions of an inch, meters, centimeters, miles, kilometers, yards, and
- so on.
-
- If your application uses the retained-drawing mode to store subpictures in
- chained segments, MS OS/2 assigns a new world space to each segment. In
- other words, if the segment attribute is set to ATTR_CHAINED and you call
- the GpiOpenSegment function, the subpicture associated with that segment
- is drawn in a new world space. The following illustration shows the
- subpictures in four chained segments. Each subpicture is drawn in its own
- world space.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.7 can be found in Section 31.2.4 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.7 Subpictures in Four Chained Segments in World Space
-
- There is a special clipping area called a clip path that you can use to
- define a part of a world space that you want to copy into the next
- coordinate space (the model space). The advantage of a clip path is that
- it is the only clipping region that can be nonrectangular. Its edges can
- include arcs, curves, and straight lines. The coordinates that define the
- dimensions and shape of a clip path are always world coordinates. You can
- create a clip path by calling the GpiBeginPath, GpiEndPath, and
- GpiSetClipPath functions and one or more Gpi primitives that define the
- dimensions and location of the path. For more information, see Chapter
- 40, "Clipping."
-
- 31.2.5 Model Coordinate Space
-
- A model coordinate space, or model space, is where you build a model, or a
- complete picture, from subpictures in one or more world spaces. You can
- have more than one model space, each corresponding to a particular model.
- Figure 31.8 shows two model spaces that were defined by calls to the
- GpiSetSegmentTransformMatrix function:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.8 can be found in Section 31.2.5 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.8 Two Model Spaces
-
- There is a special clipping area called a viewing limit that you can use
- to define a part of a model space that you want to copy into the next
- coordinate space (the page space). A viewing limit is always rectangular,
- and the coordinates that define its location and dimensions are always
- model coordinates. You can set the viewing limit by calling the
- GpiSetViewingLimit function. Figure 31.9 shows a viewing limit set in a
- model space; the dashed line represents the viewing-limit border:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.9 can be found in Section 31.2.5 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.9 Viewing Limit in Model Space
-
- 31.2.5.1 World-to-Model-Space Transformations
-
- There are three transformations that operate between the world space and
- the model space:
-
- ■ The model transformation
-
- ■ The segment transformation
-
- ■ The instance transformation
-
- Model Transformations
-
- Model transformations are used for retained- or nonretained-drawing
- operations. This means model transformations affect the output from the
- GpiDrawChain, GpiDrawFrom, and GpiDrawSegment functions and any of the Gpi
- functions that occur outside of a retained-drawing segment.
-
- You can determine the values for the current model transformation by
- calling the GpiQueryModelTransformMatrix function, which returns the model
- transformation's scaling, rotation, and translation values in a
- three-by-three matrix. Similarly, you can set these values by calling the
- GpiSetModelTransformMatrix function, passing it the scaling, rotation, and
- translation values in a three-by-three matrix.
-
- In a retained-graphics application, you could use a model transformation
- to rotate, scale, or translate parts of a subpicture. You can set and
- reset the model transformation any number of times within a
- retained-drawing segment. Figure 31.10 shows part of a floor plan as a
- single subpicture stored in a retained segment. Each chair was drawn by
- setting a new translation component in the model transformation before
- calling the GpiBox function.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.10 can be found in Section 31.2.5.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.10 Retained Subpicture Drawn Using Model Transformations
-
- Segment Transformations
-
- Segment transformations alter retained-drawing output. Unlike a model
- transformation, which can be set and reset within a segment bracket, a
- segment transformation must be set outside of a segment bracket.
-
- You can determine the values for the current segment transformation by
- calling the GpiQuerySegmentTransformMatrix function, which returns the
- scaling, rotation, and translation values in a three-by-three matrix and
- passes a segment identifier. Similarly, you can set the values for the
- segment transformation by calling the GpiSetSegmentTransformMatrix
- function, passing it the necessary values (in a three-by-three matrix) and
- a segment identifier.
-
- The user of a CAD or drafting application may need to zoom in on part of a
- subpicture that was clipped in world space by a clip path. The application
- could perform this operation by setting the segment transformation for
- that particular subpicture after setting the clip path. Figure 31.11
- shows a subpicture in world space that contains a clip path; the dashed
- line represents the outline of the clip path:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.11 can be found in Section 31.2.5.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.11 Clip Path in World Space
-
- Figure 31.12 shows a zoomed view (in model space) of the clipped part of
- the subpicture:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.12 can be found in Section 31.2.5.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.12 Scaling the Clipped Part of a Subpicture in Model Space
-
- Instance Transformations
-
- Instance transformations alter the retained-drawing output from special
- segments referred to as "called" segments. A called segment usually
- contains a subpicture that is duplicated several times in other
- subpictures. The instance transformation positions, sizes, and rotates the
- subpicture each time it is duplicated. You can set the values for the
- instance transformation by calling the GpiCallSegmentMatrix function,
- passing it the transformation values (in a three-by-three matrix) and a
- segment identifier.
-
- 31.2.6 Page Coordinate Space
-
- A page coordinate space, or page space, is where a complete picture is
- prepared for viewing in a window on a video display, printing on a page of
- printer paper, or plotting on a page of plotter paper. Page-coordinate
- units can be increments of an inch, a meter, several pels, a twip, or some
- arbitrary value. (A twip is a standard unit in the typesetting industry
- that measures 1/1440 of an inch.) You specify the units used for page
- coordinates when you call the GpiCreatePS function and create a
- presentation space.
-
- If your application uses retained-drawing mode, the picture in page space
- will contain parts of models (or pictures) from each of the model spaces
- that have not been clipped; the picture will also contain any additional
- graphics-primitive output (that has not been clipped) that the application
- generated in nonretained-drawing mode. If your application uses
- nonretained-drawing mode, the picture in page space will contain all of
- the graphics-primitive output that has not been clipped.
-
- In the page space, there is a special clipping area called a graphics
- field that you can use to define the part of the page space that you want
- to copy into the next coordinate space (the device space). The graphics
- field is always rectangular. The coordinates that define the location and
- dimensions of the graphics field are always page coordinates.
-
- 31.2.6.1 Model-to-Page-Space Transformations
-
- There are two transformations that operate between the model space and the
- page space:
-
- ■ The default viewing transformation
-
- ■ The viewing transformation
-
- Default Viewing Transformations
-
- Default viewing transformations scroll or zoom pictures in a window on a
- video display or on a page of printer or plotter paper. You can determine
- the current values for the default viewing transformation by calling the
- GpiQueryDefaultViewMatrix function, which returns the
- default-viewing-transformation values in a three-by-three matrix. You can
- set these values by calling the GpiSetDefaultViewMatrix function and
- passing it the transformation values (in a three-by-three matrix).
-
- Viewing Transformations
-
- Viewing transformations create pictures from multiple model spaces. For
- example, you could copy a picture from a model space to a page space,
- leaving all parts of the picture intact. Then you could copy a part of
- another picture from a second model space by using a viewing limit to
- define the part of the picture that you want to copy and then using the
- viewing transformation to scale and translate that part. You can determine
- the current values for the viewing transformation by calling the
- GpiQueryViewingTransformMatrix function, which returns the values for the
- viewing transformation in a three-by-three matrix. You can set the values
- by calling the GpiSetViewingTransformMatrix function and passing it the
- transformation values (in a three-by-three matrix).
-
- 31.2.7 Device Coordinate Space
-
- A device coordinate space, or device space, is the final space in which a
- picture is drawn before it appears in a window or on the page of a printer
- or plotter. Device-coordinate units are pels if the page units are pels,
- twips, increments of an inch, or increments of a meter. Device-coordinate
- units are arbitrary if the page units are arbitrary.
-
- 31.2.7.1 Page-to-Device-Space Transformations
-
- There is one transformation between the page space and the device
- space──it is called the device transformation. Unlike the other
- transformations that rotate, scale, and translate objects, the device
- transformation only scales and translates objects; also, instead of a
- three-by-three matrix, the device transformation uses two rectangles. (The
- location of the first rectangle is fixed; the location of the second
- rectangle is movable.) These two rectangles are the presentation page and
- the page viewport.
-
- Presentation Pages
-
- A presentation page is a rectangle in a page space. Its lower-left corner
- is always positioned at the origin of the page space. You can determine
- the dimensions of the presentation page by calling the GpiQueryPS
- function, which returns a pointer to a SIZEL structure that contains the
- page dimensions. If you specify arbitrary page units when you create a
- presentation space, you must also specify the dimensions of the
- presentation page. If you specify any other page unit, MS OS/2
- automatically sets the dimensions of the presentation page for you. Figure
- 31.13 shows a presentation page:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.13 can be found in Section 31.2.7.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.13 Presentation Page in Page Space
-
- Page Viewports
-
- A page viewport is a rectangle in a device space. MS OS/2 always copies
- the presentation-page rectangle into the page-viewport rectangle. You can
- determine the current dimensions of the page viewport by calling the
- GpiQueryPageViewport function, which returns a pointer to a RECTL
- structure that contains the coordinates of the viewport. You can set the
- location and dimensions of the page viewport by calling the
- GpiSetPageViewport function and passing it a pointer to a RECTL structure
- that contains the new values. Figure 31.14 shows the object from Figure
- 31.13 as it would appear in the page viewport:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.14 can be found in Section 31.2.7.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.14 Page Viewport in Device Space
-
- The ratio of the page width to the page-viewport width defines a
- horizontal scaling factor, and the ratio of the page height to the
- viewport height defines a vertical scaling factor. In Figure 31.15, the
- presentation page measures 100 centimeters by 200 centimeters, and the
- page viewport measures 200 pels by 400 pels (where each pel measures 0.25
- centimeters by 0.5 centimeters):
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.15 can be found in Section 31.2.7.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.15 Determining Scaling Factors
-
- The image in the page space was not scaled in the device space since each
- centimeter in the page space mapped to a centimeter in the device space.
-
- Figure 31.16 shows the effect of shifting the page viewport in the device
- space. Note the translation that this shift causes.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 31.16 can be found in Section 31.2.7.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 31.16 Translating the Page Viewport in Device Space
-
-
- 31.3 Using Coordinate Spaces and Transformations
-
- You can perform the following tasks by using the coordinate-space and
- transformation functions:
-
- ■ Set an application's drawing units to convenient units.
-
- ■ Scroll and zoom a picture.
-
- ■ Rotate, scale, and shift an object in a picture.
-
- 31.3.1 Setting Convenient Drawing Units
-
- You can use the GpiCreatePS function to set the device transformation so
- that it uses more convenient page units──for example, centimeters. Follow
- these steps:
-
- 1. If the output device is a screen, open a device context by calling the
- WinOpenWindowDC function. (If the output device is a printer or
- plotter, open a printer or plotter device context by calling the
- DevOpenDC function.)
-
- 2. Create a presentation space by calling the GpiCreatePS function,
- specifying low-metric page units and associating the device context
- with the presentation space.
-
- The following code fragment demonstrates these steps:
-
- HDC hdc; /* device-context handle */
- HWND hwndClient; /* client-window handle */
- SIZEL sizlPage; /* presentation-page rectangle */
- HAB hab; /* anchor-block handle */
- HPS hps; /* presentation-space handle */
- .
- .
- .
- hdc = WinOpenWindowDC(hwndClient);
- sizlPage.cx = 0;
- sizlPage.cy = 0;
- hps = GpiCreatePS(hab,
- hdc, /* device-context handle */
- &sizlPage, /* address of SIZEL structure */
- PU_LOMETRIC /* centimeters as page units */
- | GPIA_ASSOC); /* associates window DC with PS */
-
- 31.3.2 Zooming a Picture
-
- You can use the GpiSetDefaultViewMatrix function to zoom a picture. The
- following code fragment shows how to zoom out to 1/4 or 1/8 scale by using
- the default viewing transformation:
-
- /* Zoom 1/8 */
-
- matlfTransform.fxM11 = MAKEFIXED(0, 8192);
- matlfTransform.fxM12 = MAKEFIXED(0, 0);
- matlfTransform.lM13 = 0L;
- matlfTransform.fxM21 = MAKEFIXED(0, 0);
- matlfTransform.fxM22 = MAKEFIXED(0, 8192);
- matlfTransform.lM23 = 0L;
- matlfTransform.lM31 = 0L;
- matlfTransform.lM32 = 0L;
- matlfTransform.lM33 = 1L;
- GpiSetDefaultViewMatrix(hps, 9L, &matlfTransform, TRANSFORM_REPLACE);
- /* Zoom 1/4 */
-
- matlfTransform.fxM11 = MAKEFIXED(0, 1634);
- matlfTransform.fxM12 = MAKEFIXED(0, 0);
- matlfTransform.lM13 = 0L;
- matlfTransform.fxM21 = MAKEFIXED(0, 0);
- matlfTransform.fxM22 = MAKEFIXED(0, 1634);
- matlfTransform.lM23 = 0L;
- matlfTransform.lM31 = 0L;
- matlfTransform.lM32 = 0L;
- matlfTransform.lM33 = 1L;
- GpiSetDefaultViewMatrix(hps, 9L, &matlfTransform, TRANSFORM_REPLACE);
-
- 31.3.3 Rotating an Object in a Picture
-
- To rotate an object in a world space by using the model transformation,
- you must perform the following steps:
-
- 1. Translate the object over the coordinate-space origin.
-
- 2. Rotate the object.
-
- 3. Translate the object back to its original position.
-
- 4. Draw the object.
-
- The following code fragment rotates a box 45 degrees:
-
- /* translates, rotates 45 degrees, translates */
-
- matlfTransform.fxM11 = MAKEFIXED(1, 0);
- matlfTransform.fxM12 = MAKEFIXED(0, 0);
- matlfTransform.lM13 = 0L;
- matlfTransform.fxM21 = MAKEFIXED(0, 0);
- matlfTransform.fxM22 = MAKEFIXED(1, 0);
- matlfTransform.lM23 = 0L;
- matlfTransform.lM31 = -150L; /* translates box 150 units left */
- matlfTransform.lM32 = -150L; /* translates box 150 units down */
- matlfTransform.lM33 = 1L;
- GpiSetModelTransformMatrix(hps, 9L, &matlfTransform,
- TRANSFORM_REPLACE);
-
- matlfTransform.fxM11 = MAKEFIXED(0, 46340); /* cos 45 * 65536 */
- matlfTransform.fxM12 = -MAKEFIXED(0, 46340); /* -sin 45 * 65536 */
- matlfTransform.lM13 = 0L;
- matlfTransform.fxM21 = MAKEFIXED(0, 46350); /* sin 45 * 65536 */
- matlfTransform.fxM22 = MAKEFIXED(0, 46340); /* cos 45 * 65536 */
- matlfTransform.lM23 = 0L;
- matlfTransform.lM31 = 0L;
- matlfTransform.lM32 = 0L;
- matlfTransform.lM33 = 1L;
- GpiSetModelTransformMatrix(hps, 9L, &matlfTransform, TRANSFORM_ADD);
-
- matlfTransform.fxM11 = MAKEFIXED(1, 0);
- matlfTransform.fxM12 = MAKEFIXED(0, 0);
- matlfTransform.lM13 = 0L;
- matlfTransform.fxM21 = MAKEFIXED(0, 0);
- matlfTransform.fxM22 = MAKEFIXED(1, 0);
- matlfTransform.lM23 = 0L;
- matlfTransform.lM31 = 150L; /* shifts back to original pos. */
- matlfTransform.lM32 = 150L; /* shifts back to original pos. */
- matlfTransform.lM33 = 1L;
- GpiSetModelTransformMatrix(hps, 9L, &matlfTransform, TRANSFORM_ADD);
-
-
- 31.4 Summary
-
- The following list summarizes the coordinate-space and transformation
- functions:
-
- GpiConvert Determines the relationship between coordinates in two
- coordinate systems when a transformation is in effect. For example, if the
- page units are low English (0.01 inches) and an application is drawing in
- world units of feet, the application can call GpiConvert to determine the
- ratio of world units to page units and use this value to scale a picture
- down before printing.
-
- GpiQueryDefaultViewMatrix Retrieves the scaling, rotation, and
- translation values for the default viewing transformation. You can use the
- default viewing transformation to scroll and zoom a picture in a page
- space.
-
- GpiQueryModelTransformMatrix Retrieves the scaling, rotation, and
- translation values for the model transformation. You can use the model
- transformation to alter retained subpictures and nonretained pictures in a
- world space.
-
- GpiQueryPageViewport Retrieves the dimensions of the page viewport. You
- can use the page viewport to shrink and expand pictures so that they fill
- the client area of a window as it shrinks and expands.
-
- GpiQuerySegmentTransformMatrix Retrieves the scaling, rotation, and
- translation values for the segment transformation. You can use the segment
- transformation to alter subpictures stored in retained segments in a world
- space.
-
- GpiQueryViewingTransformMatrix Retrieves the scaling, rotation, and
- translation values for the viewing transformation. You can use the viewing
- transformation with the viewing-limit clipping region to transform part of
- a picture in a model space and then copy it to a page space. You can also
- use the viewing transformation to transform a complete picture in a model
- space before copying it to a page space.
-
- GpiSetDefaultViewMatrix Sets the scaling, rotation, and translation
- values for the default viewing transformation. You can use the default
- viewing transformation to scroll and zoom a picture in a page space.
-
- GpiSetModelTransformMatrix Sets the scaling, rotation, and translation
- values for the model transformation. You can use the model transformation
- to alter retained subpictures and nonretained pictures in a world space.
-
- GpiSetPageViewport Sets the dimensions of the page viewport. You can use
- the page viewport to shrink and expand pictures so that they fill the
- client area of a window as it shrinks and expands.
-
- GpiSetSegmentTransformMatrix Sets the scaling, rotation, and translation
- values for the segment transformation. You can use the segment
- transformation to alter subpictures stored in retained segments in a world
- space.
-
- GpiSetViewingTransformMatrix Sets the scaling, rotation, and translation
- values for the viewing transformation. You can use the viewing
- transformation and the viewing-limit clipping region to transform part of
- a picture in a model space and then copy it to a page space. You can also
- use the viewing transformation to transform a complete picture in a model
- space before copying it to a page space.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 32 Line and Arc Primitives
-
- 32.1 Introduction
- 32.2 About Line and Arc Primitives
- 32.2.1 Drawing Straight Lines
- 32.2.2 Drawing Arcs
- 32.2.3 Arc Parameters
- 32.2.4 Line Attributes
- 32.3 Using Line and Arc Primitives
- 32.3.1 Drawing a Straight Line
- 32.3.2 Creating a Rubber-Banding Effect with a Straight Line
- 32.3.3 Drawing a Circle
- 32.3.4 Drawing an Ellipse
- 32.3.5 Drawing a Fillet
- 32.3.6 Drawing a Spline
- 32.4 Summary
-
- 32.1 Introduction
-
- This chapter describes the line and arc primitives. You should also be
- familiar with the following topics:
-
- ■ Presentation spaces and device contexts
-
- ■ Coordinate spaces and transformations
-
- ■ Color and mix modes
-
-
- 32.2 About Line and Arc Primitives
-
- Line and arc primitives are straight lines and arcs, respectively, that
- are drawn by line and arc functions. These primitives are useful for
- creating pictures that consist of objects such as polygons, circles,
- fillets, ellipses, and other geometric figures.
-
- Line and arc primitives are useful in many applications. Spreadsheet
- applications use them to construct pie charts, bar charts, and graphs.
- Simple drawing applications use them as drawing tools.
- Computer-aided-design (CAD) applications combine them to draw such complex
- pictures as schematic diagrams for electrical wiring, blueprints for a
- building site, and cross-sectional views of machinery. This broad range of
- pictures, from simple pie charts to complex blueprints, demonstrates how
- these primitives can benefit your applications. Figure 32.1 shows some
- sample illustrations that were drawn using line and arc functions:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 32.1 can be found in Section 32.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 32.1 Sample Illustrations Using Line and Arc Functions
-
- In addition to the line and arc functions, there are numerous other
- functions that you can use to alter the appearance of lines and arcs drawn
- by the primitive functions. These "other" functions are called attribute
- functions since they alter the attributes, or characteristics, of lines
- and arcs.
-
- 32.2.1 Drawing Straight Lines
-
- You draw straight lines by calling the GpiMove function and either the
- GpiLine or GpiPolyLine function. GpiMove sets the current position to the
- starting point of a line; GpiLine draws a single line from the current
- position to a specified point; and GpiPolyLine draws a series of connected
- lines, from the current position through successive points in an array.
-
- When MS OS/2 draws a line, it includes the pels at the starting and ending
- points of the line. The algorithm used to draw the rest of the line
- depends on the device driver. For example, a driver for a raster device
- may use a modified Brezenham algorithm to draw a line, but a driver for a
- vector device, such as a plotter, simply connects the line's starting and
- ending points. In all cases, the result is a line primitive that looks the
- same from device to device.
-
- 32.2.2 Drawing Arcs
-
- You draw arcs by using GpiMove and one of the following functions:
-
- Function Description
- ──────────────────────────────────────────────────────────────────────────
- GpiFullArc Draws a circle or an ellipse.
-
- GpiPartialArc Draws a section of a circle or ellipse.
-
- GpiPointArc Draws an arc through three points.
-
- GpiPolyFillet Draws one or more fillets.
-
- GpiPolyFilletSharp Draws one or more fillets with varying degrees of
- sharpness.
-
- GpiPolySpline Draws one or more splines.
- ──────────────────────────────────────────────────────────────────────────
-
- The terms circle, ellipse, fillet, and spline are important in discussing
- arc primitives. A circle is a closed curve with a center from which every
- point on the curve is equidistant. An ellipse is a closed curve defined by
- two fixed points such that the sum of the distances from any point on the
- curve to the two fixed points is constant. A fillet is a curve that, given
- three control points, is tangent to the first and last points. A spline is
- a curve that, given four control points, is tangent to the first and last
- lines. Figure 32.2 shows a circle, an ellipse, a fillet, and a spline:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 32.2 can be found in Section 32.2.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 32.2 Arcs
-
- 32.2.3 Arc Parameters
-
- When you draw an arc or an ellipse in your application, the image that
- appears on the drawing surface reflects the current values of the arc
- parameters, p, q, r, and s. The default value of p is 1, as is the default
- value of q; the default value of r is 0, as is the default value of s.
- These parameters form a two-by-two matrix that scales and shears ellipses
- and arcs drawn by the GpiFullArc, GpiPointArc, and GpiPartialArc
- functions:
-
- ┌ ┐
- │ p=1 r=0 │
- │ │
- │ s=0 q=1 │
- └ ┘
-
-
- The parameters p and q are scaling values: p scales in the x-direction; q
- scales in the y-direction. The parameters r and s are shear components.
- When you alter r and s, a sheared ellipse or arc results. Figure 32.3
- shows four ellipses drawn by the GpiMove and GpiFullArc functions. In each
- case, one of the default arc parameters has been changed to scale or shear
- the ellipse.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 32.3 can be found in Section 32.2.3 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 32.3 Transforming the Unit Circle Using the Arc Parameters
-
- All of the arc operations begin with a unit circle that lies at the origin
- in the world coordinate system. The arc parameters define a transformation
- that is applied to each point on the perimeter of the unit circle. For any
- point (x,y) on the perimeter of the unit circle, there exists a new point
- (x',y'), as determined by the following two algorithms:
-
- x' = p x x + r x y
- y' = s x x + q x y
-
-
- If the addition of (p x r) and (s x q) is zero, the transformation is
- orthogonal, and the line from the origin (0,0) to the point (p,s) is
- either the radius of a circle or half of the major or minor axis of an
- ellipse. The line from the origin to the point (r,q) is either the radius
- of a circle or half of the minor or major axis of an ellipse.
-
- Additional scaling transformations in your application can change the
- shape of the figure accordingly. For instance, if the page units in your
- application are PU_PELS and the pels on your device are rectangular
- (rather than square), MS OS/2 will draw an ellipse (rather than a circle)
- with GpiFullArc when the arc parameters are set to their default values.
-
- If (p x q) is greater than (r x s), MS OS/2 draws the ellipse
- counterclockwise for the GpiFullArc and GpiPartialArc functions. If (p x
- q) is less than (r x s), MS OS/2 draws the ellipse clockwise, and if (p x
- q) is equal to (r x s), MS OS/2 draws a straight line rather than an
- ellipse.
-
- You can determine the current arc parameters by calling the
- GpiQueryArcParams function, which copies the current arc parameters to
- their corresponding fields in the ARCPARAMS structure. You can set the arc
- parameters by calling GpiSetArcParams and passing it a copy of the
- ARCPARAMS structure that contains the new arc parameters you want to use.
- The ARCPARAMS structure has the following form:
-
- typedef struct _ARCPARAMS { /* arcp */
- LONG lP;
- LONG lQ;
- LONG lR;
- LONG lS;
- } ARCPARAMS;
-
- 32.2.4 Line Attributes
-
- Every line and arc has style, width, and color characteristics. These
- characteristics are called line attributes. The first line attribute, line
- style, defines the way the line is drawn: solid, as a series of dashes, as
- a series of dots, or as a combination of dashes and dots. Figure 32.4
- shows the various line styles:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 32.4 can be found in Section 32.2.4 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 32.4 Line Styles
-
- The second line attribute, line width, defines the width of the line in
- pels. The third line attribute, line color, defines the color used to draw
- the line. Usually, this color is mixed with colors already on the drawing
- surface. This means that the final color of a line or curve depends not
- only on the line color but on the mix mode and the color of the drawing
- surface as well. If you draw a dotted or dashed line, the color that
- appears between the dots or dashes is the current drawing-surface color.
- The mix mode tells MS OS/2 how to combine the line and background colors
- (using a bitwise operation on the bits in the corresponding RGB values).
- For example, one mix mode combines the bits by using the bitwise OR
- operator. The resulting line has both the line and background colors.
- Using this mix mode, you would make a purple line when the line color is
- red and the background color is blue. For more information about color and
- mix-mode attributes, see Chapter 34, "Color and Mix Modes."
-
- When you create a normal presentation space, the line attributes are set
- to the following default values:
-
- Line attribute Default value
- ──────────────────────────────────────────────────────────────────────────
- Line style LINETYPE_SOLID
-
- Line color CLR_NEUTRAL
-
- Line width 1.0
-
- Mix mode FM_OVERPAINT
- ──────────────────────────────────────────────────────────────────────────
-
- You can retrieve the current line-attribute values by calling the
- GpiQueryAttrs function. This function copies the current line attributes
- to a LINEBUNDLE structure. You can change the values at any time by
- calling the GpiSetAttrs function. To make changes, you retrieve the
- current line attributes, set the appropriate fields in the LINEBUNDLE
- structure to new values, and pass the structure to GpiSetAttrs. The
- LINEBUNDLE structure has the following form:
-
- typedef struct _LINEBUNDLE { /* lbnd */
- LONG lColor; /* line color */
- LONG lReserved;
- USHORT usMixMode; /* mix mode */
- USHORT usReserved;
- FIXED fxWidth; /* line width */
- LONG lGeomWidth; /* used with path functions */
- USHORT usType; /* line style */
- USHORT usEnd; /* used with path functions */
- USHORT usJoin; /* used with path functions */
- } LINEBUNDLE;
-
- Several of the fields in this structure apply to a special wide line that
- you can construct using the path functions. For more information about
- paths and wide lines, see Chapter 35, "Paths."
-
-
- 32.3 Using Line and Arc Primitives
-
- You can use the line and the arc functions to perform the following tasks:
-
- ■ Draw a straight line.
-
- ■ Create a "rubber-banding" effect with straight lines or arcs.
-
- ■ Draw a circle, ellipse, fillet, or spline.
-
- 32.3.1 Drawing a Straight Line
-
- To draw a straight line, you must first set the current position by
- calling the GpiMove or GpiSetCurrentPosition function, then draw the line
- by calling the GpiLine function. The following code fragment shows how to
- draw straight lines:
-
- LONG DrawLine(hps, pptlStart, pptlEnd)
- HPS hps; /* presentation-space handle */
- PPOINTL pptlStart; /* pointer to coordinates of line start */
- PPOINTL pptlEnd; /* pointer to coordinates of line end */
- {
- POINTL ptl_start, ptl_end; /* point structures */
-
- ptl_start.x = pptlStart->x; /* loads starting x-coordinate */
- ptl_start.y = pptlStart->y; /* loads starting y-coordinate */
- ptl_end.x = pptlEnd->x; /* loads ending x-coordinate */
- ptl_end.y = pptlEnd->y; /* loads ending y-coordinate */
- GpiMove(hps, &ptl_start); /* sets current position */
- if (GpiLine(hps, &ptl_end)) /* draws line */
- return (1L);
- else
- return (0L);
- }
-
- The second argument to the GpiMove function is the address of a structure
- that contains coordinates of the line's starting point; the second
- argument to the GpiLine function is the address of a structure that
- contains the coordinates of the last point on the line.
-
- 32.3.2 Creating a Rubber-Banding Effect with a Straight Line
-
- When lines are drawn with a rubber-banding effect, two things happen: The
- original line (if one exists) is erased, and a new line is drawn in its
- place. This process takes place each time the mouse is dragged and
- continues until the mouse button is released. The quickest way to erase
- the original line is to set the foreground mix mode to FM_XOR and redraw
- the line. The following code fragment demonstrates how you can create this
- effect:
-
- HPS hps; /* presentation-space handle */
- POINTL ptlStart; /* starting point of line */
- POINTL ptlNew; /* ending point of line */
- POINTL ptlPrev; /* previous end point of line */
- BOOL fDraw; /* line-drawing flag */
- .
- .
- .
- GpiSetColor(hps, CLR_GREEN); /* sets line-drawing color to green */
- .
- .
- .
- MRESULT FAR PASCAL GenericWndProc(hwnd, usMessage, mp1, mp2)
- HWND hwnd;
- USHORT usMessage;
- MPARAM mp1;
- MPARAM mp2;
- {
- .
- .
- .
- case WM_BUTTON1DOWN: /* user begins drawing */
- ptlStart.x = (LONG) (LOUSHORT(mp1));
- ptlStart.y = (LONG) (HIUSHORT(mp1));
- GpiConvert(hps, CVTC_DEVICE, CVTC_WORLD, 1L, &ptlStart);
- ptlPrev.x = ptlStart.x;
- ptlPrev.y = ptlStart.y;
- GpiMove (hps, &ptlStart);
- fDraw = TRUE;
- return TRUE;
-
- case WM_MOUSEMOVE: /* user draws line */
- if (fDraw) {
- ptlNew.x = (LONG) (LOUSHORT(mp1));
- ptlNew.y = (LONG) (HIUSHORT(mp1));
- GpiConvert(hps, CVTC_DEVICE, CVTC_WORLD, 1L, &ptlNew);
- GpiSetMix(hps, FM_XOR);
- if ((ptlStart.x != ptlPrev.x) || (ptlStart.y != ptlPrev.y)) {
- GpiMove(hps, &ptlStart);
- GpiLine(hps, &ptlPrev);
- }
- if ((ptlStart.x != ptlNew.x) || (ptlStart.y != ptlNew.y)) {
- GpiMove(hps, &ptlStart);
- GpiLine(hps, &ptlNew);
- ptlPrev.x = ptlNew.x; ptlPrev.y = ptlNew.y;
- }
- GpiSetMix(hps, FM_OVERPAINT);
- return TRUE;
- }
-
- case WM_BUTTON1UP: /* user stops drawing */
- fDraw = FALSE;
- return TRUE;
- .
- .
- .
- }
-
- 32.3.3 Drawing a Circle
-
- To draw a circle, all of the transformations between the world, model,
- page, and device spaces must maintain square units. This means that
- instead of pels for page units, the application should select metric or
- English page units. (On most devices, a pel is rectangular, not square.)
- This also means that the x-values and y-values for any scaling
- transformations should be equal. If the transformations maintain square
- units, the default arc parameters will transform an ellipse drawn by the
- GpiFullArc function into a circle.
-
- If the page units are Low English and the default transformations are set,
- the following code fragment draws a circle with a diameter of 1 inch:
-
- ARCPARAMS arcp; /* structure for arc parameters */
- HPS hps; /* presentation-space handle */
- POINTL ptlPos; /* structure for current position */
- FIXED fxMult; /* multiplier for circle */
- .
- .
- .
- arcp.lP = 1L; arcp.lQ = 1L;
- arcp.lR = 0L; arcp.lS = 0L;
- GpiSetArcParams(hps,
- &arcp); /* sets parameters to default */
- ptlPos.x = 100; /* loads x-coordinate */
- ptlPos.y = 100; /* loads y-coordinate */
- GpiMove(hps, &ptlPos); /* sets current position */
- fxMult = (50 * 65536); /* sets multiplier */
- GpiFullArc(hps, DRO_OUTLINE, /* draws circle */
- fxMult);
-
- The second argument to the GpiFullArc function, DRO_OUTLINE, specifies
- that MS OS/2 should draw only the outline of the circle (rather than
- filling the interior with the current fill pattern). The third argument,
- fxMult, specifies that MS OS/2 should multiply the size of the circle by
- 50 units. Since the page units are PU_LOENGLISH and the default
- transformations are set, 50 units are equivalent to 1/2 inch. The circle
- will have a 1/2-inch radius and a 1-inch diameter.
-
- 32.3.4 Drawing an Ellipse
-
- If the world, model, page, and device transformations are set so that they
- maintain square units, you can use the arc parameters to transform the
- shape of the ellipse drawn by the GpiFullArc function. The following code
- fragment alters the arc parameter p by doubling its value, making the
- ellipse twice as wide horizontally as it is vertically.
-
- If the page units are PU_LOENGLISH and the default transformations are
- set, the following code fragment draws an ellipse with a 2-inch major axis
- (parallel to the x-axis) and a 1-inch minor axis (parallel to the y-axis).
- The ellipse is centered over a point in the lower-left corner of a
- maximized window.
-
- ARCPARAMS arcp; /* structure for arc parameters */
- HPS hps; /* presentation-space handle */
- POINTL ptlPos; /* structure for current position */
- LONG fxMult; /* multiplier for ellipse */
- .
- .
- .
- arcp.lP = 2L; arcp.lQ = 1L;
- arcp.lR = 0L; arcp.lS = 0L;
- GpiSetArcParams(hps,
- &arcp); /* sets parameters to default */
- ptlPos.x = 200; /* loads x-coordinate */
- ptlPos.y = 100; /* loads y-coordinate */
- GpiMove(hps, &ptlPos); /* sets current position */
- fxMult = (50 * 65536); /* sets multiplier */
- GpiFullArc(hps, DRO_OUTLINE, /* draws circle */
- fxMult);
- .
- .
- .
-
- The arc-parameter field lP is set to 2, and the arc-parameter field lQ is
- set to 1. From these parameters, MS OS/2 creates an ellipse with a major
- axis that is twice as long as the minor axis.
-
- 32.3.5 Drawing a Fillet
-
- When you draw a fillet, each curve is tangent to two lines. The curve of
- the first fillet is always tangent to a line drawn between the current
- position and the first control point and a line drawn between the current
- position and the second control point.
-
- The following code fragment shows how to draw a single curve by using the
- current position and two control points:
-
- POINTL aptl[2]; /* structure for control points */
- HPS hps; /* presentation-space handle */
- .
- .
- .
- aptl[0].x = 50; /* loads x-coord. of first control point */
- aptl[0].y = 50; /* loads y-coord. of first control point */
- GpiMove(hps, aptl); /* sets current position */
- aptl[0].x = 75; /* loads x-coord. of second control point */
- aptl[0].y = 75; /* loads y-coord. of second control point */
- aptl[1].x = 100; /* loads x-coord. of third control point */
- aptl[1].y = 50; /* loads y-coord. of third control point */
- GpiPolyFillet(hps, /* draws fillet */
- 2L, aptl);
- .
- .
- .
-
- When you draw a sharp fillet, the sharpness value controls the shape of
- the curve: If the value is greater than 1, a hyperbola is drawn; if the
- value is 1, a parabola is drawn; and if the value is less than 1, an
- ellipse is drawn. The following code fragment uses a sharpness value
- greater than 1, which creates a hyperbolic curve:
-
- POINTL aptl[2]; /* structure for control points */
- FIXED fxSharpness[1]; /* array with sharpness value */
- HPS hps; /* presentation-space handle */
- .
- .
- .
- aptl[0].x = 50; /* loads x-coord. of first control point */
- aptl[0].y = 50; /* loads y-coord. of first control point */
- GpiMove(hps, aptl); /* sets current position */
- aptl[0].x = 75; /* loads x-coord. of second control point */
- aptl[0].y = 75; /* loads y-coord. of second control point */
- aptl[1].x = 100; /* loads x-coord. of third control point */
- aptl[1].y = 50; /* loads y-coord. of third control point */
- fxSharpness[0] = 1; /* sets sharpness value */
- GpiPolyFilletSharp(hps, /* draws fillet */
- 2L, aptl, fxSharpness);
- .
- .
- .
-
- 32.3.6 Drawing a Spline
-
- When you use the GpiPolySpline function to draw a spline, each curve is
- tangent to the first and last lines of three intersecting lines. The
- following code fragment shows how to draw a spline:
-
- POINTL aptl[3]; /* structure for control points */
- HPS hps; /* presentation-space handle */
- .
- .
- .
- aptl[0].x = 50; /* loads x-coord. of first control point */
- aptl[0].y = 50; /* loads y-coord. of first control point */
- GpiMove(hps, aptl); /* sets current position */
- aptl[0].x = 75; /* loads x-coord. of second control point */
- aptl[0].y = 75; /* loads y-coord. of second control point */
- aptl[1].x = 100; /* loads x-coord. of third control point */
- aptl[1].y = 75; /* loads y-coord. of third control point */
- aptl[2].x = 125; /* loads x-coord. of fourth control point */
- aptl[2].y = 50; /* loads y-coord. of fourth control point */
- GpiPolySpline(hps, /* draws spline */
- 3L, aptl);
- .
- .
- .
-
-
- 32.4 Summary
-
- The following list summarizes the MS OS/2 line and arc functions:
-
- GpiFullArc Draws an ellipse by translating the ellipse generated by the
- arc parameters to the current position and scaling that ellipse with a
- specified multiplier. If the arc parameters are set to their default
- values and the page units are LOENGLISH, HIENGLISH, LOMETRIC, or HIMETRIC,
- the function draws a circle. Depending on the control argument, this
- function will fill the ellipse with the current fill pattern, draw the
- ellipse's outline only, or fill and draw the outline.
-
- GpiLine Draws a straight line from the current position to a specified
- end point.
-
- GpiMove Sets the current position. MS OS/2 does not save the old position
- (as it does for GpiSetCurrentPosition) if the attribute mode is
- AM_PRESERVE.
-
- GpiPartialArc Draws a straight line from the current position to the
- starting point of an arc and then draws the arc itself, using the current
- arc parameters, a sweep angle, and a multiplier. The arc parameters
- determine the shape of the arc and the direction in which it is drawn; the
- sweep angle and multiplier determine the length of the arc.
-
- GpiPointArc Draws an arc through three points. The first point is the
- current position; the last two points are control points passed as
- arguments to the function. The function uses the current arc parameters to
- determine the size and shape of the arc.
-
- GpiPolyFillet Draws a fillet. A fillet is a special curve that does not
- fit the circumference of an ellipse. (All of the other curves drawn by the
- various arc functions fit onto the circumference of an ellipse generated
- by the arc parameters.) A minimum of three control points defines a
- fillet.
-
- GpiPolyFilletSharp Draws a special fillet, using an array of sharpness
- values that correspond to each curve in the fillet. Sharpness values less
- than zero generate curves resembling hyperbolas; values of zero generate
- straight lines; and values greater than zero generate curves resembling
- parts of ellipses.
-
- GpiPolyLine Draws a series of straight lines starting at the current
- position. The attributes in the current line structure determine the style
- and color of lines.
-
- GpiPolySpline Draws a spline. A spline consists of one or more special
- curves called Bezier curves. A minimum of four control points defines a
- spline.
-
- GpiQueryArcParams Retrieves a pointer to a structure that contains the
- current arc parameters. MS OS/2 uses the arc parameters when it draws an
- arc using the GpiFullArc, GpiPointArc, and GpiPartialArc functions.
-
- GpiQueryCurrentPosition Retrieves a pointer to a structure that contains
- the x- and y-coordinates of the current position.
-
- GpiQueryLineType Retrieves the current line type, which can be one of
- nine possible values.
-
- GpiQueryLineWidth Retrieves the current line width. Currently in MS OS/2,
- this value should always be 65,536 decimal (0x1000 hexadecimal).
-
- GpiSetArcParams Sets the parameters of the arc. These parameters
- determine the shape of an ellipse and the direction in which MS OS/2 draws
- it. There are four arc parameters──p, s, r, and q──represented by four
- fields in the ARCPARAMS structure.
-
- GpiSetCurrentPosition Sets the current position to a point specified by
- an x- and a y-coordinate. MS OS/2 uses the current position when it draws
- lines, arcs, fillets, and splines.
-
- GpiSetLineType Sets the current line type, which can be one of nine
- possible values.
-
- GpiSetLineWidth Sets the current line width. Currently in MS OS/2, this
- value should always be 65,536 decimal (0x1000 hexadecimal).
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 33 Fonts and Character Primitives
-
- 33.1 Introduction
- 33.2 About Fonts and Character Primitives
- 33.2.1 Font Metrics
- 33.2.2 Image and Outline Fonts
- 33.2.3 Proportional and Fixed Fonts
- 33.2.4 Glyphs, Code Pages, and Code Points
- 33.2.5 Text Output
- 33.2.5.1 Text and Character Attributes
- 33.2.5.2 Character Modes
- 33.2.6 Font Files and Dynamic-Link Libraries
- 33.2.7 Selecting New Fonts
- 33.2.7.1 Public Fonts
- 33.2.7.2 Private Fonts
- 33.3 Using Fonts and Character Primitives
- 33.3.1 Selecting a Public Font
- 33.3.2 Drawing Text
- 33.3.3 Transforming Text from an Outline Font
- 33.3.4 Transforming Text from an Image Font
- 33.4 Summary
-
- 33.1 Introduction
-
- This chapter defines typographic terms and concepts that are part of the
- MS OS/2 application programming interface (API). You should also be
- familiar with the following topics:
-
- ■ Presentation spaces and device contexts
-
- ■ Coordinate spaces and transformations
-
- ■ Color and mix modes
-
-
- 33.2 About Fonts and Character Primitives
-
- A font family is a collection of fonts that share common stroke-width and
- serif characteristics. The term stroke width refers to the width of lines
- used to draw characters and symbols from a font. Figure 33.1 shows a
- lowercase letter f that consists of two strokes: a stem (the main vertical
- stroke) and a cross-stroke:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.1 can be found in Section 33.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.1 Strokes
-
- A serif is a short cross-line drawn at the ends of main strokes that form
- a character or symbol. Figure 33.2 shows serifs drawn at the ends of the
- strokes in the uppercase letters A and L:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.2 can be found in Section 33.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.2 Serifs
-
- A font, part of a font family, is a collection of characters and symbols
- that share a common height, line weight, and appearance. The height of a
- font is specified in printer's points, or points, a point being a
- typographic unit of measurement equal to 1/72 of an inch. The five
- categories of line weight and appearance are as follows:
-
- ■ Normal
-
- ■ Bold
-
- ■ Condensed
-
- ■ Expanded
-
- ■ Italic
-
- Characters from a bold font are drawn with a heavier line weight. A
- 16-point Times Roman Bold is an example of a bold font, as shown in Figure
- 33.3:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.3 can be found in Section 33.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.3 Bold Font
-
- Characters from an italic font are drawn with a normal line weight and
- slanted up and to the right. A 10-point Courier Italic is an example of an
- italic font, as shown in Figure 33.4:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.4 can be found in Section 33.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.4 Italic Font
-
- Characters from a normal font are drawn with a normal line weight. An
- 8-point Helvetica is an example of a normal font, as shown in Figure
- 33.5:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.5 can be found in Section 33.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.5 Normal Font
-
- 33.2.1 Font Metrics
-
- Every character in a font is drawn within a rectangular region called a
- character cell. Through the lower half of the character cell is drawn an
- imaginary horizontal line called the baseline. All uppercase letters and
- most lowercase letters in a given font rest on the baseline. Some
- lowercase letters, such as g or y, descend below the baseline. MS OS/2
- uses the baseline to position characters. When an application draws a
- string of text, MS OS/2 positions the leftmost point of the baseline over
- a predetermined point for each character in the string. The distance from
- the bottom of the character cell to its top is the character-cell height,
- and the distance from the baseline to the top of the character cell is the
- character-cell ascent. Similarly, the character-cell descent is the
- distance from the baseline to the bottom of the character cell, and the
- width of the character cell is the distance from one side to the other.
- Figure 33.6 shows a character cell, its origin, baseline, height, ascent,
- descent, and width:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.6 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.6 Character Cell
-
- The average distance from the baseline to the top of any uppercase
- character is called a font's em height. This measurement was given its
- name because the height of an uppercase letter M is usually equal to the
- average height of all uppercase characters in the font. Figure 33.7 shows
- the em height:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.7 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.7 Em Height
-
- The average distance from the baseline to the top of any lowercase
- character is called a font's x height. This measurement was given its name
- because the height of a lowercase letter x is usually equal to the average
- height of all lowercase characters in the font. Figure 33.8 shows the x
- height:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.8 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.8 X Height
-
- The maximum ascender, which is the height of the tallest character in a
- font, is shown in Figure 33.9:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.9 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.9 Maximum Ascender
-
- The maximum descender, which is the depth (below the baseline) of the
- lowest character in a font, is shown in Figure 33.10:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.10 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.10 Maximum Descender
-
- The lowercase ascent, which is the height of the tallest lowercase
- character in a font, is shown in Figure 33.11:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.11 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.11 Lowercase Ascent
-
- The lowercase descent, which is the depth (below the baseline) of the
- lowest lowercase character in a font, is shown in Figure 33.12:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.12 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.12 Lowercase Descent
-
- Many fonts reserve part of the space in the top of each character cell for
- accent marks. This reserved space, called internal leading, is shown in
- Figure 33.13:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.13 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.13 Internal Leading
-
- Some fonts designate a certain amount of space to leave between rows of
- text. This space, called external leading, is not included in the
- character-cell height or ascent measurements. It is shown in Figure
- 33.14:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.14 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.14 External Leading
-
- The average character width is determined by multiplying the width of each
- lowercase letter by a predetermined factor, adding the results for each
- letter in the alphabet, and then dividing by 1000. The average character
- width is determined by the setting in the lAveCharWidth field in the
- FONTMETRICS structure. For information about FONTMETRICS, see the
- Microsoft Operating System/2 Programmer's Reference, Volume 2.
-
- The em increment, which is the width of the uppercase letter M in a font,
- is shown in Figure 33.15:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.15 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.15 Em Increment
-
- The maximum baseline extent for a font is the sum of the maximum ascender
- and the maximum descender. Figure 33.16 shows an example of a maximum
- baseline extent:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.16 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.16 Maximum Baseline Extent
-
- The character slope is an angle measured clockwise with respect to a
- vertical line. The slope of a normal font is zero; the slope of an italic
- font is nonzero. Figure 33.17 shows a character slope:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.17 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.17 Character Slope
-
- The in-line direction is an angle measured clockwise with respect to a
- horizontal line. The in-line direction for a Swiss, Helvetica, or Roman
- font is normally zero; the in-line direction for a Hebrew font is normally
- 180. Figure 33.18 shows the in-line direction for a Roman font:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.18 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.18 In-line Direction
-
- The character-rotation angle is an angle measured counterclockwise with
- respect to a horizontal line. The baselines of characters are aligned with
- a vector drawn at the angle of rotation. Figure 33.19 shows a
- character-rotation angle and a character-angle vector:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.19 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.19 Character Rotation
-
- The weight class specifies the thickness of each stroke that forms part of
- each character in a font.
-
- A superscript is a character drawn immediately above and to the right of a
- normal character in a string of text. Superscripts are identified by a
- width and a height, and by vertical and horizontal offsets. Figure 33.20
- shows a superscript:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.20 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.20 Superscript
-
- A subscript is a character drawn immediately below and to the right of a
- normal character in a string of text. Subscripts are identified by a width
- and a height, and by vertical and horizontal offsets. Figure 33.21 shows
- a subscript:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.21 can be found in Section 33.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.21 Subscript
-
- Kerning is an adjustment to space between certain characters in a font.
- Some fonts contain a kerning table, which is a table of kerning values
- specifying the amount of space that should appear between certain
- characters. You can examine the kerning information by calling the
- GpiQueryKerningPairs function. You cannot set kerning for a font, but you
- can simulate kerning for an image font, using MS OS/2 Font Editor, by
- adjusting the a-space and c-space for each character. The a-space is the
- space between the left edge of a character cell and the left edge of the
- cell's character. The c-space is the space between the right edge of a
- character cell and the right edge of its character.
-
- Most of the terms described in the previous pages have corresponding
- fields in a special structure called a FONTMETRICS structure. This
- structure has the following form:
-
- typedef struct _FONTMETRICS { /* fm */
- CHAR szFamilyname[FACESIZE];
- CHAR szFacename[FACESIZE];
- USHORT idRegistry;
- USHORT usCodePage;
- LONG lEmHeight;
- LONG lXHeight;
- LONG lMaxAscender;
- LONG lMaxDescender;
- LONG lLowerCaseAscent;
- LONG lLowerCaseDescent;
- LONG lInternalLeading;
- LONG lExternalLeading;
- LONG lAveCharWidth;
- LONG lMaxCharInc;
- LONG lEmInc;
- LONG lMaxBaselineExt;
- SHORT sCharSlope;
- SHORT sInlineDir;
- SHORT sCharRot;
- USHORT usWeightClass;
- USHORT usWidthClass;
- SHORT sXDeviceRes;
- SHORT sYDeviceRes;
- SHORT sFirstChar;
- SHORT sLastChar;
- SHORT sDefaultChar;
- SHORT sBreakChar;
- SHORT sNominalPointSize;
- SHORT sMinimumPointSize;
- SHORT sMaximumPointSize;
- USHORT fsType;
- USHORT fsDefn;
- USHORT fsSelection;
- USHORT fsCapabilities;
- LONG lSubscriptXSize;
- LONG lSubscriptYSize;
- LONG lSubscriptXOffset;
- LONG lSubscriptYOffset;
- LONG lSuperscriptXSize;
- LONG lSuperscriptYSize;
- LONG lSuperscriptXOffset;
- LONG lSuperscriptYOffset;
- LONG lUnderscoreSize;
- LONG lUnderscorePosition;
- LONG lStrikeoutSize;
- LONG lStrikeoutPosition;
- SHORT sKerningPairs;
- SHORT sReserved;
- LONG lMatch;
- } FONTMETRICS;
-
- For a complete description of each field in the FONTMETRICS structure, see
- the Microsoft Operating System/2 Programmer's Reference, Volume 2.
-
- 33.2.2 Image and Outline Fonts
-
- Characters in a font are stored either as bitmaps or as collections of
- calls to line, arc, and path functions. Fonts stored as bitmaps are image
- fonts. Fonts stored as collections of line, arc, and path calls are
- outline fonts. Figure 33.22 shows an enlarged view of a lowercase letter
- a from an image font:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.22 can be found in Section 33.2.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.22 Image Font
-
- Figure 33.23 shows an enlarged view of a lowercase letter a from an
- outline font:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.23 can be found in Section 33.2.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.23 Outline Font
-
- 33.2.3 Proportional and Fixed Fonts
-
- When text is drawn, MS OS/2 aligns each character by positioning its
- character cell next to the previous character's cell, as shown in Figure
- 33.24:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.24 can be found in Section 33.2.3 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.24 Character-Cell Alignment
-
- Some fonts adjust the width of character cells so that narrow letters like
- a lowercase l or i appear closer to adjacent characters. Fonts that adjust
- the width of character cells are called proportional fonts; fonts that do
- not are called fixed fonts. Proportional fonts are generally easier to
- read than fixed fonts. Figure 33.25 shows a line of text from a
- proportional font, followed by a line of text from a fixed font:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.25 can be found in Section 33.2.3 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.25 Proportional and Fixed Fonts
-
- 33.2.4 Glyphs, Code Pages, and Code Points
-
- The image or picture that you associate with each character or symbol in a
- font is a glyph. A set of glyphs is called a code page. Each code page
- contains 256 code points (16-bit integers), in the range 0 through 255,
- that correspond to the glyphs in that code page. MS OS/2 assigns unique
- identifiers to each of its code pages. A common code page is code page
- 437. Figure 33.26 shows the glyphs and corresponding code points for this
- code page:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.26 can be found in Section 33.2.4 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.26 Code Page 437
-
- Each code page contains four special code points: a first character, a
- last character, a default character, and a break character. The default
- character is the one that appears in text when an application specifies a
- code point that does not lie between the first and last character code
- points. The break character is the space character and often has the same
- code point as the default character.
-
- If the current font is the default system font, you can determine the
- current code page by calling the GpiQueryCp function, or you can assign a
- new code page by calling the GpiSetCp function. For more information about
- code pages, see the Microsoft Operating System/2 Programmer's Reference,
- Volume 3.
-
- 33.2.5 Text Output
-
- Text output is alphanumeric output drawn with characters and symbols from
- a font. In MS OS/2, fonts are stored either in memory or on devices.
- Applications access them through a device context associated with the
- current presentation space. When you create a presentation space by
- calling the GpiCreatePS or WinGetPS function, MS OS/2 assigns the
- presentation space a default font from one of the fonts available either
- in memory or on the associated device. You can retrieve information about
- this default font by calling the GpiQueryFontMetrics function.
-
- 33.2.5.1 Text and Character Attributes
-
- There are five character attributes that affect the appearance of your
- application's text output. These character attributes are listed as
- follows:
-
- ■ Character color
-
- ■ Character-color mix mode
-
- ■ Character angle
-
- ■ Character shear
-
- ■ Character box
-
- There are two character colors: foreground and background. The foreground
- color is the color of the strokes in each character. The background color
- is the color that appears behind the character.
-
- There are two character mix modes that affect how MS OS/2 combines the
- character colors with the existing color(s) on your application's drawing
- surface. The foreground character mix mode is overpaint; the background
- character mix mode is leave-alone. If the default colors and mix modes do
- not suit your application, you can change them by calling the GpiSetAttrs
- function. You can determine the current color and mix-mode settings by
- calling the GpiQueryAttrs function. For more information about color and
- mix modes, see Chapter 34, "Color and Mix Modes."
-
- A special vector, drawn from the origin of an imaginary Cartesian
- coordinate system through a specified point, defines the character-angle
- attribute. MS OS/2 aligns the baseline with this vector. You can retrieve
- the point that defines the character-angle vector by calling the
- GpiQueryCharAngle function, or you can set the character angle by calling
- the GpiSetCharAngle function and passing it the coordinates of a point
- that defines the new vector.
-
- A character box is an imaginary rectangle that applications use to scale
- characters in a font. You can determine the current character-box
- dimensions by calling the GpiQueryCharBox function. You can set new
- character-box dimensions by calling the GpiSetCharBox function. The
- dimensions that you pass to GpiSetCharBox and the dimensions that
- GpiQueryCharBox returns are fixed values. A fixed value, which is a
- representation of a floating-point number, is a 32-bit value whose
- high-order 16-bits contain the integral part of the floating-point number
- and whose low-order 16-bits contain the fractional part. The fractional
- part is the numerator of a fraction whose denominator is fixed at 65,536.
- If, for example, one of the box dimensions were 7.635 world units, you
- could obtain the corresponding fixed value by multiplying 7.635 by 65,536
- and storing the integer part of the result (500,367) in a fixed variable.
- The high-order 16-bits would contain 0x0007 and the low-order 16-bits
- would contain 0xA28F.
-
- A special vector, drawn from the origin of an imaginary Cartesian
- coordinate system through a specified point, defines the character-shear
- attribute. MS OS/2 aligns the vertical lines of the character box and the
- vertical strokes in a character with this vector. Figure 33.27 shows the
- effect of shearing a character:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.27 can be found in Section 33.2.5.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.27 Character Shear
-
- You can determine the current character-shear angle by calling the
- GpiQueryCharShear function. This function returns a point you can use to
- determine the shear vector. You can set the character-shear angle by
- calling the GpiSetCharShear function and passing it a point structure with
- the appropriate values.
-
- 33.2.5.2 Character Modes
-
- There are three character modes that determine whether MS OS/2 draws text
- using the current character attributes. When character mode 1 is set and
- the current font is an image font, MS OS/2 ignores the current shear,
- angle, and box attributes. When character mode 2 is set and the current
- font is an image font, MS OS/2 uses the current shear, angle, and box
- character attributes when it draws image-font text. In the current release
- of MS OS/2 Presentation Manager, mode 3 is reserved for outline fonts; if
- an application attempts to draw text output in mode 3 using an image font,
- MS OS/2 issues an error.
-
- Figure 33.28 shows a line drawn at the current character-shear angle and
- an image-font character drawn after an application set the character mode
- to 2:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.28 can be found in Section 33.2.5.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.28 Image Font and Character Shear
-
- Figure 33.29 shows a line drawn at the current character angle and a
- string of image-font text drawn after an application set the character
- mode to 2:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.29 can be found in Section 33.2.5.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.29 Image Font and Character Angle
-
- Figure 33.30 shows two letters of image-font text as they would appear in
- different sizes of character box after an application set the character
- mode to 2:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.30 can be found in Section 33.2.5.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.30 Image Font and Three Sizes of Character Box
-
- You can determine which character mode is set by calling the
- GpiQueryCharMode function. You can set a new character mode by calling the
- GpiSetCharMode function.
-
- If the current font is an outline font, MS OS/2 always draws text using
- the current character attributes──regardless of the current character
- mode.
-
- Figure 33.31 shows a vector that corresponds to the current
- character-shear angle and a character of outline-font text:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.31 can be found in Section 33.2.5.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.31 Outline Font and Character Shear
-
- Figure 33.32 shows a vector that corresponds to the current character
- angle and a string of outline-font text:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.32 can be found in Section 33.2.5.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.32 Outline Font and Character Angle
-
- Figure 33.33 shows two letters of outline-font text as they would appear
- in different sizes of character box:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.33 can be found in Section 33.2.5.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.33 Outline Font and Three Sizes of Character Box
-
- In addition to the character-attribute functions, you can use the
- Presentation Manager transformations to scale, rotate, translate, shear,
- and reflect text output drawn with an outline font. Figure 33.34 shows a
- bar graph labeled with outline text that has been rotated 90 degrees:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 33.34 can be found in Section 33.2.5.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 33.34 Graph with Outline Font
-
- 33.2.6 Font Files and Dynamic-Link Libraries
-
- You can use Font Editor to alter and customize image-font files (files
- with a .fnt extension). After creating a custom font tailored to your
- application, you need to turn it into a dynamic-link library that your
- application can load. Once your application loads this library, it can use
- any font within it. A dynamic-link library is a collection of code and
- data segments that applications can access at run time. The code and data
- in a dynamic-link library is shareable──several applications can access it
- simultaneously. Dynamic-link libraries that contain fonts are unique; they
- contain data segments and empty (or useless) code segments. The MS OS/2
- naming convention for a dynamic-link library requires that the library
- name end with a .fon extension.
-
- The following text explains how you can create a dynamic-link library that
- contains your custom font. To create a dynamic-link library, you must use
- masm, the Microsoft Macro Assembler; link, the Microsoft
- Segmented-Executable linker; and rc, the MS OS/2 Resource Compiler. For
- this example, assume that your custom font file is named newfont.fnt.
-
- After creating your custom font file, you need to create a special
- assembler file with your editor. You can use the following code fragment
- as the source code for this file:
-
- code segment word ;makes dummy code segment aligned on word boundary
- db "empty_segment" ;initializes a string in dummy segment
- code ends ;dummy segment ends here
- end ;terminates source file
-
- Call this file generic.asm. Once you have created generic.asm, assemble it
- with the following command:
-
- masm generic
-
- After assembling the file, you create a module-definition file. Call this
- file generic.def. It should contain the following statements:
-
- LIBRARY generic
- SEGMENTS CODE MOVEABLE
-
- The first statement tells the linker that you are creating a library with
- the module name generic. The second statement tells the linker that the
- segments in this library are movable code segments.
-
- Upon creating generic.def, you start the linker with the following
- command:
-
- link generic,,,,generic.def
-
- This command creates an empty executable file called generic.exe.
-
- After creating the empty executable file (which is the template for a
- dynamic-link library), you should create a resource file and call it
- generic.rc. For example, if your font file is called newfont.fnt, you
- would place the following statement in generic.rc:
-
- FONT 200 newfont.fnt
-
- This statement assigns an identifier, 200, to the font resource
- newfont.fnt.
-
- Finally, you should use Resource Compiler to add the font file
- (newfont.fnt) to the empty dynamic-link library:
-
- rc generic.rc
-
- The executable file, generic.exe, now contains your custom fonts. You
- still must rename this file generic.fon and copy it to a directory pointed
- to by the libpath command in your config.sys file. After you have done so,
- you can load the fonts into your application by calling the GpiLoadFonts
- function and passing it a pointer to the library name, generic, as the
- second argument.
-
- 33.2.7 Selecting New Fonts
-
- If you need to use a font other than the default system font in your
- application, you can select a new one by calling the GpiCreateLogFont
- function. There are two kinds of fonts that you can select: public fonts
- and private fonts.
-
- 33.2.7.1 Public Fonts
-
- Public fonts are those that a user loads by using the MS OS/2 Presentation
- Manager Control Panel. There are three dynamic-link libraries that contain
- Courier, Helvetica, and Times Roman fonts. If you load each library by
- using Control Panel, a total of 76 public fonts are available to any
- application that you run. These fonts are available in both outline and
- image formats in point sizes ranging from 8 to 24 points.
-
- You can determine how many public fonts are currently loaded by calling
- the GpiQueryFonts function and passing it the QF_PUBLIC flag as the second
- argument, a NULL pointer as the third argument, and a count of 0 as the
- fourth argument, as shown in the following code fragment:
-
- FONTMETRICS fm, afm[80];
- LONG lCount, lFontCount;
- HPS hps;
-
- lFontCount = GpiQueryFonts(hps,
- QF_PUBLIC,
- NULL, /* queries all public fonts */
- &lCount,
- (LONG) (sizeof(fm)),
- (PFONTMETRICS) afm);
-
- You can determine the characteristics of the loaded public fonts by
- calling GpiQueryFonts and passing it the QF_PUBLIC flag, the count of
- available fonts returned by the first call, and the address of an array of
- FONTMETRICS structures, as shown in the following code fragment. MS OS/2
- copies the attributes of the fonts into the array of FONTMETRICS
- structures, which you can then examine in order to select a font.
-
- lFontCount = GpiQueryFonts(hps,
- QF_PUBLIC,
- NULL,
- &lCount,
- (LONG) (sizeof(fm)),
- (PFONTMETRICS) afm);
-
- Once you determine which font you need, call the GpiCreateLogFont func-
- tion, which copies various fields from the FONTMETRICS structure of the
- desired font into their corresponding fields in a FATTRS structure. The
- fields in the FATTRS structure describe the face name, code page, maximum
- baseline extent, and average character width of the font you would like to
- use. A special field, lMatch, contains a unique identifier that MS OS/2
- uses to match your request to a font. Another field in the FATTRS
- structure specifies whether the font should be an image font or an outline
- font. You can use other fields to request that MS OS/2 synthesize an
- italic, underscored, strikeout, or bold font.
-
- If MS OS/2 returns the value 2 after the call to GpiCreateLogFont, the
- function was successful. You can begin using the font after you assign it
- to the application's presentation space by passing the local identifier
- (lcid) from GpiCreateLogFont to the GpiSetCharSet function.
-
- 33.2.7.2 Private Fonts
-
- Private fonts are fonts that an application loads exclusively for its own
- use. An application loads a private font when it calls the GpiLoadFonts
- function and passes it the name of the dynamic-link library that contains
- the fonts. (Note that in order to load a dynamic-link library of fonts,
- the library must be in one of the directories pointed to by the libpath
- command in the config.sys file.)
-
- After the application loads the dynamic-link library of fonts, it can
- determine the characteristics of the fonts in that library by calling the
- GpiQueryFonts function.
-
- You can determine how many private fonts are currently loaded by calling
- GpiQueryFonts passing it the QF_PRIVATE flag as the second argument, a
- NULL pointer as the third argument, and a count of 0 as the fourth
- argument, as shown in the following code fragment.
-
- FONTMETRICS fm, afm[80];
- LONG lCount;
-
- lFontCount = GpiQueryFonts(hps,
- QF_PRIVATE,
- NULL, /* queries all private fonts */
- &lCount,
- (LONG) (sizeof(fm)),
- (PFONTMETRICS) afm);
-
- You can determine the characteristics of the loaded private fonts by
- calling GpiQueryFonts and passing it the QF_PRIVATE flag, the count of
- available fonts returned by the first call, and the address of an array of
- FONTMETRICS structures, as shown in the following code fragment. MS OS/2
- copies the font attributes into the array of FONTMETRICS structures, which
- you can then examine in order to select a font.
-
- lFontCount = GpiQueryFonts(hps,
- QF_PRIVATE,
- NULL,
- &lCount,
- (LONG) (sizeof(fm)),
- (PFONTMETRICS) afm);
-
- Once you determine which font you need, call the GpiCreateLogFont func-
- tion, which copies various fields from the FONTMETRICS structure into
- their corresponding fields in a FATTRS structure. The fields in the FATTRS
- structure describe the face name, code page, maximum baseline extent, and
- average character width of the font you would like to use. A special
- field, lMatch, contains a unique identifier that MS OS/2 uses to match
- your request to a font. Other fields in the FATTRS structure specify
- whether the font is an outline font or an image font and whether it is
- proportional or fixed. You can use another of the fields to request that
- MS OS/2 synthesize an italic, underscored, strikeout, or bold font. The
- FATTRS structure has the following form:
-
- typedef struct _FATTRS { /* fat */
- USHORT usRecordLength;
- USHORT fsSelection;
- LONG lMatch;
- CHAR szFacename[FACESIZE];
- USHORT idRegistry;
- USHORT usCodePage;
- LONG lMaxBaselineExt;
- LONG lAveCharWidth;
- USHORT fsType;
- USHORT fsFontUse;
- } FATTRS;
-
- If MS OS/2 returns the value 2 after the call to GpiCreateLogFont, the
- function was successful. You can begin using the font after you assign it
- to the application's presentation space by passing the local identifier
- (lcid) from GpiCreateLogFont to the GpiSetCharSet function. If MS OS/2
- returns 1 after you call GpiCreateLogFont, the function was not successful
- and the new font is the default system font.
-
-
- 33.3 Using Fonts and Character Primitives
-
- You can use the font and character functions to perform the following
- tasks:
-
- ■ Select a font from the public fonts loaded with Control Panel.
-
- ■ Select a font from a library of private fonts loaded by the
- application.
-
- ■ Draw a string of text using the selected font.
-
- ■ Scale, translate, and rotate a string of text from an outline font.
-
- ■ Scale, shear, and alter the direction of a string of text from image
- and outline fonts.
-
- 33.3.1 Selecting a Public Font
-
- To select a public font, you must perform the following tasks:
-
- ■ Call the GpiQueryFonts function, passing the QF_PUBLIC flag, a NULL
- pointer to the font's face name, and a count of 0 to determine the
- number of available public fonts.
-
- ■ Copy this number (the GpiQueryFonts return value) into an integer
- variable.
-
- ■ Call GpiQueryFonts again, passing the QF_PUBLIC flag, a NULL pointer to
- the font's face name, and the count returned by the previous call.
-
- ■ Examine the metrics, looking for the face name and attributes of the
- font that your application needs.
-
- ■ Copy the appropriate metrics from the font that suits your application
- into a FATTRS structure.
-
- ■ Initialize a local identifier (lcid) for the new font.
-
- ■ Call the GpiCreateLogFont function, passing a local identifier for the
- font, the address of an empty array of eight characters, and the
- address of the FATTRS structure.
-
- ■ Examine the return value from GpiCreateLogFont. If the function was
- successful, it should be 2.
-
- ■ Pass the local identifier to the etCharSet function, assigning the font
- to your application's presentation space.
-
- The following code fragment shows how to select a Helvetica public font:
-
- i = 0;
- while (!strcomp(afm[i++].szFacename, "Helv"));
- lFontCount = GpiQueryFonts(hps,
- QF_PUBLIC,
- NULL,
- &lCount,
- (LONG) (sizeof(fm)),
- (PFONTMETRICS) afm);
- lCount = lFontCount;
- lFontCount = GpiQueryFonts(hps,
- QF_PUBLIC,
- NULL,
- &lCount,
- (LONG) (sizeof(fm)),
- (PFONTMETRICS) afm);
- fat.usRecordLength = sizeof(fat);
- fat.fsSelection = afm[i].fsSelection;
- fat.lMatch = afm[i].lMatch;
- strcpy(fat.szFacename, afm[i].szFacename);
- fat.idRegistry = afm[i].idRegistry;
- fat.usCodePage = afm[i].usCodePage;
- fat.lMaxBaselineExt = afm[i].lMaxBaselineExt;
- fat.lAveCharWidth = afm[i].lAveCharWidth;
- fat.fsType = afm[i].fsType;
- fat.fsFontUse = 0;
- GpiCreateLogFont(hps,
- (PSTR8) chName,
- lcid,
- (PFATTRS) &fat);
- GpiSetCharSet(hps, lcid);
-
- 33.3.2 Drawing Text
-
- Before drawing text, you must determine which of the four ext-output
- functions you should use. The following list describes the specific
- purpose of each text-output function:
-
- ╓┌─┌───────────────────┌─────────────────────────────────────────────────────╖
- Function name Purpose
- Function name Purpose
- ──────────────────────────────────────────────────────────────────────────
- GpiCharString This function draws a string of text starting at the
- current position.
-
- GpiCharStringAt This function draws a string of text starting at a
- point that you pass as a function argument. It is
- identical to a function sequence of GpiMove,
- GpiCharString.
-
- GpiCharStringPos This function alters the intercharacter spacing in a
- string of text in order to shade a special rectangle
- that surrounds a string of text, to draw a string of
- text in halftones, or to clip a string of text to a
- special rectangle. This function starts drawing the
- text at the current position.
-
- GpiCharStringPosAt This function alters the intercharacter spacing in a
- string of text in order to shade a special rectangle
- that surrounds a string of text, to draw a string of
- text in halftones, or to clip a string of text to a
- Function name Purpose
- ──────────────────────────────────────────────────────────────────────────
- text in halftones, or to clip a string of text to a
- special rectangle. This function starts drawing the
- text at a point that you pass as one of the function
- arguments.
- ──────────────────────────────────────────────────────────────────────────
-
-
- The following code fragment shows how to load an array of characters with
- the string "MS OS/2 Presentation Manager", set the current position to the
- point (100,100) by calling the GpiMove function, and then draw the string
- by calling the GpiCharString function:
-
- ptl.x = 100; ptl.y = 100;
- GpiMove (hps, &ptl);
- GpiCharString(hps, 28L, "MS OS/2 Presentation Manager");
-
- 33.3.3 Transforming Text from an Outline Font
-
- The following code fragment shows how to rotate a string of text 90
- degrees counterclockwise by using the model transformation:
-
- matlfTransform.fxM11 = MAKEFIXED(1, 0); /* translates text */
- matlfTransform.fxM12 = MAKEFIXED(0, 0);
- matlfTransform.lM13 = 0L;
- matlfTransform.fxM21 = MAKEFIXED(0, 0);
- matlfTransform.fxM22 = MAKEFIXED(1, 0);
- matlfTransform.lM23 = 0L;
- matlfTransform.lM31 = -300L;
- matlfTransform.lM32 = -100L;
- matlfTransform.lM33 = 1L;
- GpiSetModelTransformMatrix(hps, 9L, &matlfTransform,
- TRANSFORM_REPLACE);
- matlfTransform.fxM11 = MAKEFIXED(0, 0); /* rotates text */
- matlfTransform.fxM12 = MAKEFIXED(1, 0);
- matlfTransform.lM13 = 0L;
- matlfTransform.fxM21 = -MAKEFIXED(1, 0);
- matlfTransform.fxM22 = MAKEFIXED(0, 0);
- matlfTransform.lM23 = 0L;
- matlfTransform.lM31 = 0L;
- matlfTransform.lM32 = 0L;
- matlfTransform.lM33 = 1L;
- GpiSetModelTransformMatrix(hps, 9L, &matlfTransform, TRANSFORM_ADD);
-
- matlfTransform.fxM11 = MAKEFIXED(1, 0); /* translates again */
- matlfTransform.fxM12 = MAKEFIXED(0, 0);
- matlfTransform.lM13 = 0L;
- matlfTransform.fxM21 = MAKEFIXED(0, 0);
- matlfTransform.fxM22 = MAKEFIXED(1, 0);
- matlfTransform.lM23 = 0L;
- matlfTransform.lM31 = 300L;
- matlfTransform.lM32 = 100L;
- matlfTransform.lM33 = 1L;
- GpiSetModelTransformMatrix(hps, 9L, &matlfTransform, TRANSFORM_ADD);
-
- ptl.x = 100;
- ptl.y = 100;
- GpiMove(hps, &ptl);
- GpiCharString(hps, 28L, "MS OS/2 Presentation Manager");
-
- 33.3.4 Transforming Text from an Image Font
-
- The following code fragment shows how to double the size of the character
- box, set the character mode to 2, and then print a string of text:
-
- GpiQueryCharBox(hps, &sizfxBox);
- sizfxBox.cx = 2 * sizfxBox.cx;
- sizfxBox.cy = 2 * sizfxBox.cy;
- GpiSetCharBox(hps, &sizfxBox);
- ptl.x = 100;
- ptl.y = 100;
- GpiMove(hps, &ptl);
- GpiCharString(hps, 28L, "MS OS/2 Presentation Manager");
-
-
- 33.4 Summary
-
- The following list summarizes the MS OS/2 font and character-primitive
- functions:
-
- GpiCharString Draws a string of text starting at the current position. It
- sets the current position to the end of the string at the point where the
- next character would be drawn. All text is drawn using the font assigned
- to the application's presentation space.
-
- GpiCharStringAt Draws a string of text starting at a point that you
- specify as a function argument. It updates the current position after
- drawing each character in the string and, upon completion, sets the
- current position to the point where the next character would be drawn. All
- text is drawn using the font assigned to the application's presentation
- space.
-
- GpiCharStringPos Draws a string of text starting at the current position.
- It sets the current position to the end of the string at the point where
- the next character would be drawn. All text is drawn using the font
- assigned to the application's presentation space. In addition to drawing a
- string of text, you can use this function to do the following:
-
- ■ Adjust spacing between characters in the string.
-
- ■ Clip the text to a small rectangle.
-
- GpiCharStringPosAt Draws a string of text starting at a point that you
- specify as one of the function arguments. It sets the current position to
- the end of the string at the point where the next character would be
- drawn. All text is drawn using the font assigned to the application's
- presentation space. In addition to drawing a string of text, you can use
- this function to do the following:
-
- ■ Adjust spacing between characters in the string.
-
- ■ Shade the text by drawing it in halftones.
-
- ■ Clip the text to a small rectangle.
-
- GpiCreateLogFont Passes a description of a font to MS OS/2, which
- attempts to select the closest possible match from available fonts in MS
- OS/2 or on the device associated with the current presentation space. If
- the font you request is not available, MS OS/2 selects the default system
- font. A FATTRS structure contains a description of the requested font.
- Typically, applications call the GpiQueryFonts function and examine the
- metrics for a number of fonts in the system and then load the FATTRS
- structure with values from the metrics of the desired font. If MS OS/2 is
- successful and finds a font that matches the values in FATTRS, the
- function returns a value of 2; if MS OS/2 does not find a matching font
- and substitutes the default system font instead, the function returns a
- value of 1; if the function fails completely, it returns 0.
-
- GpiDeleteSetId Frees a local identifier (lcid). A local identifier is a
- long integer value that identifies a particular font that you are using in
- your application. Once you free a local identifier from a particular font,
- that font is no longer available for use.
-
- GpiLoadFonts Loads private fonts from a dynamic-link library of fonts so
- that an application can access them by calling the GpiQueryFonts and
- GpiCreateLogFont functions. You identify a specific dynamic-link library
- by passing it the appropriate path and filename as arguments.
-
- GpiQueryCharAngle Retrieves the current value of the character-baseline
- angle. If the current font is an outline font, the baseline of each
- character's cell is drawn parallel to this angle. If the current font is
- an image font, the character-baseline angle uniquely affects the
- image-font output. If the current font is an image font and the character
- mode is 1, MS OS/2 ignores the baseline angle. If the current font is an
- image font, the character mode is 2, and the baseline angle is nonzero, MS
- OS/2 aligns text with the baseline angle. However, the baseline of each
- character remains parallel to the x-axis.
-
- GpiQueryCharBox Retrieves the dimensions (in world coordinates) of the
- character box. If the current font is an outline font, the character-cell
- dimensions are reduced or expanded to match the character-box dimensions.
- If the current font is an image font, the character-box dimensions
- uniquely affect the image-font output. If the current font is an image
- font and the character mode is 1, MS OS/2 ignores the character-box
- dimensions when it draws text. If the current font is an image font and
- the character mode is 2, MS OS/2 increases or reduces the spacing between
- characters (based on the box dimensions) when it draws text.
-
- GpiQueryCharMode Retrieves the current character-mode attribute. There
- are three character modes; each affects text output with an image font. In
- mode 1, MS OS/2 ignores the character angle, box, and shear attributes
- when drawing text with an image font. In mode 2, MS OS/2 uses each of the
- attributes when drawing text with an image font. In mode 3, MS OS/2 issues
- an error if the application attempts to draw text using an image font. An
- application can use outline fonts for text output in character mode 3
- only.
-
- GpiQueryCharSet Retrieves the local identifier assigned to the current
- font.
-
- GpiQueryCharShear Retrieves the current character-shear attribute. The
- character-shear attribute is a point that defines the angle between the
- x-axis of a coordinate system and a line drawn from a system's origin
- through the point. If the current font is an outline font, the sides of
- the character box are drawn parallel to this angle and the character
- within the box is slanted accordingly. If the current font is an image
- font and the character mode is 1, MS OS/2 ignores this attribute when
- drawing text. If the current font is an image font and the character mode
- is 2, MS OS/2 draws the sides of the character box parallel to the angle;
- the character itself remains upright.
-
- GpiQueryCharStringPos Retrieves an array of points that specify the
- position (in world coordinates) that MS OS/2 would assign to each
- character in a string of text if the string were drawn by the
- GpiCharStringPos function.
-
- GpiQueryCharStringPosAt Retrieves an array of points that specify the
- position (in world coordinates) that MS OS/2 would assign to each
- character in a string of text if the string were drawn by the
- GpiCharStringPosAt function.
-
- GpiQueryCp Retrieves the current code-page identifier. A code page is a
- character set that contains 256 characters. Each character in the code
- page is assigned a value (called a code point) in the range 0 through 255.
- A code-page identifier is a three-digit value in the range 0 through 999.
-
- GpiQueryDefCharBox Retrieves the default character-box dimensions (in
- world coordinates). The default dimensions are assigned by the font's
- designer.
-
- GpiQueryFontFileDescriptions Retrieves the types and face names of fonts
- in a file, if that file is a font file.
-
- GpiQueryFontMetrics Retrieves the font metrics for the current logical
- font.
-
- GpiQueryFonts Retrieves metrics for all of the public or private fonts if
- the third argument is a NULL pointer. Otherwise, it returns the metrics
- for fonts with a particular face name. The function returns the metrics in
- an array of FONTMETRICS structures. A public font is one that MS OS/2
- loads when a user turns the computer on. A private font is one that an
- application loads.
-
- GpiQueryKerningPairs Retrieves an array of KERNINGPAIRS structures.
- Kerning is space that appears between a pair of characters when MS OS/2
- draws them. By adjusting the kerning between certain characters, you can
- make text more readable. The KERNINGPAIRS structure contains three fields:
- The first two identify the characters, and the third specifies the amount
- of kerning (measured in world coordinates). If this last field contains a
- negative number, the kerning is reduced by that amount; if the last field
- contains a positive number, the kerning is increased by that amount.
-
- GpiQueryNumberSetIds Retrieves the number of current local identifiers
- that an application is using. You can use this value when you call the
- GpiQuerySetIds function.
-
- GpiQueryTextBox Retrieves the dimensions of a rectangle surrounding a
- string of text that an application draws using the GpiCharStringPos or
- GpiCharStringPosAt function. You can use these dimensions to draw a shaded
- rectangle behind the text.
-
- GpiQueryWidthTable Retrieves width values you can use to determine the
- average character width of characters in the current logical font. To
- determine this average character width, you multiply the width values by
- the factors given in the description of the FONTMETRICS structure.
-
- GpiSetCharAngle Sets the current value of the character-baseline angle.
- If the current font is an outline font, the baseline of each character's
- cell is drawn parallel to this angle. If the current font is an image
- font, the character-baseline angle uniquely affects the image-font output.
- If the current font is an image font and the character mode is 1, MS OS/2
- ignores the baseline angle. If the current font is an image font, the
- character mode is 2, and the baseline angle is nonzero, MS OS/2 aligns
- text with the baseline angle. However, the baseline of each character
- remains parallel to the x-axis.
-
- GpiSetCharBox Sets the dimensions (in world coordinates) of the character
- box. If the current font is an outline font, the character-cell dimensions
- are reduced or expanded to match the dimensions of the character box. If
- the current font is an image font, the dimensions of the character box
- uniquely affect the image-font output. If the current font is an image
- font and the character mode is 1, MS OS/2 ignores the character-box
- dimensions when drawing text. If the current font is an image font and the
- character mode is 2, MS OS/2 increases or reduces the spacing between
- characters (based on the box dimensions) when drawing text strings.
-
- GpiSetCharMode Sets the current character-mode attribute. There are three
- character modes; each affects text output with an image font. In mode 1,
- MS OS/2 ignores the angle, box, and shear attributes when drawing text
- with an image font. In mode 2, MS OS/2 uses each of the attributes when
- drawing text with an image font. In mode 3, MS OS/2 issues an error if the
- application attempts to draw text using an image font. An application can
- use outline fonts for text output in character mode 3 only.
-
- GpiSetCharSet Assigns a font to a presentation space. The font is
- identified by a local identifier (lcid).
-
- GpiSetCharShear Sets the current character-shear attribute. The
- character-shear attribute is a point that defines an angle between the
- x-axis of a coordinate system and a line drawn from a system's origin
- through the point. If the current font is an outline font, the sides of
- the character box are drawn parallel to this angle and the character
- within the box is slanted accordingly. If the current font is an image
- font and the character mode is 1, MS OS/2 ignores this attribute when
- drawing text. If the current font is an image font and the character mode
- is 2, MS OS/2 draws the sides of the character box parallel to the angle;
- the character itself remains upright.
-
- GpiSetCp Sets the current code-page identifier. A code page is a
- character set that contains 256 characters. Each character in the code
- page is assigned a value (called a code point) in the range 0 through 255.
- A code-page identifier is a three-digit value in the range 0 through 999.
-
- GpiUnloadFonts Unloads font definitions that were loaded previously from
- a resource file.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 34 Color and Mix Modes
-
- 34.1 Introduction
- 34.2 About Color and Mix Modes
- 34.2.1 Color and RGB Values
- 34.2.2 Color Tables
- 34.2.3 Color Output and Mix Modes
- 34.2.4 Dithering
- 34.3 Using Colors and Mix Modes
- 34.3.1 Creating a Logical Color Table
- 34.3.2 Determining the Color-Table Format and Index Values
- 34.3.3 Determining an Index Value for an RGB Value
- 34.3.4 Setting the Primitive Color Attributes
- 34.4 Summary
-
- 34.1 Introduction
-
- This chapter describes color and mix modes and their use in MS OS/2
- applications. You should also be familiar with the following topics:
-
- ■ Presentation spaces and device contexts
-
- ■ Line and arc primitives
-
- ■ Area primitives
-
- ■ Character primitives
-
- ■ Marker primitives
-
-
- 34.2 About Color and Mix Modes
-
- Color and mix modes are two primitive attributes. The color attribute
- describes a line, arc, character, marker, area, or image color before it
- is combined with the color on the drawing surface. The mix-mode attribute
- describes how the system combines a primitive's color with the color of
- the drawing surface. Some primitives have foreground and background color
- attributes. For instance, the character primitive has a foreground color
- attribute that specifies the color of the character and a background color
- attribute that specifies the color surrounding the character. The
- primitives that have foreground and background attributes also have
- foreground and background mix modes.
-
- To understand color, it is important to understand several principles of
- color devices. Most color devices can generate three fundamental colors:
- red, green, and blue. On some devices, each of these three colors
- corresponds to a color plane──for example, a red pel is visible when a pel
- in the red plane is on and the corresponding pels in the green and blue
- planes are off. On other devices, there is only one color plane, and each
- pel contains a red, a green, and a blue section──for example, a red pel is
- visible when the red section of that pel is on and the green and blue
- sections are off. By combining the three fundamental colors, a device can
- obtain five additional colors, for a total of eight. These eight colors,
- and the combinations that produce them, are as follows:
-
- Resulting Combined colors
- color
- ──────────────────────────────────────────────────────────────────────────
- Black Red, green, and blue are off.
-
- Red Red is on; green and blue are off.
-
- Green Green is on; red and blue are off.
-
- Blue Blue is on; red and green are off.
-
- Pink Red and blue are on; green is off.
-
- Cyan Blue and green are on; red is off.
-
- Yellow Red and green are on; blue is off.
-
- White Red, green, and blue are on.
- ──────────────────────────────────────────────────────────────────────────
-
- 34.2.1 Color and RGB Values
-
- In MS OS/2, the red, green, and blue components of a color are either
- stored in an RGB structure or stored as a long integer (32-bit) value. The
- RGB structure has the following format:
-
- typedef struct _RGB { /* rgb */
- BYTE bBlue;
- BYTE bGreen;
- BYTE bRed;
- } RGB;
-
- The RGB value has the following format:
-
- 0x00RRGGBB.
-
- Each field in the RGB structure and each of the last three bytes in the
- RGB value specify a color intensity in the range 0 through 255, 0 being
- the lowest intensity, 255 the highest. If a field or byte contains 0, its
- corresponding color is not visible; if a field or byte contains 128, the
- color is pale; and if a field or byte contains 255, the color is as
- intense as the device allows. If all the fields or bytes are set to 0, the
- corresponding color is black. Similarly, if all the fields or bytes are
- set to 255, the corresponding color is white.
-
- The following list shows the RGB value associated with each of the eight
- fundamental colors:
-
- Color Associated RGB value
- ──────────────────────────────────────────────────────────────────────────
- White 0x00FFFFFF
-
- Yellow 0x00FFFF00
-
- Pink 0x00FF00FF
-
- Cyan 0x0000FFFF
-
- Blue 0x000000FF
-
- Green 0x0000FF00
-
- Red 0x00FF0000
-
- Black 0x00000000
- ──────────────────────────────────────────────────────────────────────────
-
- 34.2.2 Color Tables
-
- A color table is an array of RGB values. There are two kinds of color
- tables: physical (used by device drivers) and logical (used by
- applications). The physical color table contains RGB values representing
- the available colors on a device. The logical color table contains RGB
- values representing the colors that an application would prefer to use.
- You can determine which colors are in the physical color table by calling
- the GpiQueryRealColors function. You can determine which colors are in the
- current logical color table by calling the GpiQueryLogColorTable function.
-
- The following list contains the index values and colors found in a logical
- color table:
-
- ╓┌─┌──────┌──────────────────────────────────────────────────────────────────╖
- Index Color
- ──────────────────────────────────────────────────────────────────────────
- 0 Device's background color (white)
-
- 1 Blue
-
- 2 Red
-
- 3 Pink
-
- 4 Green
-
- 5 Cyan
- Index Color
- ──────────────────────────────────────────────────────────────────────────
- 5 Cyan
-
- 6 Yellow
-
- 7 Neutral color (black)
-
- 8 Dark gray
-
- 9 Pale blue
-
- 10 Pale red
-
- 11 Pale pink
-
- 12 Dark green
-
- 13 Dark cyan
-
- 14 Brown
- Index Color
- ──────────────────────────────────────────────────────────────────────────
- 14 Brown
-
- 15 Pale gray
- ──────────────────────────────────────────────────────────────────────────
-
-
- The value you place in the color field of a primitive-attribute structure
- (by using GpiSetAttrs) is an index into the logical color table. When MS
- OS/2 draws the primitive, it searches the physical color table for a color
- that is the closest approximation to this color index. MS OS/2 then uses
- this approximate color to draw with.
-
- You can replace the default logical color table with a new color table by
- calling the GpiCreateLogColorTable function. You can also use this
- function to reset the logical color table to its original values. Either
- way, once you create a new logical color table (or reset it to its
- original values), it becomes part of the application's presentation space.
-
- For a given device, you can determine the maximum size of the logical
- color table by using the DevQueryCaps function. This function also returns
- the maximum number of distinct colors available on a particular device.
-
- 34.2.3 Color Output and Mix Modes
-
- When an application draws a line, arc, character, marker, area, or image,
- MS OS/2 uses a mix mode to determine the color that appears on a video
- display, printer, or plotter. A mix mode is a bitwise operation on the
- color indices in a device's physical color table. For example, suppose an
- application has set the lColor field in the LINEBUNDLE structure to
- CLR_BLUE and the usMixMode field in the same structure to FM_OR. The
- current drawing-surface color is CLR_BACKGROUND. The CLR_BLUE entry
- corresponds to the color blue in both the presentation space's logical
- color table and the device's physical color table. The CLR_BACKGROUND
- entry corresponds to the color white in both the presentation space's
- logical color table and the device's physical color table. The index value
- for blue in the device's table is 0x0001, and the index value for white in
- the device's table is 0x0000. To determine the color of a line, MS OS/2
- performs a bitwise OR operation on the two index values, as follows:
-
- 0x0001
- 0x0000
- ──────
- 0x0001 (Result of bitwise OR)
-
- In this case, the result is 0x0001, the index value for blue in the
- device's color table. This means that a blue line appears when the
- application calls the GpiLine or GpiPolyLine function.
-
- Some of the primitive bundles contain foreground and background colors and
- mix modes. For instance, the AREABUNDLE structure contains a foreground
- color that corresponds to the foreground color of the area fill pattern.
- The AREABUNDLE structure also contains a background color that corresponds
- to the background color that appears behind the area fill pattern.
- AREABUNDLE also contains foreground and background mix modes that specify
- bitwise operations on index values in the device's physical color table.
-
- There are 16 foreground mix modes. For each mix mode, the index value for
- the foreground and current drawing-surface colors (in the device's
- physical color table) are combined by using one of the bitwise operators.
- The different foreground mix modes are described in the following list:
-
- ╓┌─┌───────────────────┌─────────────────────────────────────────────────────╖
- Mix mode Description
- ──────────────────────────────────────────────────────────────────────────
- FM_AND Final color's index value is determined by a bitwise
- AND operation on the foreground color's index value
- and the drawing surface's index value.
-
- FM_INVERT Final color's index value is always the inverse of the
- drawing surface's index value.
-
- FM_LEAVEALONE Final color's index value is that of the
- drawing-surface color.
-
- FM_MASKSRCNOT Final color's index value is determined by inverting
- the drawing surface's index value and performing a
- bitwise AND operation on this value and the foreground
- color's index value.
-
- FM_MERGENOTSRC Final color's index value is determined by performing
- a bitwise AND operation on the drawing surface's index
- value and the inverse of the foreground color's index
- Mix mode Description
- ──────────────────────────────────────────────────────────────────────────
- value and the inverse of the foreground color's index
- value.
-
- FM_MERGESRCNOT Final color's index value is determined by performing
- a bitwise AND operation on the foreground color's
- index value and the inverse of the drawing-surface
- color's index value.
-
- FM_NOTCOPYSRC Final color's index value is the inverse of the
- foreground color's index value.
-
- FM_NOTMASKSRC Final color's index value is the inverse of the FM_AND
- result.
-
- FM_NOTMERGESRC Final color's index value is always the inverse of the
- FM_OR result.
-
- FM_NOTXORSRC Final color's index value is always the inverse of the
- FM_XOR result.
- Mix mode Description
- ──────────────────────────────────────────────────────────────────────────
- FM_XOR result.
-
- FM_ONE Final color's index value is always 1.
-
- FM_OR Final color's index value is determined by a bitwise
- OR operation on the foreground color's index value and
- the drawing surface's index value.
-
- FM_OVERPAINT Final color's index value is that of the foreground
- color.
-
- FM_SUBTRACT Final color's index value is determined by inverting
- the foreground color's index value and performing a
- bitwise AND operation on this value and the drawing
- surface's index value.
-
- FM_XOR Final color's index value is determined by a bitwise
- XOR operation on the foreground color's index value
- and the drawing surface's index value.
- Mix mode Description
- ──────────────────────────────────────────────────────────────────────────
- and the drawing surface's index value.
-
- FM_ZERO Final color's index value is always zero.
- ──────────────────────────────────────────────────────────────────────────
-
-
- There are four background mix modes. For each mix mode, the index value
- for the background color and the current drawing-surface color (in the
- device's physical color table) are combined using one of the bitwise
- operators. The different background mix modes are described in the
- following list:
-
- Mix mode Description
- ──────────────────────────────────────────────────────────────────────────
- BM_LEAVEALONE Final color's index value is that of the
- drawing-surface color.
-
- BM_OR Final color's index value is determined by a bitwise
- OR operation on the background color's index value and
- the drawing surface's index value.
-
- BM_OVERPAINT Final color's index value is that of the background
- color.
-
- BM_XOR Final color's index value is determined by a bitwise
- XOR operation on the background color's index value
- and the drawing surface's index value.
- ──────────────────────────────────────────────────────────────────────────
-
- 34.2.4 Dithering
-
- If you request a color that isn't available in the physical color table,
- MS OS/2 obtains the closest match by a process called dithering. For
- example, if the physical color table does not contain a certain shade of
- gray, MS OS/2 can create what appears to be a gray by mixing black pels
- and white pels. Similarly, if the physical color table does not contain a
- light green color but does contain a yellow and a green, MS OS/2 can
- create what appears to be light green by mixing yellow pels and green
- pels.
-
- Dithering is especially important on monochrome devices. By combining
- various combinations of black pels with white pels, MS OS/2 can create
- numerous shades of gray.
-
-
- 34.3 Using Colors and Mix Modes
-
- You can use the color and mix-mode functions to perform the following
- tasks:
-
- ■ Create a logical color table.
-
- ■ Determine the format and the starting and ending index values of the
- current logical color table.
-
- ■ Determine the index value for an entry in the logical color table that
- is the closest match to an RGB value.
-
- ■ Determine the RGB value associated with a particular entry in the
- logical color table.
-
- ■ Determine and set the current foreground and background colors.
-
- ■ Determine and set the current foreground and background mix modes.
-
- 34.3.1 Creating a Logical Color Table
-
- To create a logical color table, you must perform the following tasks:
-
- 1. Create an array of RGB values that will replace the existing logical
- color table.
-
- 2. Call the GpiCreateLogColorTable function, using the LCOL_RESET and
- LCOLF_CONSECRGB flags.
-
- The following code fragment demonstrates this process:
-
- LONG alTable[] = {
- 0xFFFFFF, /* white */
- 0xEDEDED,
- 0xDBDBDB,
- 0xC9C9C9,
- 0xB7B7B7,
- 0xA6A6A6,
- 0x949494,
- 0x828282,
- 0x707070,
- 0x5E5E5E,
- 0x4D4D4D,
- 0x3B3B3B,
- 0x292929,
- 0x171717,
- 0x050505,
- 0x000000 }; /* black */
-
- GpiCreateLogColorTable(hps,
- LCOL_RESET, /* begins with default */
- LCOLF_CONSECRGB, /* consecutive RGB values */
- 0L, /* starting index in table */
- 16L, /* number of elements in table */
- alTable);
-
- 34.3.2 Determining the Color-Table Format and Index Values
-
- To determine the format and the starting and ending index values of the
- current logical color table, you can call the GpiQueryColorData function.
- The following code fragment calls GpiQueryColorData to determine whether
- the default logical color table is loaded and, if so, loads a new table:
-
- LONG lClrData[3];
- .
- .
- .
- GpiQueryColorData(hps, 3L, lClrData);
- if (lClrData == LCOLF_DEFAULT)
- GpiCreateLogColorTable(hps,
- LCOL_RESET, /* begins with default */
- LCOLF_CONSECRGB, /* consecutive RGB values */
- 0L, /* starting index in table */
- 16L, /* number of elements in table */
- alTable);
-
- 34.3.3 Determining an Index Value for an RGB Value
-
- To determine the logical-color-table index value associated with an RGB
- value, you can call the GpiQueryColorIndex function. The following code
- fragment shows how to determine which index value matches the RGB value
- for pink (0x00FF00FF) and then use that index entry to set the foreground
- color to pink for each of the primitive attributes:
-
- LONG lIndex = 255; /* logical-color-table index */
-
- lIndex = GpiQueryColorIndex(hps, LCOLOPT_REALIZED, 0x00FF00FF);
- if ((lIndex>= 0) && (lIndex <= 15)) /* checks for valid index */
- GpiSetColor(hps, lIndex);
-
- 34.3.4 Setting the Primitive Color Attributes
-
- To set the color attributes for a single primitive, you can call the
- GpiSetAttrs function, or you can set the color attributes for all of the
- primitives in a presentation space by calling the GpiSetColor and
- GpiSetBackColor functions.
-
- The following code fragment shows how to use GpiSetAttrs to set the
- line-primitive color attribute to dark gray:
-
- LINEBUNDLE lbnd; /* line-primitive attribute bundle */
-
- lbnd.lColor = CLR_DARKGRAY;
- GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lbnd);
-
- The next code fragment shows how to use GpiSetColor to set the foreground
- color attribute for all of the primitives to dark gray:
-
- GpiSetColor(hps, CLR_DARKGRAY);
-
-
- 34.4 Summary
-
- The following list summarizes the MS OS/2 color and mix-mode functions:
-
- GpiCreateLogColorTable Creates a table of colors for an application.
- After you call this function, MS OS/2 creates the closest match to the
- ideal colors in your logical color table by mapping colors from the
- device's physical color table and then dithering them.
-
- GpiQueryBackColor Retrieves the current background color. If the
- background colors were set by the GpiSetBackColor function, the color
- returned by GpiQueryBackColor is the background color for line, character,
- marker, and bitmap operations. If the background colors were set by the
- GpiSetAttrs function, the color returned by GpiQueryBackColor is the
- background color for character output only.
-
- GpiQueryBackMix Retrieves the current background mix mode. If the
- background mix mode was set by the GpiSetBackMix function, the mix mode
- returned by GpiQueryBackMix is the background mix mode for line,
- character, marker, and bitmap operations. If the background mix mode was
- set by the GpiSetAttrs function, the mix mode returned by GpiQueryBackMix
- is the background mix mode for character output only.
-
- GpiQueryColor Retrieves the current foreground color. If the foreground
- color was set by the GpiSetColor function, the color returned by
- GpiQueryColor is the foreground color for line, character, marker, and
- bitmap operations. If the foreground color was set by the GpiSetAttrs
- function, the color returned by GpiQueryColor is the foreground color for
- character output only.
-
- GpiQueryColorData Retrieves information about the current logical color
- table. This information includes the format and the starting and ending
- index values of the current logical color table.
-
- GpiQueryColorIndex Retrieves the index value for the logical-color-table
- entry that is the closest possible match to a specified RGB value.
-
- GpiQueryLogColorTable Retrieves information about the current logical
- color table.
-
- GpiQueryMix Retrieves the value of the current foreground-color mix-mode
- attribute.
-
- GpiQueryNearestColor Retrieves the RGB value for an available color on
- the current output device that is the closest possible color match to a
- specified RGB value.
-
- GpiQueryRGBColor Retrieves the RGB value associated with a
- logical-color-table index.
-
- GpiQueryRealColors Retrieves the RGB values for actual colors in the
- device's color table.
-
- GpiRealizeColorTable Not supported in the current release of Presentation
- Manager for MS OS/2.
-
- GpiUnrealizeColorTable Not supported in the current release of
- Presentation Manager for MS OS/2.
-
- GpiSetBackColor Sets the background color for line, character, marker,
- and bitmap operations.
-
- GpiSetBackMix Sets the background mix mode for line, character, marker,
- and bitmap operations.
-
- GpiSetColor Sets the foreground color for line, character, marker, and
- bitmap operations.
-
- GpiSetMix Sets the foreground mix mode for line, character, marker, and
- bitmap operations.
-
-
-
- ────────────────────────────────────────────────────────────────────────────
- Chapter 35 Paths
-
- 35.1 Introduction
- 35.2 About Paths
- 35.2.1 Geometric Lines
- 35.2.2 Polygons and Other Shapes
- 35.2.3 Fill Modes
- 35.2.3.1 Alternate Mode
- 35.2.3.2 Winding Mode
- 35.2.4 Clip Paths
- 35.3 Using Paths
- 35.3.1 Drawing a Geometric Line
- 35.3.2 Drawing a Filled Polygon
- 35.3.3 Creating a Clip Path
- 35.4 Summary
-
- 35.1 Introduction
-
- This chapter describes a graphics object called a path. You should also be
- familiar with the following topics:
-
- ■ Presentation spaces and device contexts
-
- ■ Line and arc primitives
-
- ■ Color and mix modes
-
- ■ Area primitives
-
- ■ Clipping
-
-
- 35.2 About Paths
-
- A path is a figure that is filled or outlined. You can use paths to draw
- geometric (wide) lines, create nonrectangular clipping regions, and
- outline and/or fill irregular shapes and polygons.
-
- Paths provide the only means of drawing lines that are wider than one pel
- (pixel); the only means of clipping to circular, elliptical, or other
- nonrectangular regions; and the only means of generating filled or
- outlined irregular shapes and polygons (including triangles, trapezoids,
- rhomboids, and other nonrectangular regions). To generate filled or
- outlined rectangles, you can use the GpiBox function, and to generate
- filled or outlined circles and ellipses, you can use the GpiFullArc
- function.
-
- A path is similar to another graphics object called an area, but there are
- fundamental differences between the two objects. The interior of an area
- is always filled, while the interior of a path can be empty. Even when the
- interior of a path is empty, the borders are visible. Paths with empty
- interiors are called stroked paths because their visible borders are
- drawn, or "stroked." Another difference is in the use of paths and areas.
- Applications perform clipping operations by using paths but not by using
- areas. For more information about areas, see Chapter 36, "Area
- Primitives."
-
- There are two operations that an application can perform on a path: stroke
- and fill. You use a stroked path to draw geometric lines and to outline
- polygons. You use a filled path to fill the interior of polygons. Figure
- 35.1 shows a rectangle that is drawn first as a stroked path and then as
- a filled path:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 35.1 can be found in Section 35.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 35.1 Stroked and Filled Rectangles
-
- When MS OS/2 strokes a path, it generates a geometric line along the
- original line that defined the path. The end result is like the stroke of
- a brush. When MS OS/2 fills a path, it fills the region surrounded by the
- original line that defined the path. If this original line did not close
- the region, MS OS/2 automatically closes the region and fills the path.
-
- The functions that generate a path are always enclosed in a path bracket.
- The GpiBeginPath function defines the beginning of a path bracket, and the
- GpiEndPath function defines the end of a path bracket. The functions you
- can use within a path bracket are as follows:
-
- ■ GpiBeginElement
-
- ■ GpiBox
-
- ■ GpiCallSegmentMatrix
-
- ■ GpiCharString
-
- ■ GpiCharStringAt
-
- ■ GpiCharStringPos
-
- ■ GpiCharStringPosAt
-
- ■ GpiCloseFigure
-
- ■ GpiComment
-
- ■ GpiCreateLogFont
-
- ■ GpiDeleteElement (retain mode only)
-
- ■ GpiDeleteElementRange (retain mode only)
-
- ■ GpiDeleteElementsBetweenLabels (retain mode only)
-
- ■ GpiDeleteSetId
-
- ■ GpiElement
-
- ■ GpiEndElement
-
- ■ GpiEndPath
-
- ■ GpiFullArc
-
- ■ GpiGetData
-
- ■ GpiLabel
-
- ■ GpiLine
-
- ■ GpiMarker
-
- ■ GpiMove
-
- ■ GpiOffsetElementPointer
-
- ■ GpiPartialArc
-
- ■ GpiPointArc
-
- ■ GpiPolyFillet
-
- ■ GpiPolyFilletSharp
-
- ■ GpiPolyLine
-
- ■ GpiPolyMarker
-
- ■ GpiPolySpline
-
- ■ GpiPop
-
- ■ GpiPutData
-
- ■ GpiQueryArcParams (not valid in retain mode)
-
- ■ GpiQueryAttrMode
-
- ■ GpiQueryCurrentPosition (not valid in retain mode)
-
- ■ GpiSetArcParams
-
- ■ GpiSetAttrMode
-
- ■ GpiSetAttrs
-
- ■ GpiSetCharAngle
-
- ■ GpiSetCharBox
-
- ■ GpiSetCharDirection
-
- ■ GpiSetCharMode
-
- ■ GpiSetCharSet
-
- ■ GpiSetCharShear
-
- ■ GpiSetColor
-
- ■ GpiSetCp
-
- ■ GpiSetCurrentPosition
-
- ■ GpiSetEditMode
-
- ■ GpiSetElementPointer (not valid in retain mode)
-
- ■ GpiSetElementPointerAtLabel (not valid in retain mode)
-
- ■ GpiSetLineEnd
-
- ■ GpiSetLineJoin
-
- ■ GpiSetLineType
-
- ■ GpiSetLineWidth
-
- ■ GpiSetMarker
-
- ■ GpiSetMarkerBox
-
- ■ GpiSetMarkerSet
-
- ■ GpiSetMix
-
- ■ GpiSetModelTransformMatrix
-
- 35.2.1 Geometric Lines
-
- A geometric line is a stroked path that your application can scale by
- using one of the scaling transformations. Geometric lines can be wider
- than one pel. When you draw geometric lines, you use the same functions
- you would use to draw normal lines: GpiMove, GpiLine, GpiPolyLine,
- GpiPartialArc, and so on. But you must enclose these functions in a path
- bracket.
-
- In the floor plan shown in Figure 35.2, the outer walls were drawn using
- geometric lines. All of the other objects were drawn using normal lines.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 35.2 can be found in Section 35.2.1 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 35.2 Geometric Lines and Normal Lines
-
- After constructing a path bracket for a geometric line, you must specify a
- line-end style, a line-join style, and a line width. To specify the
- line-end style, you call the GpiSetLineEnd function; to specify the
- line-join style, you call the GpiSetLineJoin function; and to specify the
- line width, you call the GpiSetLineWidthGeom function. Once you have
- completed these steps, you can draw the line by calling the GpiStrokePath
- function.
-
- 35.2.2 Polygons and Other Shapes
-
- As noted earlier, the GpiFullArc function can generate filled or outlined
- circles and ellipses, and the GpiBox function can generate filled or
- outlined rectangles. But to generate filled or outlined regions that are
- not circular, elliptical, or rectangular, you should use the path
- functions.
-
- Figure 35.3 shows outlines of a trapezoid, a rhomboid, and a rhombus,
- each constructed by calling the GpiBeginPath, GpiPolyLine, GpiEndPath, and
- GpiStrokePath functions:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 35.3 can be found in Section 35.2.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 35.3 Stroked Paths
-
- Figure 35.4 shows the same quadrilaterals, only this time they were
- filled by calling the GpiFillPath function:
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 35.4 can be found in Section 35.2.2 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 35.4 Filled Paths
-
- 35.2.3 Fill Modes
-
- To fill a path, MS OS/2 uses one of two methods, called fill modes. You
- can select the mode──either alternate or winding──when you call
- GpiFillPath. If the path consists of multiple intersecting regions, the
- mode will affect the final appearance of the path. Figure 35.5 shows two
- identical paths that were filled using the two modes. Each path consists
- of a triangle drawn within a rectangle. The path on the left was filled
- using the alternate mode, the path on the right was filled using the
- winding mode.
-
- ┌────────────────────────────────────────────────────────────────────────┐
- │ Figure 35.5 can be found in Section 35.2.3 of the printed manual. │
- └────────────────────────────────────────────────────────────────────────┘
-
- Figure 35.5 Fill Modes
-
- 35.2.3.1 Alternate Mode
-
- When an application specifies the alternate mode, MS OS/2 performs a test
- on pels inside the path's boundary lines. This test involves the following
- steps:
-
- 1. Select a pel within the path's boundary lines.
-
- 2. Draw an imaginary ray, in the positive x-direction, from that pel
- towards infinity.
-
- 3. Highlight the pel if the ray intersects the boundary lines of the path
- an odd number of times.
-
- Figure 35.6 shows how MS OS/2 would perform this test on the path shown
- in Figure 35.5:
-
- ┌──────