home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft_Programmers_Library.7z / MPL / os2 / prgmr1.txt < prev    next >
Encoding:
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.
  1.  Microsoft Operating System/2: Programmer's Reference Volume 1
  2.  
  3.  
  4.  ══════════════════════════════════════════════════════════════════════════
  5.  
  6.  
  7.  Microsoft(R) Operating System/2: Programmer's Reference Volume 1
  8.  
  9.  Version 1.1
  10.  
  11.  
  12.  ══════════════════════════════════════════════════════════════════════════
  13.  
  14.  
  15.    Information in this document is subject to change without notice and does
  16.    not represent a commitment on the part of Microsoft Corporation. The
  17.    software and/or databases described in this document are furnished under a
  18.    license agreement or nondisclosure agreement. The software and/or
  19.    databases may be used or copied only in accordance with the terms of the
  20.    agreement. The purchaser may make one copy of the software for backup
  21.    purposes. No part of this manual and/or database may be reproduced or
  22.    transmitted in any form or by any means, electronic or mechanical,
  23.    including photocopying, recording, or information storage and retrieval
  24.    systems, for any purpose other than the purchaser's personal use, without
  25.    the written permission of Microsoft Corporation.
  26.  
  27.    (C) Copyright Microsoft Corporation, 1989. All rights reserved.
  28.  
  29.    Printed in the United States of America.
  30.  
  31.    Writers:  Brad Hastings
  32.              Stan Krute
  33.              Donn Morse
  34.              Ralph Walden
  35.              Dan Weston
  36.  
  37.    The character-set tables in this manual are reprinted by permission from
  38.    the IBM Operating System/2 User's Reference, (C) 1987 by International
  39.    Business Machines Corporation.
  40.  
  41.    Microsoft(R), MS(R), MS-DOS(R), and the Microsoft logo are registered
  42.    trademarks of Microsoft Corporation.
  43.  
  44.    IBM(R), Personal System/2(R), and PS/2(R) are registered trademarks of
  45.    International Business Machines Corporation.
  46.  
  47.    Intel(R) is a registered trademark of Intel Corporation.
  48.  
  49.    PostScript(R) is a registered trademark of Adobe Systems, Inc.
  50.  
  51.    Document No. LN0702A-110-I00-0289
  52.  
  53.  
  54.  
  55.  ────────────────────────────────────────────────────────────────────────────
  56.  Contents
  57.  
  58.  
  59.  PART 1  Introducing MS OS/2
  60.  
  61.  
  62.  Chapter 1  Introduction
  63.         1.1     Overview
  64.         1.2     About the MS OS/2 Programmer's Reference
  65.         1.3     How to Use This Manual
  66.         1.4     MS OS/2 and the C Programming Language
  67.         1.5     MS OS/2 Naming Conventions
  68.         1.6     Notational Conventions
  69.  
  70.  Chapter 2  MS OS/2 Overview
  71.         2.1     Introduction
  72.         2.2     MS OS/2 and Presentation Manager
  73.         2.3     The Window Manager
  74.         2.4     The Graphics Programming Interface
  75.         2.5     System Services
  76.         2.6     The MS OS/2 System Functions
  77.  
  78.  Chapter 3  MS OS/2 Programming Models
  79.         3.1     Introduction
  80.         3.2     Full-Screen Programs
  81.         3.3     Presentation Manager Applications
  82.         3.4     The Family Application Programming Interface
  83.         3.5     Using the Command Line
  84.         3.6     Using Structures
  85.         3.7     Using Bit Masks
  86.         3.8     Sharing Resources
  87.         3.9     C-Language Header Files
  88.  
  89.  PART 2  Window Manager
  90.  
  91.  
  92.  Chapter 4  Windows
  93.         4.1     Introduction
  94.         4.2     About Windows
  95.         4.3     System-Modal Windows
  96.         4.4     Using Windows
  97.         4.5     Summary
  98.  
  99.  Chapter 5  Messages and Message Queues
  100.         5.1     Introduction
  101.         5.2     About Messages and Message Queues
  102.         5.3     Using Messages in an Application
  103.         5.4     Summary
  104.  
  105.  Chapter 6  Window Classes
  106.         6.1     Introduction
  107.         6.2     About Window Classes
  108.         6.3     Using Window Classes
  109.         6.4     Summary
  110.  
  111.  Chapter 7  Window Procedures
  112.         7.1     Introduction
  113.         7.2     About Window Procedures
  114.         7.3     Using a Window Procedure
  115.         7.4     Summary
  116.  
  117.  Chapter 8  Mouse and Keyboard Input
  118.         8.1     Introduction
  119.         8.2     About Mouse and Keyboard Input
  120.         8.3     Using the Mouse and Keyboard in an Application
  121.         8.4     Summary
  122.  
  123.  Chapter 9  Frame Windows
  124.         9.1     Introduction
  125.         9.2     About Frame Windows
  126.         9.3     Using Frame Windows
  127.         9.4     Summary
  128.  
  129.  Chapter 10  Control Windows
  130.         10.1    Introduction
  131.         10.2    About Control Windows
  132.         10.3    Using Control Windows in an Application
  133.         10.4    Creating a Custom Control Window
  134.         10.5    Summary
  135.  
  136.  Chapter 11  Title-Bar Controls
  137.         11.1    Introduction
  138.         11.2    About Title Bars
  139.         11.3    Using Title-Bar Controls in Applications
  140.         11.4    Default Title-Bar Behavior
  141.         11.5    Summary
  142.  
  143.  Chapter 12  Button Controls
  144.         12.1    Introduction
  145.         12.2    About Button Controls
  146.         12.3    Using Button Controls in an Application
  147.         12.4    Default Button Behavior
  148.         12.5    Summary
  149.  
  150.  Chapter 13  Entry-Field Controls
  151.         13.1    Introduction
  152.         13.2    About Entry-Field Controls
  153.         13.3    Using Entry-Field Controls in an Application
  154.         13.4    Default Entry-Field Behavior
  155.         13.5    Summary
  156.  
  157.  Chapter 14  List-Box Controls
  158.         14.1    Introduction
  159.         14.2    About List Boxes
  160.         14.3    Using a List Box in an Application
  161.         14.4    Default List-Box Behavior
  162.         14.5    Summary
  163.  
  164.  Chapter 15  Static Controls
  165.         15.1    Introduction
  166.         15.2    About Static Controls
  167.         15.3    Using Static Controls in an Application
  168.         15.4    Default Static-Control Behavior
  169.         15.5    Summary
  170.  
  171.  Chapter 16  Scroll-Bar Controls
  172.         16.1    Introduction
  173.         16.2    About Scroll Bars
  174.         16.3    Using Scroll Bars
  175.         16.4    Summary
  176.  
  177.  Chapter 17  Menus
  178.         17.1    Introduction
  179.         17.2    About Menus
  180.         17.3    Defining Menu Items in a Resource File
  181.         17.4    Menu Data Structures
  182.         17.5    Using Menus in your Applications
  183.         17.6    Summary
  184.  
  185.  Chapter 18  Accelerator Tables
  186.         18.1    Introduction
  187.         18.2    About Accelerator Tables
  188.         18.3    Accelerator Tables in a Resource-Definition File
  189.         18.4    Accelerator-Table Data Structures
  190.         18.5    Using an Accelerator Table in an Application
  191.         18.6    Summary
  192.  
  193.  Chapter 19  Dialog Windows
  194.         19.1    Introduction
  195.         19.2    About Dialog Windows
  196.         19.3    Dialog Data Structures
  197.         19.4    Dialog Resources
  198.         19.5    Using Message and Dialog Boxes
  199.         19.6    Summary
  200.  
  201.  Chapter 20  Painting and Drawing
  202.         20.1    Introduction
  203.         20.2    About Painting and Drawing
  204.         20.3    Strategies for Painting and Drawing
  205.         20.4    Printing
  206.         20.5    Summary
  207.  
  208.  Chapter 21  Drawing in Windows
  209.         21.1    Introduction
  210.         21.2    Window-Drawing Functions
  211.         21.3    Using Window-Drawing Functions
  212.         21.4    Summary
  213.  
  214.  Chapter 22  Mouse Pointers and Icons
  215.         22.1    Introduction
  216.         22.2    About Mouse Pointers
  217.         22.3    Using a Mouse Pointer in an Application
  218.         22.4    Summary
  219.  
  220.  Chapter 23  Cursors
  221.         23.1    Introduction
  222.         23.2    About Cursors
  223.         23.3    Using Cursors in an Application
  224.         23.4    Summary
  225.  
  226.  Chapter 24  Printing
  227.         24.1    Introduction
  228.         24.2    About Printing
  229.         24.3    Printing
  230.         24.4    Special Printing Topics
  231.         24.5    Summary
  232.  
  233.  Chapter 25  Heaps
  234.         25.1    Introduction
  235.         25.2    About Heaps
  236.         25.3    Using a Heap in an Application
  237.         25.4    Summary
  238.  
  239.  Chapter 26  Clipboard
  240.         26.1    Introduction
  241.         26.2    About the Clipboard
  242.         26.3    Using the Clipboard
  243.         26.4    Summary
  244.  
  245.  Chapter 27  Dynamic Data Exchange
  246.         27.1    Introduction
  247.         27.2    About Dynamic Data Exchange
  248.         27.3    Using Dynamic Data Exchange
  249.         27.4    Summary
  250.  
  251.  Chapter 28  Hooks
  252.         28.1    Introduction
  253.         28.2    About Hooks
  254.         28.3    Types of Hooks
  255.         28.4    Using Hooks
  256.         28.5    Hook Example
  257.         28.6    Summary
  258.  
  259.  Chapter 29  Help
  260.         29.1    Introduction
  261.         29.2    About Help
  262.         29.3    Using Help in an Application
  263.         29.4    Summary
  264.  
  265.  PART 3  Graphics Programming Interface
  266.  
  267.  
  268.  Chapter 30  Presentation Spaces and Device Contexts
  269.         30.1    Introduction
  270.         30.2    About Presentation Spaces and Device Contexts
  271.         30.3    Using Presentation Spaces and Device Contexts
  272.         30.4    Summary
  273.  
  274.  Chapter 31  Coordinate Spaces and Transformations
  275.         31.1    Introduction
  276.         31.2    About Coordinate Spaces and Transformations
  277.         31.3    Using Coordinate Spaces and Transformations
  278.         31.4    Summary
  279.  
  280.  Chapter 32  Line and Arc Primitives
  281.         32.1    Introduction
  282.         32.2    About Line and Arc Primitives
  283.         32.3    Using Line and Arc Primitives
  284.         32.4    Summary
  285.  
  286.  Chapter 33  Fonts and Character Primitives
  287.         33.1    Introduction
  288.         33.2    About Fonts and Character Primitives
  289.         33.3    Using Fonts and Character Primitives
  290.         33.4    Summary
  291.  
  292.  Chapter 34  Color and Mix Modes
  293.         34.1    Introduction
  294.         34.2    About Color and Mix Modes
  295.         34.3    Using Colors and Mix Modes
  296.         34.4    Summary
  297.  
  298.  Chapter 35  Paths
  299.         35.1    Introduction
  300.         35.2    About Paths
  301.         35.3    Using Paths
  302.         35.4    Summary
  303.  
  304.  Chapter 36  Area Primitives
  305.         36.1    Introduction
  306.         36.2    About Areas and Area Primitives
  307.         36.3    Using Areas and Area Primitives
  308.         36.4    Summary
  309.  
  310.  Chapter 37  Marker Primitives
  311.         37.1    Introduction
  312.         37.2    About Marker Primitives
  313.         37.3    Using Markers
  314.         37.4    Summary
  315.  
  316.  Chapter 38  Bitmaps
  317.         38.1    Introduction
  318.         38.2    About Bitmaps
  319.         38.3    Using Bitmaps
  320.         38.4    Summary
  321.  
  322.  Chapter 39  Regions
  323.         39.1    Introduction
  324.         39.2    About Regions
  325.         39.3    Using Regions
  326.         39.4    Summary
  327.  
  328.  Chapter 40  Clipping
  329.         40.1    Introduction
  330.         40.2    About Clipping
  331.         40.3    Using Clipping
  332.         40.4    Summary
  333.  
  334.  Chapter 41  Metafiles
  335.         41.1    Introduction
  336.         41.2    About Metafiles
  337.         41.3    Using Metafiles
  338.         41.4    Summary
  339.  
  340.  Chapter 42  Segments and Retained Graphics
  341.         42.1    Introduction
  342.         42.2    About Segments and Retained Graphics
  343.         42.3    Using Segments and Retained Drawings
  344.         42.4    Summary
  345.  
  346.  PART 4  System Services
  347.  
  348.  
  349.  Chapter 43  Processes, Threads, and Sessions
  350.         43.1    Introduction
  351.         43.2    About Processes, Threads, and Sessions
  352.         43.3    Using Processes
  353.         43.4    Using Threads
  354.         43.5    Summary
  355.  
  356.  Chapter 44  The Memory Manager
  357.         44.1    Introduction
  358.         44.2    About the Memory Manager
  359.         44.3    Using the Memory Manager
  360.         44.4    Summary
  361.  
  362.  Chapter 45  Dynamic Linking
  363.         45.1    Introduction
  364.         45.2    About Dynamic Linking
  365.         45.3    Building Dynamic-Link Libraries
  366.         45.4    Using Dynamic Linking
  367.         45.5    Summary
  368.  
  369.  Chapter 46  The File System
  370.         46.1    Introduction
  371.         46.2    About the File System
  372.         46.3    Using the File System
  373.         46.4    Summary
  374.  
  375.  Chapter 47  Video Input and Output
  376.         47.1    Introduction
  377.         47.2    About Video Input and Output
  378.         47.3    Using Video Input and Output
  379.         47.4    Summary
  380.  
  381.  Chapter 48  Advanced Video Input and Output
  382.         48.1    Introduction
  383.         48.2    About Advanced Video Input and Output
  384.         48.3    Using Advanced Video Input and Output
  385.         48.4    Summary
  386.  
  387.  Chapter 49  The Mouse
  388.         49.1    Introduction
  389.         49.2    About the Mouse
  390.         49.3    Using the Mouse
  391.         49.4    Summary
  392.  
  393.  Chapter 50  The Keyboard
  394.         50.1    Introduction
  395.         50.2    About the Keyboard
  396.         50.3    Using the Keyboard
  397.         50.4    Summary
  398.  
  399.  Chapter 51  Interprocess Communication
  400.         51.1    Introduction
  401.         51.2    About Interprocess Communication
  402.         51.3    Using Interprocess Communication
  403.         51.4    Summary
  404.  
  405.  Chapter 52  Timers
  406.         52.1    Introduction
  407.         52.2    About Timers
  408.         52.3    Using Timers
  409.         52.4    Summary
  410.  
  411.  Chapter 53  Window Timers
  412.         53.1    Introduction
  413.         53.2    About Window Timers
  414.         53.3    Using Window Timers
  415.         53.4    Summary
  416.  
  417.  Chapter 54  Device Monitors
  418.         54.1    Introduction
  419.         54.2    About Device Monitors
  420.         54.3    Using Device Monitors
  421.         54.4    Summary
  422.  
  423.  Chapter 55  Atom Tables
  424.         55.1    Introduction
  425.         55.2    About Atom Tables
  426.         55.3    Using Atom Tables in an Application
  427.         55.4    Summary
  428.  
  429.  Chapter 56  System Information
  430.         56.1    Introduction
  431.         56.2    About System Information
  432.         56.3    Using System Information
  433.         56.4    Summary
  434.  
  435.  
  436.  ────────────────────────────────────────────────────────────────────────────
  437.  Figures
  438.  
  439.         Figure 2.1     A Typical Presentation Manager Window
  440.         Figure 11.1    Frame Window with Title Bar
  441.         Figure 12.1    Button Types
  442.         Figure 14.1    Typical List-Box Control
  443.         Figure 17.1    Menu-Bar and Pull-Down Menus
  444.         Figure 17.2    Submenus
  445.         Figure 19.1    Sample Message Box
  446.         Figure 19.2    Sample Dialog Box
  447.         Figure 20.1    Application-to-Device Path
  448.         Figure 20.2    Clip Region and Visible Region
  449.         Figure 20.3    Update Region and Visible Region
  450.         Figure 20.4    Cached-Micro Presentation Space
  451.         Figure 20.5    Micro Presentation Space
  452.         Figure 20.6    Normal Presentation Space
  453.         Figure 21.1    Rectangle Types
  454.         Figure 22.1    Bit Values in the AND and XOR Masks
  455.         Figure 24.1    Application to Device Path
  456.         Figure 24.2    World-Space to Device-Space Translation
  457.         Figure 24.3    Portrait-Mode Pages in World Space
  458.         Figure 24.4    Landscape-Mode Pages in World Space
  459.         Figure 24.5    IBM4201 Page Setup
  460.         Figure 25.1    Heap in Automatic Data Segment
  461.         Figure 25.2    Back Pointer for Moveable Heap Object in Automatic
  462.                         Data Segment
  463.         Figure 25.3    Back Pointer for Moveable Heap Object in Separate
  464.                         Data Segment
  465.         Figure 27.1    Typical DDE Segment
  466.         Figure 29.1    Help Menu Item
  467.         Figure 31.1    Device Coordinate System
  468.         Figure 31.2    Video Display and Single-Coordinate-Space System
  469.         Figure 31.3    Diagonal Line in a Single-Coordinate-Space System
  470.         Figure 31.4    One Rectangle Displayed on Two Different Devices
  471.         Figure 31.5    Fixed Value
  472.         Figure 31.6    Rotating an Object
  473.         Figure 31.7    Subpictures in Four Chained Segments in World Space
  474.         Figure 31.8    Two Model Spaces
  475.         Figure 31.9    Viewing Limit in Model Space
  476.         Figure 31.10   Retained Subpicture Drawn Using Model Transformations
  477.         Figure 31.11   Clip Path in World Space
  478.         Figure 31.12   Scaling the Clipped Part of a Subpicture in Model
  479.                         Space
  480.         Figure 31.13   Presentation Page in Page Space
  481.         Figure 31.14   Page Viewport in Device Space
  482.         Figure 31.15   Determining Scaling Factors
  483.         Figure 31.16   Translating the Page Viewport in Device Space
  484.         Figure 32.1    Sample Illustrations Using Line and Arc Functions
  485.         Figure 32.2    Arcs
  486.         Figure 32.3    Transforming the Unit Circle Using the Arc Parameters
  487.         Figure 32.4    Line Styles
  488.         Figure 33.1    Strokes
  489.         Figure 33.2    Serifs
  490.         Figure 33.3    Bold Font
  491.         Figure 33.4    Italic Font
  492.         Figure 33.5    Normal Font
  493.         Figure 33.6    Character Cell
  494.         Figure 33.7    Em Height
  495.         Figure 33.8    X Height
  496.         Figure 33.9    Maximum Ascender
  497.         Figure 33.10   Maximum Descender
  498.         Figure 33.11   Lowercase Ascent
  499.         Figure 33.12   Lowercase Descent
  500.         Figure 33.13   Internal Leading
  501.         Figure 33.14   External Leading
  502.         Figure 33.15   Em Increment
  503.         Figure 33.16   Maximum Baseline Extent
  504.         Figure 33.17   Character Slope
  505.         Figure 33.18   In-line Direction
  506.         Figure 33.19   Character Rotation
  507.         Figure 33.20   Superscript
  508.         Figure 33.21   Subscript
  509.         Figure 33.22   Image Font
  510.         Figure 33.23   Outline Font
  511.         Figure 33.24   Character-Cell Alignment
  512.         Figure 33.25   Proportional and Fixed Fonts
  513.         Figure 33.26   Code Page 437
  514.         Figure 33.27   Character Shear
  515.         Figure 33.28   Image Font and Character Shear
  516.         Figure 33.29   Image Font and Character Angle
  517.         Figure 33.30   Image Font and Three Sizes of Character Box
  518.         Figure 33.31   Outline Font and Character Shear
  519.         Figure 33.32   Outline Font and Character Angle
  520.         Figure 33.33   Outline Font and Three Sizes of Character Box
  521.         Figure 33.34   Graph with Outline Font
  522.         Figure 35.1    Stroked and Filled Rectangles
  523.         Figure 35.2    Geometric Lines and Normal Lines
  524.         Figure 35.3    Stroked Paths
  525.         Figure 35.4    Filled Paths
  526.         Figure 35.5    Fill Modes
  527.         Figure 35.6    Alternate-Mode Test
  528.         Figure 35.7    Winding-Mode Test
  529.         Figure 35.8    Triangular Clip Path
  530.         Figure 35.9    Geometric Line Ends
  531.         Figure 35.10   Geometric Line Joins
  532.         Figure 36.1    Two Areas
  533.         Figure 36.2    Disjoint Area
  534.         Figure 36.3    Predefined Fill Patterns
  535.         Figure 37.1    Default Marker Set
  536.         Figure 37.2    Markers Used in a Graph
  537.         Figure 38.1    Bitmap and Image
  538.         Figure 38.2    Bitmap Shown on Two Displays with Different Aspect
  539.                         Ratios
  540.         Figure 38.3    Bits and Pels in a Bitmapped Image
  541.         Figure 38.4    A Bitcount and its Associated Color Table
  542.         Figure 38.5    Bits and Pels in a Special Bitmapped Image
  543.         Figure 39.1    Disjoint Region
  544.         Figure 39.2    Region of Two Intersecting Rectangles
  545.         Figure 39.3    Text in Client Area
  546.         Figure 39.4    Disjoint Clip Region
  547.         Figure 39.5    Combining Regions
  548.         Figure 39.6    Three Square Regions and Three Fill Patterns
  549.         Figure 40.1    Text in an Elliptical Clipping Area
  550.         Figure 40.2    Valid Clipping Areas
  551.         Figure 40.3    Clipping in Four Coordinate Spaces
  552.         Figure 42.1    Combining Subpictures to Create a Floor Plan
  553.         Figure 42.2    Chained and Called Segments
  554.         Figure 42.3    Correlation Operation
  555.         Figure 42.4    Inserting a New Element in a Segment
  556.         Figure 42.5    Replacing an Element with a New Element
  557.         Figure 48.1    2-Byte Character Format
  558.         Figure 48.2    4-Byte Character Format
  559.  
  560.  
  561.  ────────────────────────────────────────────────────────────────────────────
  562.  Tables
  563.  
  564.         Table 30.1     Presentation-Space Features and Restrictions
  565.         Table 38.1     Drawing Modes and Bitmapped Output
  566.         Table 38.2     GpiBitBlt Output
  567.  
  568.  
  569.  
  570.  ────────────────────────────────────────────────────────────────────────────
  571.  PART 1  INTRODUCING MS OS/2
  572.  ────────────────────────────────────────────────────────────────────────────
  573.    Chapter 1  Introduction
  574.    Chapter 2  MS OS/2 Overview
  575.    Chapter 3  MS OS/2 Programming Models
  576.  
  577.  
  578.  
  579.  ────────────────────────────────────────────────────────────────────────────
  580.  Chapter 1  Introduction
  581.  
  582.         1.1     Overview
  583.         1.2     About the MS OS/2 Programmer's Reference
  584.         1.3     How to Use This Manual
  585.         1.4     MS OS/2 and the C Programming Language
  586.         1.5     MS OS/2 Naming Conventions
  587.         1.6     Notational Conventions
  588.  
  589.  
  590.  1.1  Overview
  591.  
  592.    This manual describes the Microsoft(R) Operating System/2 (MS(R) OS/2)
  593.    system functions. MS OS/2 is a single-user, multitasking operating system
  594.    for personal computers. MS OS/2 system functions let programs use the
  595.    operating system to carry out tasks such as reading from and writing to
  596.    disk files, allocating memory, and starting other programs.
  597.  
  598.    Part 1, "Introducing MS OS/2," introduces the MS OS/2 system functions. It
  599.    provides a brief description of the Microsoft Operating System/2
  600.    Programmer's Reference, describes the role of the C programming language
  601.    in the Programmer's Reference, and gives the calling and notational
  602.    conventions used in this manual. The chapters in this part provide a
  603.    general overview of the MS OS/2 system functions and describe the three MS
  604.    OS/2 programming models.
  605.  
  606.    Part 2, "Window Manager," describes the portion of MS OS/2 that lets
  607.    applications create and manage windows. The chapters in this part provide
  608.    detailed information about windows, messages, message queues, control
  609.    windows, dialog windows, and other window-management topics.
  610.  
  611.    Part 3, "Graphics Programming Interface," describes the portion of MS OS/2
  612.    that lets applications use device-independent graphics. The chapters in
  613.    this part provide detailed information about presentation spaces,
  614.    transformations, device contexts, graphics primitives, retained graphics,
  615.    metafiles, and other graphics-related topics.
  616.  
  617.    Part 4, "System Services," describes the portion of MS OS/2 that lets
  618.    applications use the basic multitasking services of MS OS/2. The chapters
  619.    in this part provide detailed information about processes and threads,
  620.    memory management, the file system, dynamic linking, keyboard and mouse
  621.    input, video output, device control, and other information about the
  622.    system.
  623.  
  624.    This manual is intended to describe the purpose of the MS OS/2 system
  625.    functions and to explain the operating-system concepts behind them. It
  626.    also shows how the MS OS/2 system functions work together to carry out
  627.    specific tasks. It does not show how to write, compile, and link programs
  628.    containing these functions. For more information on these topics, see
  629.    Microsoft Operating System/2 Programming Tools.
  630.  
  631.  
  632.  1.2  About the MS OS/2 Programmer's Reference
  633.  
  634.    The Microsoft Operating System/2 Programmer's Reference, a set of three
  635.    volumes, fully describes the MS OS/2 system functions and related data
  636.    types, macros, structures, messages, and file formats. The Programmer's
  637.    Reference is the source for specific information about programming for MS
  638.    OS/2.
  639.  
  640.    This manual, Volume 1 of the three-volume set, describes the purpose of
  641.    the MS OS/2 system functions and the concepts and principles behind the
  642.    functions. Volume 1 is intended for programmers new to MS OS/2 or learning
  643.    parts of MS OS/2 for the first time. This volume provides the basic
  644.    information needed for an understanding of MS OS/2.
  645.  
  646.    Volumes 2 and 3 consist of alphabetical listings of MS OS/2 system
  647.    functions and related data types, macros, structures, and messages. These
  648.    two volumes define the details of the syntax, parameters, and return
  649.    values of each MS OS/2 system function. Volumes 2 and 3 are intended to be
  650.    used by programmers already acquainted with MS OS/2 and who need only
  651.    specifics of particular functions.
  652.  
  653.  
  654.  1.3  How to Use This Manual
  655.  
  656.    This manual describes the MS OS/2 system functions in individual-topic
  657.    chapters. Each chapter describes the portion of MS OS/2 that lets an
  658.    application carry out a specific task or set of related tasks. For
  659.    example, the chapter on memory management defines the basic memory
  660.    management terms, describes the role of the memory-management functions,
  661.    and illustrates how to use those functions.
  662.  
  663.    Each chapter has three parts: a general description, programming samples,
  664.    and a summary. The general description contains a thorough discussion of
  665.    the purpose and operation of pertinent MS OS/2 functions. The programming
  666.    samples show how to use those MS OS/2 functions in applications to carry
  667.    out useful tasks. The summary briefly describes each function and message
  668.    described in the chapter.
  669.  
  670.    In many cases, the reader must have some basic knowledge of other portions
  671.    of MS OS/2 in order to understand the concepts described in the chapter.
  672.    Each chapter lists the prerequisite topics.
  673.  
  674.  
  675.  1.4  MS OS/2 and the C Programming Language
  676.  
  677.    The C programming language is the preferred development language for MS
  678.    OS/2 programs. Many of the programming features of MS OS/2 were designed
  679.    with C and other high-level languages in mind. MS OS/2 programs can also
  680.    be developed in Pascal, FORTRAN, BASIC, and assembly language, but C is
  681.    the most straightforward and easiest language to use to access MS OS/2
  682.    functions. For this reason, all syntax and program samples in this manual
  683.    are written in the C programming language.
  684.  
  685.    The MS OS/2 system functions use many types, macros, and structures that
  686.    are not part of standard C language. These types, macros, and structures
  687.    have been defined to make the task of creating MS OS/2 programs simpler
  688.    and to make program sources clearer and easier to understand.
  689.  
  690.    All types, macros, and structures discussed in this manual are defined in
  691.    the MS OS/2 C-language include files. Programmers may wish to use these
  692.    include files when developing MS OS/2 programs in other computer languages
  693.    such as Pascal or assembly language. If include files for a given language
  694.    are not available, a programmer can translate the definitions by following
  695.    the guidelines given in Volumes 2 and 3 of the Programmer's Reference.
  696.  
  697.    Many chapters in this manual include program examples. These examples show
  698.    how to use MS OS/2 system functions to accomplish simple tasks. In nearly
  699.    all cases, the examples are code fragments, not complete programs. A code
  700.    fragment is intended to show the context in which a function can be used;
  701.    it often assumes that variables, structures, and constants used in the
  702.    example have been defined and/or initialized. A code fragment may also use
  703.    comments to represent a task instead of giving the actual statements.
  704.  
  705.    Although the examples are not complete, you can use them in your programs
  706.    by taking the following steps:
  707.  
  708.    ■  Include the os2.h file in your program.
  709.  
  710.    ■  Define the appropriate include constants for the functions, structures,
  711.       and constants used in the example.
  712.  
  713.    ■  Define and initialize all variables.
  714.  
  715.    ■  Replace comments that represent tasks with appropriate statements.
  716.  
  717.    ■  Check return values for errors and take appropriate actions.
  718.  
  719.    Some examples in this manual combine both MS OS/2 and C run-time functions
  720.    to carry out their tasks.
  721.  
  722.  
  723.  1.5  MS OS/2 Naming Conventions
  724.  
  725.    In this manual, all parameter, variable, structure, field, and constant
  726.    names conform to MS OS/2 naming conventions. MS OS/2 naming conventions
  727.    are rules that define how to create names that indicate both the purpose
  728.    and data type of an item used with MS OS/2 system functions. These naming
  729.    conventions are used in this manual to help you readily identify the
  730.    purpose and type of the function parameters, structure fields, and
  731.    variables. These conventions are also used in most MS OS/2 sample program
  732.    sources to make the sources more readable and informative.
  733.  
  734.    The following list briefly describes the MS OS/2 naming conventions:
  735.  
  736. ╓┌─┌──────────┌──────────────────────────────────────────────────────────────╖
  737.    Item       Convention
  738.    ──────────────────────────────────────────────────────────────────────────
  739.    Variable   All variable, parameter, and field names consist of up to three
  740.    Parameter  elements: a prefix, a base type, and a qualifier. The names
  741.    Field      always consist of at least a base type or a qualifier. In most
  742.               cases, the name also includes a prefix. The base type
  743.               identifies the data type of the item; the prefix specifies
  744.               additional information, such as whether the item is a pointer,
  745.               an array, or a count of bytes. The qualifier specifies the
  746.               purpose of the item. All letters in the prefix and base type
  747.               are lowercase. The letters in the qualifier are mixed-case
  748.               (both uppercase and lowercase). When naming variables, the
  749.               prefix and base type are optional for common integer types such
  750.               as SHORT and USHORT.
  751.  
  752.    Structure  All structure names consist of a word or phrase that specifies
  753.               the purpose of the structure. All letters in the structure name
  754.               are uppercase.
  755.  
  756.    Constant   All constant names consist of a prefix (derived from the name
  757.               of the function associated with the constant) and a word or
  758.    Item       Convention
  759.    ──────────────────────────────────────────────────────────────────────────
  760.              of the function associated with the constant) and a word or
  761.               phrase that specifies the meaning of the constant in terms of a
  762.               value, action, color, or condition. All letters in the constant
  763.               name are uppercase and an underscore (_) separates the prefix
  764.               from the rest of the name.
  765.  
  766.    Function   All function names consist of a three-letter system prefix and
  767.               a word or phrase that describes the action of the function.
  768.               Each word in the function name starts with an uppercase letter.
  769.               Verb and noun combinations, such as DosGetDateTime, are
  770.               recommended.
  771.    ──────────────────────────────────────────────────────────────────────────
  772.  
  773.  
  774.    The following examples show some of the standard prefix and base types you
  775.    will see in this manual:
  776.  
  777. ╓┌─┌───────────────┌───────────────────────────┌─────────────────────────────╖
  778.    Prefix/Base     Description                 Example
  779.    Prefix/Base     Description                 Example
  780.    type
  781.    ──────────────────────────────────────────────────────────────────────────
  782.    f               Boolean flag; TRUE if       BOOL fSuccess;
  783.                    successful
  784.    ch              8-bit character             CHAR chChar;
  785.  
  786.    s               16-bit signed integer       SHORT sRate;
  787.  
  788.    l               32-bit signed integer       LONG lDistance;
  789.  
  790.    uch             8-bit unsigned character    UCHAR uchScan;
  791.  
  792.    us              16-bit unsigned integer     USHORT usHeight;
  793.  
  794.    ul              32-bit unsigned integer     ULONG ulWidth;
  795.  
  796.    b               8-bit unsigned integer      BYTE bAttribute;
  797.  
  798.    sz              Zero-terminated array of    CHAR szName[];
  799.                    characters
  800.    Prefix/Base     Description                 Example
  801.    type
  802.    ──────────────────────────────────────────────────────────────────────────
  803.                   characters
  804.    fb              Array of flags in a byte    BYTE fbMask;
  805.  
  806.    fs              Array of flags in a short   USHORT fsMask;
  807.  
  808.    fl              Array of flags in a long    ULONG flMask;
  809.  
  810.    sel             16-bit segment selector     SEL selSegment;
  811.  
  812.    p               32-bit far pointer to a     PCH pchBuffer;
  813.                    given type
  814.    np              16-bit near pointer to a    NPCH npchBuffer;
  815.                    given type
  816.    a               Array of a given type       CHAR achData[1];
  817.  
  818.    i               Index to an array of a      USHORT ichIndex;
  819.                    given type
  820.    c               Count of items of a given   USHORT cb;
  821.    Prefix/Base     Description                 Example
  822.    type
  823.    ──────────────────────────────────────────────────────────────────────────
  824.   c               Count of items of a given   USHORT cb;
  825.                    type
  826.    hf              Handle identifying a given  HFILE hf;
  827.                    object
  828.    off             Offset                      USHORT offSeg;
  829.  
  830.    id              Identifier for a given      USHORT idSession;
  831.                    object
  832.    ──────────────────────────────────────────────────────────────────────────
  833.  
  834.  
  835.  
  836.  1.6  Notational Conventions
  837.  
  838.    The following notational conventions are used throughout this manual:
  839.  
  840.    Convention      Meaning
  841.    ──────────────────────────────────────────────────────────────────────────
  842.    bold            Bold type is used for keywords──for example, the names of
  843.                    functions, data types, structures, and macros. These names
  844.                    are spelled exactly as they should appear in source
  845.                    programs.
  846.  
  847.    italics         Italic type is used to indicate the name of an argument;
  848.                    this name must be replaced by an actual argument. Italics
  849.                    are also used to show emphasis in text.
  850.  
  851.    this font       This font is used for example program-code fragments.
  852.    ──────────────────────────────────────────────────────────────────────────
  853.  
  854.  
  855.  
  856.  ────────────────────────────────────────────────────────────────────────────
  857.  Chapter 2  MS OS/2 Overview
  858.  
  859.         2.1     Introduction
  860.         2.2     MS OS/2 and Presentation Manager
  861.             2.2.1     Queued Input
  862.             2.2.2     Device-Independent Graphics
  863.             2.2.3     Shared Resources
  864.         2.3     The Window Manager
  865.             2.3.1     Windows
  866.             2.3.2     Menus
  867.             2.3.3     Dialog Windows
  868.             2.3.4     The Message Loop
  869.         2.4     The Graphics Programming Interface
  870.             2.4.1     Presentation Spaces and Device Contexts
  871.             2.4.2     Graphics Primitives
  872.             2.4.3     Other Graphics Tools
  873.             2.4.4     Drawing
  874.             2.4.5     Retained Graphics and Segments
  875.             2.4.6     Metafiles
  876.         2.5     System Services
  877.             2.5.1     Multitasking
  878.             2.5.2     Dynamic Linking
  879.             2.5.3     Memory Management
  880.             2.5.4     The File System
  881.             2.5.5     Full-Screen Keyboard, Mouse, and Video Operations
  882.             2.5.6     Interprocess Communication
  883.         2.6     The MS OS/2 System Functions
  884.  
  885.  2.1  Introduction
  886.  
  887.    This chapter is an overview of the features of Microsoft Operating
  888.    System/2. The most important of these features are the graphical user
  889.    interface and device-independent graphics provided by the MS OS/2
  890.    Presentation Manager and the multitasking and other system services
  891.    provided by the MS OS/2 base. In particular, this overview describes the
  892.    following:
  893.  
  894.    ■  MS OS/2 and Presentation Manager
  895.  
  896.    ■  The window manager
  897.  
  898.    ■  The graphics programming interface (GPI)
  899.  
  900.    ■  The system services
  901.  
  902.    ■  The MS OS/2 system functions
  903.  
  904.  
  905.  2.2  MS OS/2 and Presentation Manager
  906.  
  907.    In a multitasking environment, it is important to give all applications
  908.    some portion of the screen through which they can interact with the user.
  909.    One of the principal goals of MS OS/2 is to provide visual access to most,
  910.    if not all, applications at the same time. This access can be granted
  911.    either by giving selected applications full use of the screen while other
  912.    applications wait in the background or by letting applications share the
  913.    screen. In MS OS/2, each application decides which method to use by
  914.    choosing a "session" to run in. The session dictates whether the
  915.    application receives complete control of the screen or must share it with
  916.    other applications.
  917.  
  918.    When MS OS/2 first starts, it creates the Presentation Manager session.
  919.    All applications in this session share the screen. Applications that run
  920.    in this session are called Presentation Manager applications, since
  921.    Presentation Manager is the portion of MS OS/2 that creates and manages
  922.    the Presentation Manager session. When a new application starts, it can
  923.    direct the system to create a new session for it. The new session gives
  924.    complete control of the screen to the application. Applications that use
  925.    the full screen are called full-screen applications.
  926.  
  927.    A Presentation Manager application shares the display with other
  928.    applications by using a "window" for interaction with the user. Basically,
  929.    a window is a rectangular portion of the system display that the system
  930.    grants to an application. However, a window is also a combination of
  931.    visual devices, such as menus, controls, and scroll bars, with which the
  932.    user directs the actions of the application.
  933.  
  934.    A Presentation Manager application must create its own window before
  935.    producing any output or receiving any input. Once the application creates
  936.    its window, MS OS/2 provides the application with detailed information
  937.    about what the user is doing with the window and automatically carries out
  938.    many of the tasks the user requests, such as moving and sizing the window.
  939.  
  940.    A Presentation Manager application can create and use any number of
  941.    windows to display information in a variety of ways. The system manages
  942.    the screen, controlling the placement and display of windows and ensuring
  943.    that no two applications attempt to access the same part of the system
  944.    display at the same time. (In the latter case, the system overlaps the
  945.    window of one application with the window of the other.)
  946.  
  947.  2.2.1  Queued Input
  948.  
  949.    In traditional programming environments, a program reads from the keyboard
  950.    by making an explicit call to a function (getchar, for example). The
  951.    function typically waits until the user presses a key before returning the
  952.    character code to the program. A Presentation Manager application does not
  953.    make explicit calls to read from the keyboard. Instead, MS OS/2 receives
  954.    all input from the keyboard, mouse, and timer into its system queue and
  955.    automatically redirects the input to the application by copying it from
  956.    the system queue to the application queue. When the application is ready
  957.    to retrieve input, it reads from its queue and dispatches the message to
  958.    the appropriate window.
  959.  
  960.    In Presentation Manager, input from the keyboard and mouse is provided
  961.    automatically to every window that is created. MS OS/2 provides input in a
  962.    uniform format called an input message. This message contains information
  963.    about the input that far exceeds the information available in other
  964.    environments. An input message specifies the system time, the position of
  965.    the mouse, the state of the keyboard, the scan code of the key (if a key
  966.    is pressed), the number of the mouse button (if a button is pressed), and
  967.    the device that generated the message. For example, the keyboard message
  968.    WM_CHAR corresponds to a press or release of a specific key. In each
  969.    message, MS OS/2 provides a device-independent virtual-key code that
  970.    identifies the key, as well as the device-dependent scan code generated by
  971.    the keyboard. The message also specifies the status of other keys on the
  972.    keyboard, such as SHIFT, CTRL, and NUMLOCK. Keyboard, mouse, and timer
  973.    messages all have the same format and are processed in the same manner.
  974.  
  975.  2.2.2  Device-Independent Graphics
  976.  
  977.    In Presentation Manager, you have access to a rich set of
  978.    device-independent graphics operations. This means that your applications
  979.    can easily draw lines, rectangles, circles, and complex regions, and can
  980.    use the same calls and data to draw on a high-resolution graphics display
  981.    as they use to draw on a dot-matrix printer.
  982.  
  983.    MS OS/2 requires device drivers to convert graphics-output requests to
  984.    output for a printer, plotter, display, or other output device. A device
  985.    driver is a special executable library that an application can load and
  986.    use to carry out graphics operations in the "context" of the specific
  987.    device──that is, the device driver, the output device, and the
  988.    communications port.
  989.  
  990.  2.2.3  Shared Resources
  991.  
  992.    MS OS/2 is a multitasking system. This means that more than one
  993.    application can run at a time. Presentation Manager applications must
  994.    share the display, the keyboard, the mouse, and even the CPU with all
  995.    other applications that are currently running in the same session. For
  996.    this reason, MS OS/2 carefully controls these resources and requires
  997.    applications to use a specific program interface that guarantees this
  998.    control.
  999.  
  1000.  
  1001.  2.3  The Window Manager
  1002.  
  1003.    The MS OS/2 window manager consists of the MS OS/2 system functions that
  1004.    let applications create and manage windows and related elements. These
  1005.    related elements are primarily menus, dialog windows, and the message
  1006.    loop. The window manager provides the elements that your applications need
  1007.    to construct a graphical user interface.
  1008.  
  1009.  2.3.1  Windows
  1010.  
  1011.    A window is the primary input and output device of any Presentation
  1012.    Manager application. It is the application's only access to the system
  1013.    display, so, since nearly all Presentation Manager applications interact
  1014.    with the user in some way through the system display, these applications
  1015.    must use windows.
  1016.  
  1017.    A window is a rectangle on the system display. A typical window is
  1018.    composed of a title bar, a menu bar, scroll bars, borders, and other
  1019.    features. You list the features you want for a window when you create the
  1020.    window. MS OS/2 then draws and manages the window. Figure 2.1 shows the
  1021.    main features of a window:
  1022.  
  1023.    ┌────────────────────────────────────────────────────────────────────────┐
  1024.    │ Figure 2.1 can be found in Section 2.3.1 of the printed manual.        │
  1025.    └────────────────────────────────────────────────────────────────────────┘
  1026.  
  1027.    Figure 2.1  A Typical Presentation Manager Window
  1028.  
  1029.    Interestingly, most Presentation Manager user-interface elements are also
  1030.    windows, including menus, title bars, buttons, entry fields, icons, and
  1031.    scroll bars.
  1032.  
  1033.    Although an application creates a window and technically "owns" it, the
  1034.    management of the window is actually a collaborative effort between the
  1035.    application and the system. The system maintains the position and
  1036.    appearance of the window, manages the standard window features such as the
  1037.    border, scroll bars, and title, and carries out many tasks initiated by
  1038.    the user that directly affect the window. The application maintains
  1039.    everything else about the window──in particular, the client window, in
  1040.    which the application is free to display anything it wants.
  1041.  
  1042.    To manage this collaborative effort, MS OS/2 advises each window of
  1043.    changes that might affect it. Every window must have a corresponding
  1044.    window procedure that receives these window-management messages and
  1045.    responds appropriately. Window-management messages either specify actions
  1046.    for the function to take or request information from the function.
  1047.  
  1048.  2.3.2  Menus
  1049.  
  1050.    Menus are the principal means of user input for a Presentation Manager
  1051.    application. A menu is a list of commands that the user can view and
  1052.    choose from. When you create an application, you supply the menu name and
  1053.    the command names. MS OS/2 displays and manages the menus for you, sending
  1054.    a message to the window procedure when the user makes a choice. This
  1055.    message is the signal to carry out the command.
  1056.  
  1057.  2.3.3  Dialog Windows
  1058.  
  1059.    A dialog window is a temporary window that you can create to let the user
  1060.    supply more information for a command. A dialog window contains one or
  1061.    more controls. A control is a small window that has a very simple input or
  1062.    output function. The controls in a dialog window give the user a means of
  1063.    supplying filenames, choosing options, and otherwise directing the action
  1064.    of the command. For example, an entry-field control lets the user enter
  1065.    and edit text.
  1066.  
  1067.  2.3.4  The Message Loop
  1068.  
  1069.    Since your application receives input through a message queue, the chief
  1070.    feature of any Presentation Manager application is the message loop. The
  1071.    message loop retrieves input messages from the message queue and
  1072.    dispatches them to the appropriate windows.
  1073.  
  1074.    For example, MS OS/2 collects hardware input, in the form of messages, in
  1075.    its system queue. It then copies this input to the appropriate message
  1076.    queue. The message loop in the application retrieves a message from the
  1077.    message queue and dispatches it, through the system, to the appropriate
  1078.    window procedure. The window procedure can respond to an input message by
  1079.    calling MS OS/2 functions to carry out work in the window.
  1080.  
  1081.    For a more specific example, consider how the system and an application
  1082.    collaborate to process keyboard-input messages. The system receives
  1083.    keyboard input when the user presses and releases a key. The system copies
  1084.    the keyboard messages from the system queue to the application's message
  1085.    queue. The message loop retrieves the keyboard messages, translates them
  1086.    into ANSI-character WM_CHAR messages, and dispatches the WM_CHAR messages
  1087.    to the appropriate window procedure. The window procedure then uses the
  1088.    GpiCharString function to display the character in the client window.
  1089.  
  1090.    MS OS/2 sends window-management messages directly to a window (Win)
  1091.    function. For example, after MS OS/2 carries out a request to destroy a
  1092.    window, it sends a WM_DESTROY message directly to the window procedure,
  1093.    bypassing the message queue. The window procedure must then use the
  1094.    WinPostMsg function to copy a WM_QUIT message into the message queue,
  1095.    signaling the main function that the window is destroyed and that the
  1096.    application should terminate. When the message loop retrieves the WM_QUIT
  1097.    message, the loop terminates and the main function exits.
  1098.  
  1099.  
  1100.  2.4  The Graphics Programming Interface
  1101.  
  1102.    The graphics programming interface (GPI) consists of the MS OS/2 system
  1103.    functions that let you create device-independent graphics for your
  1104.    applications. The Gpi functions are used in conjunction with the window
  1105.    manager to draw lines, shapes, and text in a window. Applications can also
  1106.    use the Gpi functions to draw graphics output on such devices as raster
  1107.    printers and vector plotters.
  1108.  
  1109.  2.4.1  Presentation Spaces and Device Contexts
  1110.  
  1111.    A presentation space is the key to an application's access to the system
  1112.    display, to printers, and to other graphics-output devices. Conceptually,
  1113.    a presentation space is a device-independent space in which you can create
  1114.    and manipulate graphics for display. The presentation space defines your
  1115.    drawing environment by specifying the tools you have available to create
  1116.    graphics. These tools include the graphics primitives granted to every
  1117.    presentation space, as well as the bitmaps and fonts that your application
  1118.    loads for its exclusive use.
  1119.  
  1120.    Actually, a presentation space is little more than a data structure whose
  1121.    fields contain values that define the drawing environment. The values
  1122.    represent the colors, widths, styles, and other attributes of the graphics
  1123.    you draw. The system creates the data structure when you create the
  1124.    presentation space and initializes the structure to default values.
  1125.  
  1126.    You must create a presentation space to create graphics. You must also
  1127.    create a device context to display those graphics on a device. A device
  1128.    context is a bridge from a presentation space to a specific device. You
  1129.    create a device context by specifying the device you want to access and
  1130.    the type of access you want, such as direct or queued (for printing). You
  1131.    begin displaying graphics on the device by associating the device context
  1132.    with the presentation space. Once you have associated the device context,
  1133.    any lines, text, and images you draw in the presentation space are also
  1134.    displayed on the given device.
  1135.  
  1136.    Like a presentation space, a device context is a data structure. It
  1137.    contains information about the device driver that supports the specified
  1138.    device. The device driver interprets graphics commands sent to it from the
  1139.    presentation space and creates the corresponding commands for its device.
  1140.    It then sends the commands either directly to the device or to the
  1141.    spooler, depending on the type of access you gave the device context when
  1142.    you created it.
  1143.  
  1144.  2.4.2  Graphics Primitives
  1145.  
  1146.    In MS OS/2, graphics primitives are lines, arcs, markers, text, areas, and
  1147.    images. They are called primitives because you use them as the basic tools
  1148.    to create the documents, pictures, and other composite graphics that your
  1149.    applications display to the user.
  1150.  
  1151.    You draw a primitive by using a Gpi function. For example, to draw a line,
  1152.    you use the GpiLine function and specify the ending point of the line. The
  1153.    function uses the current point as the starting point for the line and
  1154.    draws from the starting point to the ending point. The current point is
  1155.    simply the ending point of the last primitive, unless you explicitly set
  1156.    the current point by using a function such as GpiMove.
  1157.  
  1158.    A line primitive is a straight line. An arc primitive is a curve. Curves
  1159.    can be arcs of a circle or of an ellipse, or they can be more complex
  1160.    curves such as splines and fillets. A marker primitive is a mark or
  1161.    character that you draw at a specific point. Markers are typically used to
  1162.    plot points in a graph. An area primitive is a closed figure that has been
  1163.    filled with a pattern. A common use for an area primitive is to represent
  1164.    a cross-section in a mechanical drawing. An image is a bitmapped image,
  1165.    with each bit representing the color of a pel (picture element) on the
  1166.    device. Images are often used for complex pictures that cannot easily be
  1167.    drawn.
  1168.  
  1169.    Every primitive has a corresponding set of primitive attributes. The
  1170.    attributes specify the color, style, size, and orientation of the
  1171.    primitive when your application draws it. The primitive attributes are
  1172.    given default values when you create the presentation space, so you can
  1173.    use the primitives immediately. However, you can reset the attributes at
  1174.    any time. You have the choice of changing the attributes for individual
  1175.    primitives or changing a specific attribute for all primitives. For
  1176.    example, you can set the color for all primitives by using the GpiSetColor
  1177.    function, or you can set it for just the line primitive by using the
  1178.    GpiSetAttrs function.
  1179.  
  1180.  2.4.3  Other Graphics Tools
  1181.  
  1182.    In addition to the graphics primitives, MS OS/2 provides graphics tools
  1183.    that you can use to draw graphics and to affect how the graphics are
  1184.    drawn. These tools are paths, bitmaps, clipping areas, transformations,
  1185.    and color tables.
  1186.  
  1187.    A path is a sequence of lines that you can use to create a filled area, a
  1188.    geometric line, or a clip path. A path is very much like an area
  1189.    primitive, in that you can use the path as a closed figure and fill it
  1190.    with a pattern. Unlike an area primitive, however, a path can be used to
  1191.    create geometric lines, sometimes called wide lines. Geometric lines are
  1192.    drawn, using a given width and pattern, so that they follow the outline
  1193.    specified by the path. Geometric lines give you a selection of line styles
  1194.    and patterns that are not available with the line primitive.
  1195.  
  1196.    A bitmap is an array of bits that represents an image that you can display
  1197.    on a raster output device. Bitmaps typically represent scanned images and
  1198.    icons and are very much like image primitives. Unlike an image primitive,
  1199.    however, a bitmap can have several different formats, each format
  1200.    specifying color information that an image primitive cannot contain. Also,
  1201.    bitmaps can be used to create fill patterns that you can use to fill
  1202.    figures created using paths and area primitives. Finally, bitmaps can be
  1203.    copied from one presentation space to another or even from one location to
  1204.    another within the same presentation space.
  1205.  
  1206.    A font is a collection of characters and symbols that you can use to draw
  1207.    text. Characters in a font belong to the same typeface and share
  1208.    stroke-width and serif characteristics. Some common fonts are 12-point
  1209.    Helvetica, 10-point Times Roman Bold, and 12-point Courier Italic. To use
  1210.    fonts in an application, you first create a logical font that describes
  1211.    the typeface and other characteristics that you want. Then you use the
  1212.    local identifier for the logical font to set that font as the current font
  1213.    for the presentation space. Subsequent text functions use the current font
  1214.    to draw text.
  1215.  
  1216.    Clipping is a process that limits graphics output to a specific region on
  1217.    the display or on a page of printer paper. You can use clipping with a
  1218.    presentation space by creating a clipping area. The clipping area is the
  1219.    region where output can appear. If an application attempts to draw output
  1220.    outside a clipping area, the system will "clip" the output, preventing it
  1221.    from appearing on the device. You can create a clipping area for a
  1222.    presentation space by setting the dimensions of the graphics field and
  1223.    viewing limits or by creating a clip path or clip region. The final
  1224.    clipping area is the intersection of these four possible clip regions.
  1225.  
  1226.    A transformation defines how the system should map the points in one
  1227.    coordinate space onto another coordinate space. Since all graphics
  1228.    primitives and other drawing tools use coordinate spaces, a transformation
  1229.    affects the way all graphics are drawn by your application. For example,
  1230.    you can use a transformation to move a figure from one place to another on
  1231.    the display or to rotate or adjust the size of the figure. Transformations
  1232.    are typically used to give the user different perspectives on a single
  1233.    drawing or to create rotated or sheared figures that would be
  1234.    time-consuming for the application to plot and draw.
  1235.  
  1236.    A logical color table is an array of colors that an application uses when
  1237.    drawing graphics. Any primitive or other graphic you draw has one of the
  1238.    colors given in the table. You specify a color by giving a color index.
  1239.    The index identifies the table entry defining the color you want. Every
  1240.    presentation space has a default color table when it is created, but you
  1241.    can create a new logical color table to replace the default table if you
  1242.    need other colors. Creating a new table associates the color indexes with
  1243.    whatever color you have specified in the corresponding table entry.
  1244.  
  1245.  2.4.4  Drawing
  1246.  
  1247.    You draw graphics by using the MS OS/2 drawing functions. A drawing
  1248.    function draws a primitive or other graphic, applying the primitive
  1249.    attributes and whatever information you supply to the function when you
  1250.    call it. For example, when drawing line primitives, the system applies the
  1251.    current line color and style. The style determines whether the line is
  1252.    solid or a series of dashes, dots, or both.
  1253.  
  1254.    Some attributes apply to all graphics primitives. For example, the
  1255.    foreground and background colors and mix modes affect all primitives. The
  1256.    foreground color defines the color of the primitive and the background
  1257.    color defines the color "behind" the primitive. For a line drawn using a
  1258.    dashed style, the dashes have the foreground color and the gaps between
  1259.    the dashes have the background color. The mix modes define how the
  1260.    foreground and background colors are combined with colors already on the
  1261.    display. The mix mode can cause the color to overpaint the existing color,
  1262.    leave it alone, or mix with it by using a binary operator such as the
  1263.    exclusive-OR operator.
  1264.  
  1265.    Some attributes are specific to a particular graphics primitive. For
  1266.    example, the arc parameters apply only to arcs. The arc parameters specify
  1267.    a transformation that maps a circle to another circle, ellipse, or similar
  1268.    shape. When you draw an arc, the system uses the shape defined by the
  1269.    transformed circle as the shape for your arc. You supply a multiplier to
  1270.    set the final size of the arc.
  1271.  
  1272.    A number of drawing functions use loadable resources to draw graphics. For
  1273.    example, the text-drawing functions, such as GpiCharString and
  1274.    GpiCharStringPos, can use a loaded font to draw text. To make a loadable
  1275.    resource available for these functions, you typically load the resource
  1276.    into memory and create a local identifier for the resource. For example,
  1277.    to use a font resource, you load it using the GpiLoadFonts function and
  1278.    then set the local identifier by using the GpiCreateLogFont function. Once
  1279.    you have a local identifier, you can set the resource to be the current
  1280.    resource by using a function such as GpiSetCharSet. Along with the
  1281.    text-drawing functions, the marker and area functions can use resources
  1282.    when they draw.
  1283.  
  1284.  2.4.5  Retained Graphics and Segments
  1285.  
  1286.    MS OS/2 lets you retain the graphics you draw in your application by
  1287.    storing them in retained segments. You create a retained segment by
  1288.    setting the drawing mode of the presentation space to DM_RETAIN or
  1289.    DM_DRAWANDRETAIN and opening the segment. All subsequent graphics are
  1290.    stored in the segment (and are also drawn on the device, if you specified
  1291.    DM_DRAWANDRETAIN). You can close the segment at any time and draw the
  1292.    contents by using a function such as GpiDrawSegment.
  1293.  
  1294.    Retained segments are useful for storing graphics that result from user
  1295.    input. Once stored, the graphics can be redrawn or edited at any time. An
  1296.    element pointer lets the application move to a specific graphics element
  1297.    in a segment. The element can then be drawn or replaced, or new elements
  1298.    can be inserted.
  1299.  
  1300.  2.4.6  Metafiles
  1301.  
  1302.    A metafile, created by using a special device context, is another method
  1303.    of storing graphics. In this case, you associate the metafile device
  1304.    context with the presentation space, draw the graphics you want in the
  1305.    metafile, and then disassociate the device context and close it. Closing
  1306.    the metafile returns a handle that you can use to save the metafile in a
  1307.    disk file.
  1308.  
  1309.    Metafiles are a useful way of transferring graphics images from one
  1310.    computer to another. An application can load a metafile from disk and play
  1311.    it into a presentation space. The presentation space can be associated
  1312.    with any device──display or printer. The graphics in the metafile are
  1313.    stored as graphics commands, not as a bitmap, so an application can
  1314.    examine and extract portions of the metafile if necessary.
  1315.  
  1316.  
  1317.  2.5  System Services
  1318.  
  1319.    The system services consist of all the MS OS/2 system functions that let
  1320.    you create processes and threads, access disk files and devices, allocate
  1321.    memory, and retrieve or set information about the system. In Presentation
  1322.    Manager applications, the system-service functions are typically used to
  1323.    carry out tasks for which no corresponding window-manager or Gpi function
  1324.    exists. In full-screen programs, system-service functions are used almost
  1325.    exclusively, even to interact with the user and access the devices of the
  1326.    computer.
  1327.  
  1328.  2.5.1  Multitasking
  1329.  
  1330.    Multitasking, one of the principal features of MS OS/2, is the ability of
  1331.    the system to manage the execution of more than one program at a time.
  1332.    This ability helps to optimize use of the computer, since time normally
  1333.    spent by a program waiting for user input is distributed to other programs
  1334.    that may be printing a document or recalculating a spreadsheet.
  1335.  
  1336.    MS OS/2 provides multitasking in the traditional sense of having more than
  1337.    one program run at a time, and it also extends this concept to permit a
  1338.    single program to run more than one copy of itself at the same time.
  1339.  
  1340.    Every program that has been loaded into memory and is running is called a
  1341.    process. Each copy of a process is called a thread. A process always has
  1342.    at least one thread, called the main thread or thread 1, and can create
  1343.    more threads. These additional threads are useful for carrying out tasks
  1344.    unrelated to the processing of the main thread. For example, a process may
  1345.    create a thread to write data to a disk file. This frees the main thread
  1346.    so that it can continue to process user input.
  1347.  
  1348.  2.5.2  Dynamic Linking
  1349.  
  1350.    Dynamic linking lets a program gain access at run time to functions that
  1351.    are not part of its executable code. These functions are contained in
  1352.    dynamic-link libraries──special program modules that contain executable
  1353.    code but cannot be run as programs. Instead, programs load the appropriate
  1354.    dynamic-link libraries and execute the code in the libraries by linking to
  1355.    them dynamically.
  1356.  
  1357.    Dynamic-link libraries are very common in MS OS/2. In fact, most of the
  1358.    system is contained in dynamic-link libraries. The chief advantage of
  1359.    dynamic-link libraries is that they reduce the amount of memory needed by
  1360.    a program. A program loads a library only if it needs to execute a
  1361.    function in the library. Once the library is loaded, the system also
  1362.    shares it with any other program that needs it. This means that only one
  1363.    copy of the library is ever loaded at any one time.
  1364.  
  1365.  2.5.3  Memory Management
  1366.  
  1367.    Programs can, at any time, allocate additional memory for their own use.
  1368.    MS OS/2 controls access to system memory through the use of selectors. A
  1369.    selector is a unique number identifying a specific segment in memory. When
  1370.    a program allocates a segment, it specifies the size of the segment (in
  1371.    bytes) and receives a selector for that segment. This selector can then be
  1372.    used to access the memory.
  1373.  
  1374.    MS OS/2 protects memory from unauthorized use. The process that allocates
  1375.    memory owns that memory, and no other process can access it. Attempting to
  1376.    access memory owned by another process causes a protection violation and
  1377.    usually terminates the process.
  1378.  
  1379.    If two processes need to share memory, a process can create shared memory
  1380.    and either pass the selector to the process that is to share the memory or
  1381.    pass the name of the shared segment to that process. When two processes
  1382.    share a segment, no protection violation occurs for them, but the memory
  1383.    remains protected from all other processes. The sharing processes must
  1384.    manage the shared memory.
  1385.  
  1386.  2.5.4  The File System
  1387.  
  1388.    MS OS/2 programs have complete access to the disk files and devices of the
  1389.    computer. MS OS/2 manages its disk files and its devices in essentially
  1390.    the same way. For example, a program can use the same functions to open
  1391.    and read from a disk file as it uses to open and read from a serial port.
  1392.    Each open file or device is identified by a unique file handle. The
  1393.    program uses the handle in system functions to access the file or device.
  1394.  
  1395.    MS OS/2 lets programs create, open, move, and delete files and directories
  1396.    in the file system. When a process opens a file, it specifies whether the
  1397.    file can be shared──that is, whether it can be accessed and possibly
  1398.    modified by other processes. This sharing also applies to devices that a
  1399.    process may open. Processes can open any device directly, including the
  1400.    parallel port, the serial ports, and the disk drive. MS OS/2 provides a
  1401.    wide range of input-and-output-control functions that a process can use to
  1402.    access and set the modes of the devices it has opened.
  1403.  
  1404.    Ordinarily, the system automatically opens three files when a program
  1405.    starts: the standard-input, standard-output, and standard-error files.
  1406.    These files correspond to the keyboard and the full-screen display. The
  1407.    program can use these files to read from the keyboard and write to a
  1408.    full-screen display.
  1409.  
  1410.  2.5.5  Full-Screen Keyboard, Mouse, and Video Operations
  1411.  
  1412.    For full-screen programs, MS OS/2 provides access to the keyboard, the
  1413.    mouse, and the video display. A program can open these devices in much the
  1414.    same way as it opens a file. The MS OS/2 keyboard (Kbd) functions return
  1415.    much more information about a keystroke than do the standard file-system
  1416.    functions. Also, the keyboard functions let a program create logical
  1417.    keyboards and manage these keyboards for the processes in the same screen
  1418.    group.
  1419.  
  1420.    Similarly, a program can open the mouse and read events from the
  1421.    mouse-event queue. An event is a mouse motion or button click. The program
  1422.    can also manage the mouse pointer, moving it, hiding it, and showing it as
  1423.    necessary.
  1424.  
  1425.    Any full-screen program can write individual characters and strings
  1426.    directly to a character-based display. Unlike Presentation Manager
  1427.    applications, which must write characters to windows, a full-screen
  1428.    program has complete control of the system display while its session is in
  1429.    the foreground. The program can write both characters and attributes to
  1430.    the display, read characters from the display, and change modes for the
  1431.    display. A program that uses the video functions in a full-screen session
  1432.    must manage the display for that session.
  1433.  
  1434.    The keyboard and mouse functions should not be used in Presentation
  1435.    Manager applications, since the system provides its own mouse and keyboard
  1436.    management. Many of the video functions can be used in a special type of
  1437.    Presentation Manager application called an advanced-video-input-and-output
  1438.    (AVIO) program. An AVIO program creates a window but uses the video
  1439.    functions to write text to the window.
  1440.  
  1441.  2.5.6  Interprocess Communication
  1442.  
  1443.    MS OS/2 provides several methods of interprocess communication:
  1444.    semaphores, pipes, signals, and queues.
  1445.  
  1446.    A semaphore is a special variable that a process can use to signal the
  1447.    beginning and ending of a given operation and to prevent more than one
  1448.    thread within the process from accessing a specific resource at the same
  1449.    time. A process can create and use three types of semaphores: system, RAM,
  1450.    and fast-safe RAM. System semaphores are used between processes to control
  1451.    access to a shared resource. RAM semaphores are used between threads in
  1452.    the same process to control a resource or to signal the end of an
  1453.    operation. Fast-safe RAM semaphores are used between threads or processes
  1454.    to control a resource. The RAM semaphores are typically used when
  1455.    semaphore processing must be fast.
  1456.  
  1457.    A pipe is a special file that two processes can use to transfer data.
  1458.    Although a pipe is like a file, it does not correspond to a device or a
  1459.    file on disk. Instead, the pipe is maintained by the system. Two processes
  1460.    use a pipe by opening the pipe and retrieving two handles: a read handle
  1461.    and a write handle. One process uses the write handle to write data to the
  1462.    pipe. The other process uses the read handle to read the data from the
  1463.    pipe.
  1464.  
  1465.    A signal is a special interrupt that is sent to a process by the system or
  1466.    by another process. The signal temporarily stops normal execution of the
  1467.    process and causes the process to execute a signal handler. Signals are
  1468.    typically used to stop a process and exit. For example, pressing the
  1469.    CTRL+C key combination in a full-screen session generates a signal that
  1470.    usually stops the current process. The signal handler defines what a
  1471.    process does when it receives a signal. If a process does not want default
  1472.    signal handling, it can disable a signal or replace the signal handler
  1473.    with one of its own.
  1474.  
  1475.    A queue is a special buffer that a process creates and shares with other
  1476.    processes. A queue is a convenient way for one process to channel data
  1477.    from two or more related processes into a single buffer. Note that this
  1478.    kind of queue is different from the message queue used by Presentation
  1479.    Manager. The queues are not related.
  1480.  
  1481.  
  1482.  2.6  The MS OS/2 System Functions
  1483.  
  1484.    The MS OS/2 system functions give applications access to all the features
  1485.    of MS OS/2. The MS OS/2 features, such as windows, device-independent
  1486.    graphics, and multitasking, let you create programs that make optimal use
  1487.    of the computer's memory, display, and CPU while still meeting the needs
  1488.    of a wide range of users through either the traditional character-based
  1489.    interface or the graphical user interface of Presentation Manager.
  1490.  
  1491.    The MS OS/2 system functions are organized into several distinct groups,
  1492.    as described in the following list:
  1493.  
  1494. ╓┌─┌───────────────┌─────────────────────────────────────────────────────────╖
  1495.    Function group  Usage
  1496.    ──────────────────────────────────────────────────────────────────────────
  1497.    Dev             Use the Presentation Manager device (Dev) functions to
  1498.                    open and control Presentation Manager device drivers.
  1499.                    These functions let you create device contexts that you
  1500.                    can associate with a presentation space and use with the
  1501.                    Gpi functions to carry out device-independent graphics
  1502.                    operations for displays, printers, and plotters.
  1503.  
  1504.    Dos             Use the disk-operating-system (Dos) functions in
  1505.                    full-screen and Presentation Manager sessions to read from
  1506.                    and write to disk files, to allocate memory, to start
  1507.                    threads and processes, to communicate with other
  1508.                    processes, and to access the computer's devices directly.
  1509.                    Most functions in this group can be used in Presentation
  1510.                    Manager applications.
  1511.  
  1512.    Gpi             Use the graphics-programming-interface (Gpi) functions to
  1513.                    create graphics output for a display, a printer, or other
  1514.    Function group  Usage
  1515.    ──────────────────────────────────────────────────────────────────────────
  1516.                   create graphics output for a display, a printer, or other
  1517.                    output devices. The Gpi functions give you a full range of
  1518.                    graphics primitives, from lines to complex curves to
  1519.                    bitmaps. You choose the attributes for the primitives
  1520.                    (such as color, line width, and pattern) and then draw
  1521.                    lines, text, and shapes. The retained-graphics capability
  1522.                    lets you save the drawings in segments and build complex
  1523.                    pictures by drawing a chain of segments.
  1524.  
  1525.    Kbd             Use the keyboard (Kbd) functions in full-screen sessions
  1526.                    to read keystrokes from the keyboard, to manage multiple
  1527.                    logical keyboards, and to change code pages and
  1528.                    translation tables. Since the Presentation Manager session
  1529.                    provides its own keyboard support, Kbd functions are not
  1530.                    needed in Presentation Manager applications.
  1531.  
  1532.    Mou             Use the mouse (Mou) functions in full-screen sessions to
  1533.                    read mouse input from the mouse-event queue, to set the
  1534.                    mouse-pointer shape, and to manage the mouse for all
  1535.    Function group  Usage
  1536.    ──────────────────────────────────────────────────────────────────────────
  1537.                   mouse-pointer shape, and to manage the mouse for all
  1538.                    processes in a session. As with the keyboard, the
  1539.                    Presentation Manager session provides its own mouse
  1540.                    support, so Mou functions are not needed in Presentation
  1541.                    Manager applications.
  1542.  
  1543.    Vio             Use the video-input-and-output (Vio) functions in
  1544.                    full-screen sessions to write characters and character
  1545.                    attributes to the screen, to create pop-up <windows for
  1546.                    messages, to change video modes, and to access physical
  1547.                    video memory. Vio functions can also be used in
  1548.                    advanced-video-input-and-output (AVIO) applications for
  1549.                    the Presentation Manager session, to write characters and
  1550.                    character attributes in a window. Most Presentation
  1551.                    Manager applications, however, use the
  1552.                    graphics-programming-interface (Gpi) functions to write
  1553.                    text in a window.
  1554.  
  1555.    Win             Use the window-manager (Win) functions to create and
  1556.    Function group  Usage
  1557.    ──────────────────────────────────────────────────────────────────────────
  1558.   Win             Use the window-manager (Win) functions to create and
  1559.                    manage windows. Presentation Manager applications use
  1560.                    windows as the main interface with the user. The Win
  1561.                    functions let you create menus, scroll bars, and dialog
  1562.                    windows that let the user choose commands and supply
  1563.                    input. Your application receives all mouse and keyboard
  1564.                    input as messages from the message queue. The Win
  1565.                    functions let you retrieve messages from the queue and
  1566.                    dispatch them to the window the input is intended for.
  1567.    ──────────────────────────────────────────────────────────────────────────
  1568.  
  1569.  
  1570.  
  1571.  
  1572.  
  1573.  ────────────────────────────────────────────────────────────────────────────
  1574.  Chapter 3  MS OS/2 Programming Models
  1575.  
  1576.         3.1     Introduction
  1577.         3.2     Full-Screen Programs
  1578.         3.3     Presentation Manager Applications
  1579.         3.4     The Family Application Programming Interface
  1580.         3.5     Using the Command Line
  1581.         3.6     Using Structures
  1582.         3.7     Using Bit Masks
  1583.         3.8     Sharing Resources
  1584.         3.9     C-Language Header Files
  1585.  
  1586.  3.1  Introduction
  1587.  
  1588.    This chapter describes the types of programs that you can develop for MS
  1589.    OS/2. MS OS/2 supports the following program types:
  1590.  
  1591.    ■  Full-screen programs
  1592.  
  1593.    ■  Full-screen programs in a window
  1594.  
  1595.    ■  Presentation Manager applications
  1596.  
  1597.    ■  Advanced-video-input-and-output (AVIO) programs
  1598.  
  1599.    ■  Family-application-programming-interface (FAPI) programs
  1600.  
  1601.  
  1602.  3.2  Full-Screen Programs
  1603.  
  1604.    A full-screen program is any MS OS/2 program that does not create a
  1605.    Presentation Manager message queue. In other words, it is a program that
  1606.    does not rely on the Presentation Manager mouse and keyboard processing
  1607.    for input. Full-screen programs typically run in a full-screen session.
  1608.  
  1609.    Most full-screen programs use the Dos functions to perform input, output,
  1610.    memory management, and other activities. Full-screen programs also
  1611.    commonly use the standard-input, standard-output, and standard-error files
  1612.    created for them when they start.
  1613.  
  1614.    A full-screen program uses a main function as its starting point and can
  1615.    call as many other functions as needed to complete its designated task.
  1616.    The following simple full-screen program copies the line "Hello, world" to
  1617.    the screen:
  1618.  
  1619.    #include <os2.h>
  1620.  
  1621.    main( )
  1622.    {
  1623.        USHORT cbWritten;
  1624.  
  1625.        DosWrite(1, "Hello, world\r\n", 14, &cbWritten);
  1626.    }
  1627.  
  1628.    The MS OS/2 system functions use many structures, data types, and
  1629.    constants that are not part of the standard C language. For example, the
  1630.    data type USHORT is a special MS OS/2 data type that specifies an unsigned
  1631.    short integer. In order to use these items, you must include the MS OS/2
  1632.    header file os2.h at the beginning of your program source file. For more
  1633.    information about the C-language header files, see Section 3.9.
  1634.  
  1635.    The MS OS/2 system functions are not standard C functions. They use the
  1636.    Pascal calling convention. This means, for example, that the MS OS/2
  1637.    functions expect parameters to be passed in left-to-right order instead of
  1638.    the standard right-to-left order of C functions. To use the MS OS/2
  1639.    functions in a C-language program, you must declare them with the pascal
  1640.    keyword, which directs the C compiler to generate proper instructions for
  1641.    the function call. All MS OS/2 functions are declared this way within the
  1642.    os2.h file, so including the file saves you the trouble of declaring each
  1643.    function individually.
  1644.  
  1645.    The os2.h file also declares the parameter types for each function.
  1646.    Without these declarations, many function parameters would require type
  1647.    casting to avoid compiler errors. For example, the DosWrite function shown
  1648.    in the preceding example requires the second parameter to be a complete
  1649.    far (32-bit) address to the given string. Since the os2.h file declares
  1650.    the second parameter with this type, the compiler does the cast for you.
  1651.  
  1652.    Some full-screen programs can also run in a window in the Presentation
  1653.    Manager session. Although the program runs in a window, it does not create
  1654.    the window. Instead, the system creates the window and provides the input
  1655.    and output to the program just as if it were running in a full-screen
  1656.    session. A full-screen program can run in a window only if it does not use
  1657.    functions that directly access the devices that Presentation Manager
  1658.    controls. For example, a program that attempts to retrieve the address of
  1659.    the video buffer or to change video modes may fail.
  1660.  
  1661.  
  1662.  3.3  Presentation Manager Applications
  1663.  
  1664.    A Presentation Manager application is any MS OS/2 program that creates a
  1665.    message queue. A window is the only means a Presentation Manager
  1666.    application has to receive input and display output, so Presentation
  1667.    Manager applications typically create one or more windows to interact with
  1668.    the user.
  1669.  
  1670.    All MS OS/2 Presentation Manager applications have essentially the
  1671.    following structure:
  1672.  
  1673.    ■  A main function
  1674.  
  1675.    ■  One or more window procedures
  1676.  
  1677.    ■  Optional functions to support the main function and/or the window
  1678.       procedures
  1679.  
  1680.    Since nearly all Presentation Manager applications create and use windows,
  1681.    the main function carries out the same basic tasks in most applications.
  1682.    The typical main function does the following, in the order shown:
  1683.  
  1684.    1.  Initializes the application for Presentation Manager.
  1685.  
  1686.    2.  Creates a message queue.
  1687.  
  1688.    3.  Creates a window class.
  1689.  
  1690.    4.  Creates a window.
  1691.  
  1692.    5.  Starts the message loop and continues to dispatch messages until the
  1693.        WM_QUIT message is retrieved.
  1694.  
  1695.    6.  Destroys the window when finished using it.
  1696.  
  1697.    7.  Destroys the message queue.
  1698.  
  1699.    8.  Terminates the application.
  1700.  
  1701.    Every MS OS/2 Presentation Manager application has at least one thread of
  1702.    execution. Each thread that calls Presentation Manager functions must
  1703.    register with the system by calling the WinInitialize function. This
  1704.    function creates an anchor block and returns an anchor-block handle that
  1705.    the thread can use in subsequent functions.
  1706.  
  1707.    An anchor block links a process with the system. The anchor block includes
  1708.    an instance data segment in which to store the process's environment and
  1709.    storage for error messages. The anchor-block handle is used in the call to
  1710.    the WinTerminate function that ends the association with the anchor block
  1711.    just before the application terminates.
  1712.  
  1713.    The application creates the message queue by using the WinCreateMsgQueue
  1714.    function. This function returns a queue handle that can be used in
  1715.    subsequent functions. Once the queue is created, the application can
  1716.    register a window class, create a window and start the message loop. After
  1717.    the message loop ends, the application can destroy the window and use the
  1718.    queue handle in the WinDestroyMsgQueue function to destroy the queue.
  1719.  
  1720.    Once the application is initialized and a message queue and window are
  1721.    created, the application can enter the main message loop. The application
  1722.    waits there for messages to appear in the queue, retrieves them, and
  1723.    dispatches them, as appropriate, to its windows. When the user or system
  1724.    chooses to terminate an application, a WM_QUIT message is used to trigger
  1725.    an exit from the message loop.
  1726.  
  1727.    After leaving the message loop, an application carries out various
  1728.    termination activities, including destroying windows, releasing memory,
  1729.    destroying message queues, closing files, and severing connections with
  1730.    the shell and other applications.
  1731.  
  1732.    The following code fragment from a simple Presentation Manager application
  1733.    copies the line "Hello, world" to its window:
  1734.  
  1735.    #define INCL_WIN
  1736.    #define INCL_DOS
  1737.    #include <os2.h>
  1738.    HAB hab;            /* anchor-block handle     */
  1739.    HMQ hmq;            /* message-queue handle    */
  1740.    QMSG qmsg;          /* message-queue structure */
  1741.  
  1742.    MRESULT CALLBACK MyWindowProc(HWND, USHORT, MPARAM, MPARAM);
  1743.  
  1744.    HWND hwndFrame;     /* frame-window handle     */
  1745.    HWND hwndClient;    /* client-window handle    */
  1746.    ULONG flStyle = FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
  1747.                    FCF_MINMAX | FCF_SHELLPOSITION | FCF_TASKLIST;
  1748.  
  1749.    main()
  1750.    {
  1751.        /*
  1752.         * Initialize the thread for making Presentation Manager calls and
  1753.         * create the message queue.
  1754.         */
  1755.  
  1756.        hab = WinInitialize(0);
  1757.        hmq = WinCreateMsgQueue(hab, DEFAULT_QUEUE_SIZE);
  1758.  
  1759.        /* Register the class, terminate on failure. */
  1760.  
  1761.        if (!WinRegisterClass(hab, "MyClass",
  1762.                MyWindowProc, CS_SIZEREDRAW, NULL))
  1763.            DosExit(EXIT_PROCESS, 0);
  1764.  
  1765.        /* Create the window, terminate on failure. */
  1766.  
  1767.        if (!(hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE,
  1768.                &flStyle, "My Window!", 0L, NULL, 0, &hwndClient)))
  1769.            DosExit(EXIT_PROCESS, 0);
  1770.  
  1771.        /* Get and dispatch messages. */
  1772.  
  1773.        while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
  1774.            WinDispatchMsg(hab, &qmsg, NULL, 0, 0);
  1775.        WinDestroyWindow(hwndFrame);    /* destroy the main window   */
  1776.        WinDestroyMsgQueue(hmq);        /* destroy the message queue */
  1777.        WinTerminate(hab);              /* terminate                 */
  1778.    }
  1779.  
  1780.    MRESULT CALLBACK MyWindowProc(hwnd, usMessage, mp1, mp2)
  1781.    HWND hwnd;
  1782.    USHORT msg;
  1783.    MPARAM mp1;
  1784.    MPARAM mp2;
  1785.    {
  1786.        HPS hps;        /* presentation-space handle */
  1787.        RECTL rcl;      /* rectangle structure       */
  1788.        POINTL ptl;     /* point structure           */
  1789.  
  1790.        switch (msg) {
  1791.            case WM_PAINT:
  1792.                hps = WinBeginPaint(hwnd,
  1793.                    NULL, NULL);                       /* start painting  */
  1794.                WinQueryWindowRect(hwnd, &rcl);        /* get window size */
  1795.                WinFillRect(hps, &rcl, CLR_WHITE);     /* fill background */
  1796.                ptl.x = (rcl.xRight - rcl.xLeft) / 2;
  1797.                ptl.y = (rcl.yTop - rcl.yBottom) / 2;
  1798.                GpiMove(hps, &ptl);          /* move to center of window  */
  1799.                GpiCharString(hps, 12L,
  1800.                    "Hello, world");                     /* draw string   */
  1801.                WinEndPaint(hps);                        /* end painting  */
  1802.                return (0L);
  1803.  
  1804.            default:
  1805.                return (WinDefWindowProc(hwnd, msg, mp1, mp2));
  1806.        }
  1807.    }
  1808.  
  1809.    An advanced-video-input-and-output (AVIO) program is a Presentation
  1810.    Manager program that uses the advanced Vio functions for text output.
  1811.    These function let a Presentation Manager application write text to a
  1812.    window just as if it were writing the text to a full screen. These
  1813.    programs must run in the Presentation Manager session and must create at
  1814.    least one window for input and output.
  1815.  
  1816.  
  1817.  3.4  The Family Application Programming Interface
  1818.  
  1819.    Many MS OS/2 functions can be used in programs intended to be run in real
  1820.    mode. These functions, collectively called the family application
  1821.    programming interface (family API, or FAPI), let developers create MS OS/2
  1822.    programs that can run in both protected and real modes; that is, they can
  1823.    run under MS OS/2 and under MS-DOS versions 2.x and 3.x.
  1824.  
  1825.    To use the family API in real-mode programs, you must use only the MS OS/2
  1826.    functions that belong to the FAPI, and you must observe the restrictions
  1827.    that apply to these functions when running in real mode. Also, you must
  1828.    bind your program by using the Microsoft Operating System/2 Bind utility
  1829.    (bind). The bind utility supplies the code needed to link the MS OS/2
  1830.    functions to the corresponding MS-DOS system calls. This code is used only
  1831.    when the program is run in real mode; that is, a bound program can still
  1832.    run in protected mode.
  1833.  
  1834.    Not all MS OS/2 functions belong to the FAPI, and some that do belong have
  1835.    slightly different behavior when used in real mode than when used in
  1836.    protected mode. The following is a complete list of the FAPI functions.
  1837.    Those functions marked with a dagger (╪) operate differently in real mode
  1838.    than in protected mode; all other FAPI functions operate identically in
  1839.    both protected and real modes.
  1840.  
  1841.  
  1842.    DosAllocHuge ╪       DosInsMessage ╪      KbdFlushBuffer ╪
  1843.    DosAllocSeg ╪        DosMkDir             KbdGetStatus╪
  1844.    DosBeep              DosMove              KbdPeek ╪
  1845.    DosBufReset          DosNewSize           KbdSetStatus ╪
  1846.    DosCaseMap ╪         DosOpen ╪            KbdStringIn╪
  1847.    DosChDir             DosPutMessage ╪      VioGetBuf
  1848.    DosChgFilePtr        DosQCurDir           VioGetCurPos
  1849.    DosClose             DosQCurDisk          VioGetCurType
  1850.    DosCreateCSAlias ╪   DosQFHandState       VioGetMode
  1851.    DosDelete            DosQFileInfo         VioGetPhysBuf
  1852.    DosDevConfig         DosQFileMode         VioReadCellStr
  1853.    DosDevIOCtl ╪        DosQFSInfo           VioReadCharStr
  1854.    DosDupHandle         DosQVerify           VioScrLock ╪
  1855.    DosErrClass          DosRead ╪            VioScrollDn
  1856.    DosError ╪           DosReallocHuge ╪     VioScrollLf
  1857.    DosExecPgm ╪         DosReallocSeg ╪      VioScrollRt
  1858.    DosExit ╪            DosRmDir             VioScrollUp
  1859.    DosFileLocks         DosSelectDisk        VioScrUnLock
  1860.    DosFindClose         DosSetDateTime       VioSetCurPos
  1861.    DosFindFirst ╪       DosSetFHandState ╪   VioSetCurType
  1862.    DosFindNext ╪        DosSetFileInfo       VioSetMode
  1863.    DosFreeSeg ╪         DosSetFileMode       VioShowBuf
  1864.    DosGetCollate ╪      DosSetFSInfo         VioWrtCellStr
  1865.    DosGetCtryInfo ╪     DosSetSigHandler ╪   VioWrtCharStr
  1866.    DosGetDateTime       DosSetVec ╪          VioWrtCharStrAtt
  1867.    DosGetDBCSEv ╪       DosSetVerify         VioWrtNAttr
  1868.    DosGetEnv            DosSleep             VioWrtNCell
  1869.    DosGetHugeShift      DosSubAlloc          VioWrtNChar
  1870.    DosGetMachineMode    DosSubFree           VioWrtTTY
  1871.    DosGetMessage ╪      DosSubSet
  1872.    DosGetVersion        DosWrite
  1873.    DosHoldSignal ╪      KbdCharIn ╪
  1874.  
  1875.    ──────────────────────────────────────────────────────────────────────────
  1876.    Note
  1877.      The DosGetMachineMode function is especially useful in FAPI programs,
  1878.      since it specifies which environment the program is running in: MS OS/2
  1879.      or MS-DOS.
  1880.    ──────────────────────────────────────────────────────────────────────────
  1881.  
  1882.    Following are the real-mode restrictions and/or differences in operation
  1883.    for the FAPI functions marked with daggers (╪) in the preceding list:
  1884.  
  1885.    DosAllocHuge  Rounds the usPartialSeg parameter value up to the next
  1886.    paragraph (16-byte) value. This function copies the actual segment
  1887.    address, not a selector, to the variable pointed to by the psel parameter.
  1888.  
  1889.    DosAllocSeg  Rounds the usSize parameter value up to the next paragraph
  1890.    (16-byte) value. This function copies the actual segment address, not a
  1891.    selector, to the variable pointed to by the psel parameter.
  1892.  
  1893.    DosCaseMap  Provides no method of identifying the boot drive. The system
  1894.    assumes that the country.sys file is in the root directory of the current
  1895.    drive.
  1896.  
  1897.    DosCreateCSAlias  Returns as a selector the actual segment address of the
  1898.    allocated memory. Freeing either the returned selector or the original
  1899.    selector immediately frees the block of memory.
  1900.  
  1901.    DosDevIOCtl  Restricts the input-and-output-control functions that can be
  1902.    used. Categories 2, 3, 4, 6, 7, 10, and 11 cannot be used. Also, some
  1903.    control functions in categories 1, 5, and 8 can be used with MS-DOS 3.x
  1904.    but not with MS-DOS 2.x. The following input-and-output-control functions
  1905.    can be used in FAPI programs:
  1906.  
  1907.          ASYNC_SETBAUDRATE
  1908.          ASYNC_SETLINECTRL
  1909.          DSK_BLOCKREMOVABLE
  1910.          DSK_GETLOGICALMAP
  1911.          DSK_LOCKDRIVE        DSK_REDETERMINEMEDIA        DSK_SETLOGICALMAP
  1912.          DSK_UNLOCKDRIVE        PRT_GETFRAMECTL
  1913.          PRT_GETINFINITERETRY
  1914.          PRT_GETPRINTERSTATUS
  1915.          PRT_INITPRINTER
  1916.          PRT_SETFRAMECTL (for IBM Graphics Printers only)
  1917.          PRT_SETINFINITERETRY (current program only)
  1918.  
  1919.    DosError  If the fEnable parameter is HARDERROR_DISABLE, causes all
  1920.    subsequent int 24h requests to fail, until another call is made to the
  1921.    DosError function with fEnable set to HARDERROR_ENABLE.
  1922.  
  1923.    DosExecPgm  Allows only the value EXEC_SYNC for the fExecFlags parameter.
  1924.    Other values cause errors. The buffer pointed to by the pchFailName
  1925.    parameter is filled with blanks, even if the function fails. The
  1926.    codeResult field of the RESULTCODES structure receives the exit code for
  1927.    the DosExit function or the MS-DOS call that terminates the program.
  1928.  
  1929.    DosExit  Exits from the currently executing program, since there are no
  1930.    threads in the real-mode environment. If the fTerminate parameter is
  1931.    EXIT_THREAD, the entire process ends, not just a thread.
  1932.  
  1933.    DosFindFirst  Requires the phdir parameter to be HDIR_SYSTEM.
  1934.  
  1935.    DosFindNext  Requires the hdir parameter to be HDIR_SYSTEM.
  1936.  
  1937.    DosFreeSeg  Does not treat a code-segment selector (created by using the
  1938.    DosCreateCSAlias function) and the corresponding data-segment selector as
  1939.    unique. Freeing one frees both.
  1940.  
  1941.    DosGetCollate  Provides no method of identifying the boot drive. The
  1942.    system assumes that the country.sys file is in the root directory of the
  1943.    current drive.
  1944.  
  1945.    DosGetCtryInfo  Provides no method of identifying the boot drive. The
  1946.    system assumes that the country.sys file is in the root directory of the
  1947.    current drive.
  1948.  
  1949.    DosGetDBCSEv  Provides no method of identifying the boot drive. The system
  1950.    assumes that the country.sys file is in the root directory of the current
  1951.    drive.
  1952.  
  1953.    DosGetMessage  Provides no method of identifying the boot drive. The
  1954.    system assumes that the message file is in the root directory of the
  1955.    current drive.
  1956.  
  1957.    DosHoldSignal  Recognizes only the signal-interrupt (SIG_CTRLC) and
  1958.    signal-break (SIG_CTRLBREAK) signals.
  1959.  
  1960.    DosInsMessage  Provides no method of identifying the boot drive. The
  1961.    system assumes that the message file is in the root directory of the
  1962.    current drive.
  1963.  
  1964.    DosOpen  Restricts the values that can be used with the fsOpenMode
  1965.    parameter. The parameter can be a combination of the following values:
  1966.  
  1967. ╓┌─┌─────────────────────────────┌───────────────────────────────────────────╖
  1968.    Value                         Meaning
  1969.    ──────────────────────────────────────────────────────────────────────────
  1970.    OPEN_ACCESS_READONLY          Read-only access mode.
  1971.  
  1972.    OPEN_ACCESS_WRITEONLY         Write-only access mode.
  1973.  
  1974.    OPEN_ACCESS_READWRITE         Read/write access mode.
  1975.  
  1976.    Value                         Meaning
  1977.    ──────────────────────────────────────────────────────────────────────────
  1978. 
  1979.    OPEN_SHARE_DENYREADWRITE      Deny read/write share mode. Not available in
  1980.                                  MS-DOS 2.x. Available in MS-DOS 3.x only
  1981.                                  when the share command has been used.
  1982.  
  1983.    OPEN_SHARE_DENYWRITE          Deny-write share mode. Not available in
  1984.                                  MS-DOS 2.x. Available in MS-DOS 3.x only
  1985.                                  when the share command has been used.
  1986.  
  1987.    OPEN_SHARE_DENYREAD           Deny-read share mode. Not available in
  1988.                                  MS-DOS 2.x. Available in MS-DOS 3.x only
  1989.                                  when the share command has been used.
  1990.  
  1991.    OPEN_SHARE_DENYNONE           Deny-none share mode. Not available in
  1992.                                  MS-DOS 2.x. Available in MS-DOS 3.x only
  1993.                                  when the share command has been used.
  1994.  
  1995.    OPEN_FLAGS_NOINHERIT          Inheritance flag. Not available in MS-DOS
  1996.                                  2.x.
  1997.    Value                         Meaning
  1998.    ──────────────────────────────────────────────────────────────────────────
  1999.                                 2.x.
  2000.  
  2001.    OPEN_FLAGS_WRITE_THROUGH      Write-through flag. Not available in MS-DOS
  2002.                                  2.x.
  2003.  
  2004.    OPEN_FLAGS_DASD               Direct-access-storage-device (DASD) flag.
  2005.    ──────────────────────────────────────────────────────────────────────────
  2006.  
  2007.  
  2008.    The fail-on-error flag (OPEN_FLAGS_FAIL_ON_ERROR) is not available to
  2009.    real-mode programs.
  2010.  
  2011.    DosPutMessage  Provides no method of identifying the boot drive. The
  2012.    system assumes that the message file is in the root directory of the
  2013.    current drive.
  2014.  
  2015.    DosRead  Uses the KbdStringIn function whenever the specified file handle
  2016.    identifies the keyboard device. In real mode, KbdStringIn reads only the
  2017.    number of characters specified in the call, then beeps to signal the user
  2018.    that no additional characters can be entered. (In protected mode, the user
  2019.    can enter characters until the keyboard buffer is full.)
  2020.  
  2021.    DosReallocHuge  Rounds the usPartialSize parameter value up to the next
  2022.    paragraph (16-byte) value.
  2023.  
  2024.    DosReallocSeg  Rounds the usNewSize parameter value up to the next
  2025.    paragraph (16-byte) value.
  2026.  
  2027.    DosSetFHandState  Requires that the OPEN_FLAGS_FAIL_ON_ERROR flag and the
  2028.    OPEN_FLAGS_WRITE_THROUGH flag not be set. Also, the OPEN_FLAGS_NOINHERIT
  2029.    flag must not be set in MS-DOS 2.x.
  2030.  
  2031.    DosSetSigHandler  Can be used to install signal handlers for only the
  2032.    signal-interrupt (SIG_CTRLC) and signal-break (SIG_CTRLBREAK) signals.
  2033.    Furthermore, the SIG_CTRLC and SIG_CTRLBREAK signals are treated as the
  2034.    same signal, so the function accepts only the SIG_CTRLC value when setting
  2035.    a signal handler.
  2036.  
  2037.    DosSetVec  Does not accept VECTOR_EXTENSION_ERROR as the usVecNum value,
  2038.    since this exception is not raised in machines using the 8088 or 8086
  2039.    microprocessor.
  2040.  
  2041.    KbdCharIn  Does not copy the system time to the KBDKEYINFO structure and
  2042.    provides no interim character support. This function retrieves characters
  2043.    only from the default keyboard (handle 0). The fbStatus field can be
  2044.    0x0000 or SHIFT_KEY_IN. The hkbd parameter is ignored.
  2045.  
  2046.    KbdFlushBuffer  Ignores the hkbd parameter.
  2047.  
  2048.    KbdGetStatus  Does not support the interim or turnaround character.
  2049.  
  2050.    KbdPeek  Does not copy the system time to the KBDKEYINFO structure and
  2051.    provides no interim character support. This function retrieves characters
  2052.    only from the default keyboard (handle 0). The fbStatus field can be
  2053.    0x0000 or SHIFT_KEY_IN. The hkbd parameter is ignored.
  2054.  
  2055.    KbdSetStatus  Does not support the interim character or the turnaround
  2056.    character. Raw input mode with echo mode on is not supported. The hkbd
  2057.    parameter is ignored.
  2058.  
  2059.    KbdStringIn  Ignores the hkbd parameter.
  2060.  
  2061.    VioScrLock  Always indicates that the lock was successful.
  2062.  
  2063.  
  2064.  3.5  Using the Command Line
  2065.  
  2066.    In standard C-language programs, you can use the argc and argv parameters
  2067.    of the main function to retrieve individual copies of the command-line
  2068.    arguments. You can use these parameters in MS OS/2 programs, but you can
  2069.    also retrieve the entire command line, exactly as the user typed it, by
  2070.    using the DosGetEnv function.
  2071.  
  2072.    When it starts a program, MS OS/2 prepares an environment segment for the
  2073.    program. This segment contains definitions of all environment variables,
  2074.    as well as the command line. The DosGetEnv function retrieves the segment
  2075.    selector for this environment segment and the address offset within that
  2076.    segment for the start of the command line.
  2077.  
  2078.    You can echo the command line on the screen by using the DosGetEnv
  2079.    function to get the address of the command line in the environment
  2080.    segment, as shown in the following sample program:
  2081.  
  2082.    #define INCL_DOS
  2083.    #include <os2.h>
  2084.  
  2085.    main( )
  2086.    {
  2087.        SEL selEnvironment;
  2088.        USHORT offCommand;
  2089.        PSZ pszCommandLine;
  2090.        USHORT cbWritten;
  2091.        USHORT i, cch;
  2092.  
  2093.        DosGetEnv(&selEnvironment, &offCommand);
  2094.        pszCommandLine = MAKEP(selEnvironment, offCommand);
  2095.  
  2096.        /*
  2097.         * The first string is the program name. The command line is the
  2098.         * next null-terminated string.
  2099.         */
  2100.  
  2101.        for (i = 0; pszCommandLine[i]; i++);
  2102.  
  2103.        /* Find the length of the command-line string. */
  2104.  
  2105.        for (i++, cch = 0; pszCommandLine[cch + i]; cch++);
  2106.  
  2107.        DosWrite(1, &pszCommandLine[i], cch, &cbWritten);
  2108.    }
  2109.  
  2110.    The command line has two parts. The first part is the program name,
  2111.    terminated by a zero byte. The second part is the rest of the command
  2112.    line, terminated by two zero bytes. The preceding program echoes the
  2113.    command line by skipping over the program name and then writing everything
  2114.    up to the next zero byte to the screen. The first for statement skips over
  2115.    the command name; the second for statement computes the length of the
  2116.    string. The MAKEP macro creates the far pointer that is needed to access
  2117.    the command line in the environment segment.
  2118.  
  2119.    You can examine your program's environment by using the selector retrieved
  2120.    by the DosGetEnv function. The program's environment consists of the
  2121.    environment variables that have been declared and passed to the program.
  2122.    Each program has a unique environment that is typically inherited from the
  2123.    program that started it──for example, from the MS OS/2 command processor,
  2124.    cmd.
  2125.  
  2126.    You can use the DosScanEnv function to scan for a specific environment
  2127.    variable. This function takes as an argument the name of the environment
  2128.    variable that you are interested in and copies the current value of this
  2129.    variable to a buffer that you supply. The following sample program uses
  2130.    DosScanEnv to display the value of the environment variable specified in
  2131.    the command line:
  2132.  
  2133.    #define INCL_DOSQUEUES
  2134.    #include <os2.h>
  2135.  
  2136.    main( )
  2137.    {
  2138.        SEL selEnvironment;
  2139.        USHORT offCommand;
  2140.        PSZ pszCommandLine;
  2141.        PSZ pszValue;
  2142.        USHORT cbWritten;
  2143.        USHORT i, cch;
  2144.  
  2145.        DosGetEnv(&selEnvironment, &offCommand);
  2146.        pszCommandLine = MAKEP(selEnvironment, offCommand);
  2147.  
  2148.        for (i = 0; pszCommandLine[i]; i++);
  2149.        for (i++; pszCommandLine[i] == ' '; i++);
  2150.  
  2151.        if (!DosScanEnv(&pszCommandLine[i], &pszValue)) {
  2152.            for (cch = 0; pszValue[cch]; cch++);
  2153.            DosWrite(1, pszValue, cch, &cbWritten);
  2154.        }
  2155.    }
  2156.  
  2157.  
  2158.  3.6  Using Structures
  2159.  
  2160.    Many MS OS/2 functions use structures for input and output. To use a
  2161.    structure in an MS OS/2 function, you first define the structure in your
  2162.    program and then pass the 32-bit far address of the structure as a
  2163.    parameter in the function call.
  2164.  
  2165.    For example, the DosGetDateTime function copies the current date and time
  2166.    to a DATETIME structure whose address you supply. The fields of the
  2167.    DATETIME structure define the month, day, and year, as well as the time of
  2168.    day (to hundredths of a second). The DATETIME structure, defined in the
  2169.    os2.h file, has the following form:
  2170.  
  2171.    typedef struct _DATETIME {    /* date */
  2172.        UCHAR   hours;
  2173.        UCHAR   minutes;
  2174.        UCHAR   seconds;
  2175.        UCHAR   hundredths;
  2176.        UCHAR   day;
  2177.        UCHAR   month;
  2178.        USHORT  year;
  2179.        SHORT   timezone;
  2180.        UCHAR   weekday;
  2181.    } DATETIME;
  2182.  
  2183.    To retrieve the date and time, you call the DosGetDateTime function, using
  2184.    the address operator (&) to specify the address of the DATETIME structure.
  2185.    The following sample program shows how to make the call:
  2186.  
  2187.    #include <os2.h>
  2188.  
  2189.    CHAR szDayName[] = "MonTueWedThuFriSatSun";
  2190.    CHAR szMonthName[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  2191.    CHAR szDate[] = "xx:xx:xx xxx xxx xx, xxxx\r\n";
  2192.    main( )
  2193.    {
  2194.        DATETIME date;
  2195.        SHORT offset;
  2196.        SHORT i;
  2197.        USHORT usYear;
  2198.        USHORT cbWritten;
  2199.  
  2200.        DosGetDateTime(&date);  /* address of DATETIME structure */
  2201.  
  2202.        szDate[0] = (date.hours / 10) + '0';
  2203.        szDate[1] = (date.hours % 10) + '0';
  2204.        szDate[3] = (date.minutes / 10) + '0';
  2205.        szDate[4] = (date.minutes % 10) + '0';
  2206.        szDate[6] = (date.seconds / 10) + '0';
  2207.        szDate[7] = (date.seconds % 10) + '0';
  2208.        offset = date.weekday * 3;
  2209.        for (i = 0; i < 3; i++)
  2210.            szDate[i + 9] = szDayName[i + offset];
  2211.        offset = (date.month - 1) * 3;
  2212.        for (i = 0; i < 3; i++)
  2213.            szDate[i + 13] = szMonthName[i + offset];
  2214.        szDate[17] = (date.day < 10) ? ' ' : (date.day / 10 + '0');
  2215.        szDate[18] = (date.day % 10) + '0';
  2216.        usYear = date.year;
  2217.        szDate[21] = (usYear / 1000) + '0';
  2218.        usYear = usYear % 1000;
  2219.        szDate[22] = (usYear / 100) + '0';
  2220.        usYear = usYear % 100;
  2221.        szDate[23] = (usYear / 10) + '0';
  2222.        szDate[24] = (usYear % 10) + '0';
  2223.  
  2224.        DosWrite(1, szDate, 27, &cbWritten);
  2225.    }
  2226.  
  2227.    One drawback to using MS OS/2 functions exclusively is that there are no
  2228.    formatted output functions, such as the C-language printf function.
  2229.    Therefore, the preceding program formats the data itself before displaying
  2230.    it. The program uses the integer-division operators (/ and %) to convert
  2231.    binary numbers to ASCII characters. The program then copies the ASCII
  2232.    characters to a string and displays the string by using the DosWrite
  2233.    function.
  2234.  
  2235.    Some MS OS/2 functions require that you fill one or more fields of the
  2236.    structure before calling the function. For example, there are some
  2237.    structures whose length depends on the version of the operating system
  2238.    being used; MS OS/2 requires that you supply the expected length so that
  2239.    the function does not copy data beyond the end of your structure.
  2240.  
  2241.  
  2242.  3.7  Using Bit Masks
  2243.  
  2244.    In MS OS/2, many functions use bit masks. A bit mask (also called an array
  2245.    of flags) is a combination of two or more Boolean flags in a single byte,
  2246.    word, or double-word value. In C-language programs, you can use the
  2247.    bitwise AND, OR, and NOT operators to examine and set the values in a bit
  2248.    mask.
  2249.  
  2250.    If a function retrieves a bit mask, you can check a specific flag in the
  2251.    bit mask by using the AND operator, as shown in the following code
  2252.    fragment:
  2253.  
  2254.    USHORT fsEvent;
  2255.  
  2256.    if (fsEvent & 0x0004)
  2257.        /* is the flag set? */
  2258.  
  2259.    You can set a flag in a bit mask by using the OR operator, as shown in the
  2260.    following code fragment:
  2261.  
  2262.    ULONG flFunctions;
  2263.  
  2264.    flFunctions = flFunctions | KR_KBDPEEK;
  2265.  
  2266.    Finally, you can clear a flag in a bit mask by using the AND and NOT
  2267.    operators, as shown in the following code fragment:
  2268.  
  2269.    USHORT fsEvent;
  2270.  
  2271.    fsEvent = fsEvent & ~0x0004;
  2272.  
  2273.  
  2274.  3.8  Sharing Resources
  2275.  
  2276.    Many MS OS/2 functions let you use the resources of the computer, such as
  2277.    the keyboard, screen, disk, and even the system speaker. Since MS OS/2 is
  2278.    a multitasking operating system and more than one program may be running
  2279.    at a time, MS OS/2 considers all resources of the computer to be shared
  2280.    resources. As a result, programs must not claim exclusive access to a
  2281.    given resource.
  2282.  
  2283.    Consider a simple program that plays a short tune by using the DosBeep
  2284.    function. This function, when called by a single program, generates a tone
  2285.    at the system speaker, but if two programs call DosBeep at the same time,
  2286.    the result is chaotic. For example, try running two or more copies of the
  2287.    following program at the same time:
  2288.  
  2289.    #include <os2.h>
  2290.  
  2291.    #define CNOTES 14
  2292.    USHORT ausTune[] = {
  2293.        440, 1000,
  2294.        480, 1000,
  2295.        510, 1000,
  2296.        550, 1000,
  2297.        590, 1000,
  2298.        620, 1000,
  2299.        660, 1000
  2300.        };
  2301.  
  2302.    main( )
  2303.    {
  2304.        int i;
  2305.  
  2306.        for (i = 0; i < CNOTES; i += 2)
  2307.            DosBeep(ausTune[i], ausTune[i + 1]);
  2308.    }
  2309.  
  2310.    The first parameter of the DosBeep function specifies the frequency of the
  2311.    note. The second parameter specifies the duration. The array ausTune
  2312.    defines frequency and duration values for each note in the tune.
  2313.  
  2314.    DosBeep is intended to be used for signaling the user when an error
  2315.    occurs, such as pressing an incorrect key. Since the system speaker is a
  2316.    shared resource, a process should use the DosBeep function sparingly.
  2317.  
  2318.  
  2319.  3.9  C-Language Header Files
  2320.  
  2321.    The MS OS/2 C-language header file os2.h contains the definitions you need
  2322.    to use the functions, data types, structures, and constants described in
  2323.    the Microsoft Operating System/2 Programmer's Reference.
  2324.  
  2325.    When you include the os2.h file, the C preprocessor automatically defines
  2326.    many, but not all, of the most commonly used MS OS/2 functions. The os2.h
  2327.    header file is the "master" file of a set of files that contain the MS
  2328.    OS/2 function definitions. Each file contains definitions for the
  2329.    functions, data types, structures, and constants associated with a
  2330.    specific group of MS OS/2 functions. To minimize the time required to
  2331.    process the many header files, each function group is conditionally
  2332.    processed on the basis of whether a corresponding constant is defined
  2333.    within the program source file. The following is a list of these
  2334.    constants, with descriptions of the function groups they represent:
  2335.  
  2336. ╓┌─┌────────────────────────┌────────────────────────────────────────────────╖
  2337.    Constant                 Meaning
  2338.    ──────────────────────────────────────────────────────────────────────────
  2339.    INCL_AVIO                Includes all MS OS/2 version 1.1 AVIO functions.
  2340.  
  2341.    INCL_BASE                Include all MS OS/2 version 1.1 system functions
  2342.                             (Dos, Vio, Kbd, Mou).
  2343.  
  2344.    INCL_BITMAPFILEFORMAT    Include the bitmap file-header structure
  2345.                             BITMAPFILEHEADER.
  2346.  
  2347.    INCL_DEV                 Include all MS OS/2 version 1.1 device functions
  2348.                             (Dev).
  2349.  
  2350.    INCL_DEVERRORS           Include the Dev-function error constants.
  2351.  
  2352.    INCL_DOS                 Include all MS OS/2 version 1.1 kernel functions
  2353.                             (Dos).
  2354.    Constant                 Meaning
  2355.    ──────────────────────────────────────────────────────────────────────────
  2356.                            (Dos).
  2357.  
  2358.    INCL_DOSDATETIME         Include the date/time and timer functions.
  2359.  
  2360.    INCL_DOSDEVICES          Include the device and IOPL support functions.
  2361.  
  2362.    INCL_DOSDEVIOCTL         Include all MS OS/2 version 1.1 input-and-output
  2363.                             control functions (IOCtls).
  2364.  
  2365.    INCL_DOSERRORS           Include the Dos-function error constants.
  2366.  
  2367.    INCL_DOSFILEMGR          Include the file-management functions.
  2368.  
  2369.    INCL_DOSINFOSEG          Include the information-segment functions.
  2370.  
  2371.    INCL_DOSMEMMGR           Include the memory-management functions.
  2372.  
  2373.    INCL_DOSMISC             Include miscellaneous Dos functions.
  2374.  
  2375.    Constant                 Meaning
  2376.    ──────────────────────────────────────────────────────────────────────────
  2377. 
  2378.    INCL_DOSMODULEMGR        Include the module-manager functions.
  2379.  
  2380.    INCL_DOSMONITORS         Include the monitor functions.
  2381.  
  2382.    INCL_DOSNLS              Include national-language-support functions.
  2383.  
  2384.    INCL_DOSNMPIPES          Include named-pipe functions.
  2385.  
  2386.    INCL_DOSPROCESS          Include the process- and thread-support
  2387.                             functions.
  2388.  
  2389.    INCL_DOSQUEUES           Include the queue functions and other
  2390.                             miscellaneous functions.
  2391.  
  2392.    INCL_DOSRESOURCES        Include the resource-support functions.
  2393.  
  2394.    INCL_DOSSEMAPHORES       Include the semaphore functions.
  2395.  
  2396.    Constant                 Meaning
  2397.    ──────────────────────────────────────────────────────────────────────────
  2398. 
  2399.    INCL_DOSSESMGR           Include the session-manager functions.
  2400.  
  2401.    INCL_DOSSIGNALS          Include the signal functions.
  2402.  
  2403.    INCL_DOSTRACE            Include the DosPTrace function.
  2404.  
  2405.    INCL_ERRORS              Include all MS OS/2 version 1.1 error constants.
  2406.  
  2407.    INCL_FONTFILEFORMAT      Include the font-file structures.
  2408.  
  2409.    INCL_GPI                 Include all MS OS/2 version 1.1
  2410.                             graphics-programming-interface functions (Gpi).
  2411.  
  2412.    INCL_GPIBITMAPS          Include the bitmap and pel functions.
  2413.  
  2414.    INCL_GPICONTROL          Include the basic presentation-space-control
  2415.                             functions.
  2416.  
  2417.    Constant                 Meaning
  2418.    ──────────────────────────────────────────────────────────────────────────
  2419. 
  2420.    INCL_GPICORRELATION      Include the pick-aperture, boundary, and
  2421.                             correlation functions.
  2422.  
  2423.    INCL_GPIERRORS           Include the Gpi-function error constants.
  2424.  
  2425.    INCL_GPILCIDS            Include the physical- and logical-font functions.
  2426.  
  2427.    INCL_GPILOGCOLORTABLE    Include the logical-color-table functions.
  2428.  
  2429.    INCL_GPIMETAFILES        Include the metafile functions.
  2430.  
  2431.    INCL_GPIPATHS            Include the path and clipping functions.
  2432.  
  2433.    INCL_GPIPRIMITIVES       Include the drawing-primitive and
  2434.                             primitive-attribute functions.
  2435.  
  2436.    INCL_GPIREGIONS          Include the region and clipping functions.
  2437.  
  2438.    Constant                 Meaning
  2439.    ──────────────────────────────────────────────────────────────────────────
  2440. 
  2441.    INCL_GPISEGEDITING       Include the segment-editing functions.
  2442.  
  2443.    INCL_GPISEGMENTS         Include the segment-control and drawing
  2444.                             functions.
  2445.  
  2446.    INCL_GPITRANSFORMS       Include the transformation and
  2447.                             transform-conversion functions.
  2448.  
  2449.    INCL_KBD                 Include all MS OS/2 version 1.1 keyboard
  2450.                             functions (Kbd).
  2451.  
  2452.    INCL_MOU                 Include all MS OS/2 version 1.1 mouse functions
  2453.                             (Mou).
  2454.  
  2455.    INCL_NOCOMMON            Exclude any function group not explicitly
  2456.                             defined.
  2457.  
  2458.    INCL_PM                  Include all MS OS/2 version 1.1 Presentation
  2459.    Constant                 Meaning
  2460.    ──────────────────────────────────────────────────────────────────────────
  2461.   INCL_PM                  Include all MS OS/2 version 1.1 Presentation
  2462.                             Manager functions and structures.
  2463.  
  2464.    INCL_SHLERRORS           Include the shell error constants.
  2465.  
  2466.    INCL_SUB                 Include all MS OS/2 version 1.1 video, keyboard,
  2467.                             and mouse functions (Vio, Kbd, and Mou).
  2468.  
  2469.    INCL_VIO                 Include all MS OS/2 version 1.1 video functions
  2470.                             (Vio).
  2471.  
  2472.    INCL_WIN                 Include all MS OS/2 version 1.1 window functions
  2473.                             (Win).
  2474.  
  2475.    INCL_WINACCELERATORS     Include the keyboard-accelerator functions.
  2476.  
  2477.    INCL_WINATOM             Include the atom-manager functions.
  2478.  
  2479.    INCL_WINBUTTONS          Include the button-control functions.
  2480.    Constant                 Meaning
  2481.    ──────────────────────────────────────────────────────────────────────────
  2482.   INCL_WINBUTTONS          Include the button-control functions.
  2483.  
  2484.    INCL_WINCATCHTHROW       Include the WinCatch and WinThrow support
  2485.                             functions.
  2486.  
  2487.    INCL_WINCLIPBOARD        Include the clipboard-manager functions.
  2488.  
  2489.    INCL_WINCOUNTRY          Include the country-support functions.
  2490.  
  2491.    INCL_WINCURSORS          Include the text-cursor functions.
  2492.  
  2493.    INCL_WINDIALOGS          Include the dialog-box functions.
  2494.  
  2495.    INCL_WINENTRYFIELDS      Include the entry-field functions.
  2496.  
  2497.    INCL_WINERRORS           Include the Win-function error constants.
  2498.  
  2499.    INCL_WINFRAMECTLS        Include the frame-control (title bar and size
  2500.                             border) functions.
  2501.    Constant                 Meaning
  2502.    ──────────────────────────────────────────────────────────────────────────
  2503.                            border) functions.
  2504.  
  2505.    INCL_WINFRAMEMGR         Include the frame-manager functions.
  2506.  
  2507.    INCL_WINHEAP             Include the heap-manager functions.
  2508.  
  2509.    INCL_WINHOOKS            Include the hook-manager functions.
  2510.  
  2511.    INCL_WININPUT            Include the mouse- and keyboard-input functions.
  2512.  
  2513.    INCL_WINLISTBOXES        Include the list-box-control functions.
  2514.  
  2515.    INCL_WINMENUS            Include the menu-control functions.
  2516.  
  2517.    INCL_WINMESSAGEMGR       Include the message-management functions.
  2518.  
  2519.    INCL_WINPOINTERS         Include the mouse-pointer functions.
  2520.  
  2521.    INCL_WINPROGRAMLIST      Include the shell-program-list API functions.
  2522.    Constant                 Meaning
  2523.    ──────────────────────────────────────────────────────────────────────────
  2524.   INCL_WINPROGRAMLIST      Include the shell-program-list API functions.
  2525.  
  2526.    INCL_WINRECTANGLES       Include the rectangle functions.
  2527.  
  2528.    INCL_WINSCROLLBARS       Include the scroll-bar-control functions.
  2529.  
  2530.    INCL_WINSHELLDATA        Include the shell-data functions.
  2531.  
  2532.    INCL_WINSTATICS          Include the static-control functions.
  2533.  
  2534.    INCL_WINSWITCHLIST       Include the shell-switch-list API functions.
  2535.  
  2536.    INCL_WINSYS              Include the system-value and color functions.
  2537.  
  2538.    INCL_WINTIMER            Include the timer functions.
  2539.  
  2540.    INCL_WINTRACKRECT        Include the WinTrackRect function.
  2541.  
  2542.    INCL_WINWINDOWMGR        Include the general window-management functions.
  2543.    Constant                 Meaning
  2544.    ──────────────────────────────────────────────────────────────────────────
  2545.   INCL_WINWINDOWMGR        Include the general window-management functions.
  2546.    ──────────────────────────────────────────────────────────────────────────
  2547.  
  2548.  
  2549.    To use a function within your program, you simply define the corresponding
  2550.    constant by using the #define directive before you include the os2.h file.
  2551.    For example, the following code fragment includes definitions for the
  2552.    memory-management and file-management functions:
  2553.  
  2554.    #define INCL_DOSMEMMGR
  2555.    #define INCL_DOSFILEMGR
  2556.    #include <os2.h>
  2557.  
  2558.    main( )
  2559.    {
  2560.        .
  2561.        .
  2562.        .
  2563.    }
  2564.  
  2565.    Once you have defined a constant, you can use any function, structure, or
  2566.    data type in that function group.
  2567.  
  2568.  
  2569.  
  2570.  ────────────────────────────────────────────────────────────────────────────
  2571.  PART 2  WINDOW MANAGER
  2572.  ────────────────────────────────────────────────────────────────────────────
  2573.    Chapter 4  Windows
  2574.    Chapter 5  Messages and Message Queues
  2575.    Chapter 6  Window Classes
  2576.    Chapter 7  Window Procedures
  2577.    Chapter 8  Mouse and Keyboard Input
  2578.    Chapter 9  Frame Windows
  2579.    Chapter 10  Control Windows
  2580.    Chapter 11  Title-Bar Controls
  2581.    Chapter 12  Button Controls
  2582.    Chapter 13  Entry-Field Controls
  2583.    Chapter 14  List-Box Controls
  2584.    Chapter 15  Static Controls
  2585.    Chapter 16  Scroll-Bar Controls
  2586.    Chapter 17  Menus
  2587.    Chapter 18  Accelerator Tables
  2588.    Chapter 19  Dialog Windows
  2589.    Chapter 20  Painting and Drawing
  2590.    Chapter 21  Drawing in Windows
  2591.    Chapter 22  Mouse Pointers and Icons
  2592.    Chapter 23  Cursors
  2593.    Chapter 24  Printing
  2594.    Chapter 25  Heaps
  2595.    Chapter 26  Clipboard
  2596.    Chapter 27  Dynamic Data Exchange
  2597.    Chapter 28  Hooks
  2598.    Chapter 29  Help
  2599.  
  2600.  
  2601.  
  2602.  ────────────────────────────────────────────────────────────────────────────
  2603.  Chapter 4  Windows
  2604.  
  2605.         4.1     Introduction
  2606.         4.2     About Windows
  2607.             4.2.1     Desktop Windows
  2608.             4.2.2     Application Windows
  2609.             4.2.3     Window Creation
  2610.                 4.2.3.1    Window-Creation Functions
  2611.                 4.2.3.2    Window-Creation Messages
  2612.             4.2.4     Window Handles
  2613.             4.2.5     Window Size and Position
  2614.             4.2.6     Window Styles
  2615.             4.2.7     Window Destruction
  2616.             4.2.8     Locked Windows
  2617.             4.2.9     Disabled Windows
  2618.         4.3     System-Modal Windows
  2619.             4.3.1     Window Data
  2620.             4.3.2     Subclassed Windows
  2621.             4.3.3     Window Relationships
  2622.                 4.3.3.1    Parent-Child Relationship
  2623.                 4.3.3.2    Ownership
  2624.                 4.3.3.3    Object Windows
  2625.             4.3.4     Visibility
  2626.             4.3.5     Size
  2627.             4.3.6     Position
  2628.                 4.3.6.1    Size and Position Messages
  2629.             4.3.7     Z Order
  2630.             4.3.8     Maximized and Minimized Windows
  2631.             4.3.9     Redrawing Windows
  2632.             4.3.10    System Commands
  2633.         4.4     Using Windows
  2634.             4.4.1     Creating a Window
  2635.             4.4.2     Creating a Frame Window
  2636.             4.4.3     Destroying a Window
  2637.             4.4.4     Setting and Querying Window Data
  2638.             4.4.5     Creating a Top-Level Window
  2639.             4.4.6     Creating an Object Window
  2640.             4.4.7     Changing the Parent Window
  2641.             4.4.8     Finding a Parent, Child, or Owner Window
  2642.             4.4.9     Setting an Owner Window
  2643.             4.4.10    Finding a Child or Owned Window
  2644.             4.4.11    Enumerating Top-Level Windows
  2645.             4.4.12    Moving and Sizing a Window
  2646.             4.4.13    Moving a Window in a Stack of Windows
  2647.             4.4.14    Showing and Hiding a Window
  2648.             4.4.15    Maximizing, Minimizing, and Restoring a Window
  2649.         4.5     Summary
  2650.             4.5.1     Window Functions
  2651.             4.5.2     Standard Window Messages
  2652.             4.5.3     Relationship Functions
  2653.             4.5.4     Functions for Moving, Sizing, and Changing
  2654.             4.5.5     Messages for Moving, Sizing, and Changing
  2655.  
  2656.  4.1  Introduction
  2657.  
  2658.    This chapter describes the portions of MS OS/2 that let you create and use
  2659.    windows; manage relationships between windows; and size, move, and display
  2660.    windows in your Presentation Manager application. You should also be
  2661.    familiar with the following topics:
  2662.  
  2663.    ■  Standard user-interface guidelines
  2664.  
  2665.    ■  Application initialization and termination
  2666.  
  2667.    ■  Messages and message queues
  2668.  
  2669.    ■  Window classes and window procedures
  2670.  
  2671.  
  2672.  4.2  About Windows
  2673.  
  2674.    A window is a rectangular area of the screen where an application displays
  2675.    output and receives input from the user. You might think of a window as a
  2676.    "graphics terminal" that shares the screen with other terminals. Only one
  2677.    "terminal" is active at a time, and when it is, a user can use the mouse
  2678.    and keyboard to interact with the application that owns the terminal.
  2679.  
  2680.    Unlike a graphics terminal, however, a window must be created by an
  2681.    application before it can be used. MS OS/2 does not create a window by
  2682.    default. This means that one of the first tasks of a Presentation Manager
  2683.    application is to create a window.
  2684.  
  2685.  4.2.1  Desktop Windows
  2686.  
  2687.    MS OS/2 automatically creates two windows: the desktop window and the
  2688.    desktop-object window. The desktop window is the base (bottom-most) window
  2689.    in the Presentation Manager session. It is the window that paints the
  2690.    background for this session. It serves as the base for all windows created
  2691.    and displayed by applications. The desktop-object window is like a desktop
  2692.    window that is never displayed. It serves as a base for windows that
  2693.    coordinate the activity of other windows that are not displayed.
  2694.  
  2695.  4.2.2  Application Windows
  2696.  
  2697.    Every application creates at least one window, called the main window, to
  2698.    serve as the "graphics terminal" for the application. The application also
  2699.    creates many other windows either directly or indirectly to carry out
  2700.    tasks related to the main window. In fact, most windows used by an
  2701.    application are composed of several different windows. Each window plays a
  2702.    part in displaying output and receiving input from the user.
  2703.  
  2704.    Typically, an application's main window is made up of several windows
  2705.    acting together as one. The main window is usually a frame window that
  2706.    contains a client window and one or more control windows, such as a title
  2707.    bar and a System menu.
  2708.  
  2709.    An application can use several types of windows: frame windows, client
  2710.    windows, control windows, dialog windows, message boxes, and menus.
  2711.  
  2712.    A frame window is a special window that the application uses as the base
  2713.    when constructing a main window or other composite window. A frame window
  2714.    provides basic features, such as borders and system-command processing,
  2715.    that a main window needs to conform to the MS OS/2 user-interface
  2716.    guidelines.
  2717.  
  2718.    A dialog window is a frame window that contains one or more control
  2719.    windows. Dialog windows are used almost exclusively for prompting the user
  2720.    for input. An application usually creates a dialog window when it needs
  2721.    additional information to complete a command. It then destroys the dialog
  2722.    window when the requested information has been entered.
  2723.  
  2724.    A message box is a frame window that an application uses to display a
  2725.    note, caution, or warning to the user. Message boxes are commonly used to
  2726.    inform the user of problems the application encounters while carrying out
  2727.    a task.
  2728.  
  2729.    A client window is the window in which the application displays the
  2730.    current document or data. For example, a desktop-publishing application
  2731.    displays the current page of a document in a client window. Most
  2732.    applications create at least one client window. The application must
  2733.    process input to the window and then display output.
  2734.  
  2735.    A control window is any window used in conjunction with another window to
  2736.    carry out useful input or output tasks, such as displaying messages or
  2737.    reading text. MS OS/2 provides several predefined control-window classes
  2738.    that can be used to create control windows. Control windows include
  2739.    buttons, entry fields, list boxes, menus, scroll bars, static text, and
  2740.    title bars.
  2741.  
  2742.    A menu is a control window that presents a list of commands and other
  2743.    menus to the user. The user chooses commands from the list by using a
  2744.    mouse or keyboard. The application then carries out the chosen task.
  2745.  
  2746.    Many simple applications create only a main window. The application
  2747.    manages the client window and allows the frame and control windows to
  2748.    operate as defined by MS OS/2.
  2749.  
  2750.  4.2.3  Window Creation
  2751.  
  2752.    An application creates windows by using a window-creation function, such
  2753.    as WinCreateWindow, and supplying information about the window to be
  2754.    created. An application can create one or more windows in any thread for
  2755.    which it has created a message queue. An application creates a message
  2756.    queue for a thread by using the WinCreateMsgQueue function after
  2757.    initializing the application for Presentation Manager by using the
  2758.    WinInitialize function.
  2759.  
  2760.    The following information must be supplied when creating a window:
  2761.  
  2762.    ■  Window class
  2763.  
  2764.    ■  Window name
  2765.  
  2766.    ■  Parent window
  2767.  
  2768.    ■  Window position relative to the parent window
  2769.  
  2770.    ■  Window position relative to its sibling windows (Z order)
  2771.  
  2772.    ■  Window width and height
  2773.  
  2774.    ■  Window styles
  2775.  
  2776.    ■  Owner window
  2777.  
  2778.    ■  Window identifier
  2779.  
  2780.    ■  Class-specific data
  2781.  
  2782.    Every window belongs to a window class. The window class defines how the
  2783.    window behaves and appears when operating. The chief component of the
  2784.    window class is the window procedure. The window procedure is a function
  2785.    that receives and processes all input and requests for action sent to the
  2786.    window by the system. The window class also defines the class styles.
  2787.    These tell MS OS/2 what initial window styles to give a window created
  2788.    with this class.
  2789.  
  2790.    A window can have a name. A window name is a text string that identifies
  2791.    the window for the user. The window name is typically displayed in the
  2792.    window or in a title bar within the window. How the name is used depends
  2793.    on the window class.
  2794.  
  2795.    Every window created has a parent window. The parent window provides the
  2796.    coordinate system used for positioning the window and defines the
  2797.    relationship the new window has with other windows in the system. The
  2798.    parent window also affects the behavior and appearance of the window. For
  2799.    example, when the parent window is hidden, the child window is also
  2800.    hidden.
  2801.  
  2802.    Every window has a position, size, and Z-order position. The position
  2803.    specifies the location on the screen of the window's lower-left corner.
  2804.    This position is relative to the lower-left corner of the parent window
  2805.    (in pels). A window's size is the width and height in the window (in
  2806.    pels). A window's Z-order position specifies the position of the window in
  2807.    the stack of overlapping windows. The window at the top of the Z order
  2808.    overlaps all sibling windows (that is, windows having the same parent
  2809.    window). A window at the bottom of the Z order is overlapped by all
  2810.    sibling windows. An application sets a window's Z-order position by
  2811.    placing it behind a given sibling window.
  2812.  
  2813.    Every window can have a style. The window style specifies how the window
  2814.    behaves or appears. For example, a window style can specify whether the
  2815.    window is visible or invisible when first created. A few window styles
  2816.    apply to all windows, but most apply to windows of specific window
  2817.    classes. The window procedure for that class interprets the style.
  2818.  
  2819.    A window can be owned by another window. An owner window is similar to a
  2820.    parent window, but it does not affect the behavior or appearance of the
  2821.    window in the same way. The owner window usually coordinates the activity
  2822.    of a window so that it can operate in conjunction with other windows. The
  2823.    window sends messages about its state to its owner window; the owner
  2824.    window sends messages about what action to carry out next.
  2825.  
  2826.    A window can have a window identifier. A window identifier uniquely
  2827.    identifies a window that operates in conjunction with other windows. A
  2828.    window identifier is especially useful if a window sends information to
  2829.    the owner window.
  2830.  
  2831.    A window can have class-specific data. This data further defines how the
  2832.    window behaves and appears when first created. The system passes
  2833.    class-specific data to the window procedure. The window procedure then
  2834.    applies the data to the new window.
  2835.  
  2836.    4.2.3.1  Window-Creation Functions
  2837.  
  2838.    The basic window-creation function is WinCreateWindow. The WinCreateWindow
  2839.    function takes window class, style, size, and position information and
  2840.    creates a new window. All other window-creation functions, such as
  2841.    WinCreateStdWindow and WinCreateDlg, supply some of this information by
  2842.    default and create windows of a specific class or style.
  2843.  
  2844.    Although WinCreateWindow provides the most direct means of creating a
  2845.    window, most applications do not use it. Instead, they typically use the
  2846.    WinWinCreateStdWindow function to create a main window and use the
  2847.    WinDlgBox or WinCreateDlg function to create dialog windows.
  2848.  
  2849.    The WinCreateMenu, WinLoadMenu, WinLoadDlg, WinMessageBox, and
  2850.    WinCreateFrameControls functions also create windows. Each of these
  2851.    functions substitutes for one or more calls to the WinCreateWindow
  2852.    function required to create a given window. For example, you can create a
  2853.    frame window, one or more control windows, and a client window, all in a
  2854.    single call to WinCreateStdWindow.
  2855.  
  2856.    4.2.3.2  Window-Creation Messages
  2857.  
  2858.    The system sends messages to the window procedure as it creates a window.
  2859.    Each window procedure receives a WM_CREATE message, specifying that the
  2860.    window is being created.
  2861.  
  2862.    The system also sends a WM_ADJUSTWINDOWPOS message, specifying the size
  2863.    and position for the window. This message allows the window procedure to
  2864.    adjust the size and position before they are actually applied to the
  2865.    window.
  2866.  
  2867.    The system also sends other messages. The number and order of these
  2868.    messages depend on the window class and style and on the function used to
  2869.    create the window.
  2870.  
  2871.  4.2.4  Window Handles
  2872.  
  2873.    When a window is created, the creation function returns a window handle. A
  2874.    window handle uniquely identifies the window and can be used in functions
  2875.    to direct the action of the function to the window. Window handles have
  2876.    the data type HWND; applications must use this type when declaring the
  2877.    variables that hold window handles.
  2878.  
  2879.    There are several special constants that can be used in place of a window
  2880.    handle in certain functions. For example, HWND_DESKTOP can be used in the
  2881.    WinCreateWindow function to specify the desktop window as the new window's
  2882.    parent window. Similarly, HWND_OBJECT represents the desktop-object
  2883.    window. HWND_TOP and HWND_BOTTOM represent the top and bottom positions
  2884.    when setting the Z-order position for a window.
  2885.  
  2886.    Although the NULL constant is not a window handle, it can be used in some
  2887.    functions to specify that no window is affected. For example, NULL can be
  2888.    used in the WinCreateWindow function to specify that there is no owner
  2889.    window. Some functions may return NULL, indicating that the given action
  2890.    applies to no window.
  2891.  
  2892.  4.2.5  Window Size and Position
  2893.  
  2894.    A window's size and position can be expressed as a bounding rectangle,
  2895.    given in coordinates relative to its parent window. The window's size and
  2896.    position can be explicitly specified when it is created, or the system can
  2897.    use default values. The window's size and position can be changed at any
  2898.    time.
  2899.  
  2900.    The default coordinate system for a window specifies that the point (0,0)
  2901.    is at the window's lower-left corner; coordinates increase upward and to
  2902.    the right.
  2903.  
  2904.    When two sibling windows overlap, the system must specify which window is
  2905.    displayed in front. This ordering of sibling windows is known as the Z
  2906.    order. For more information about Z order, see Section 4.3.7.
  2907.  
  2908.  4.2.6  Window Styles
  2909.  
  2910.    A window style is a value that specifies how a window behaves or appears
  2911.    in a given situation. Window styles let applications adapt windows of a
  2912.    given class for special circumstances. For example, an application can
  2913.    give a window the style WS_SYNCPAINT to cause it to paint immediately
  2914.    whenever any portion of the window becomes invalid. A window normally
  2915.    paints only if there are no messages waiting in the message queue.
  2916.  
  2917.    An application usually sets the window style when it creates the window.
  2918.    It can also set the window style after creation by using the WinShowWindow
  2919.    and WinSetWindowULong functions. MS OS/2 provides several standard window
  2920.    styles that apply to all windows. It also provides many styles for the
  2921.    predefined frame and control windows. The frame and control styles are
  2922.    unique to each predefined window class and can be used only for windows
  2923.    belonging to the corresponding class.
  2924.  
  2925.    Initially, the class styles of the window class used to create the window
  2926.    determine the window styles of the new window. If the window class has the
  2927.    style CS_SYNCPAINT, all windows created using that class have the style
  2928.    WS_SYNCPAINT by default.
  2929.  
  2930.    MS OS/2 has the following standard window styles:
  2931.  
  2932. ╓┌─┌───────────────────┌─────────────────────────────────────────────────────╖
  2933.    Style               Description
  2934.    ──────────────────────────────────────────────────────────────────────────
  2935.    WS_VISIBLE          Makes the window visible. MS OS/2 draws the window on
  2936.                        the screen unless overlapping windows completely
  2937.                        obscure it. Windows without this style are hidden. If
  2938.                        overlapping windows completely obscure the window, the
  2939.                        window is still considered to be visible. Visibility
  2940.                        simply means that MS OS/2 draws the window if it can.
  2941.  
  2942.    Style               Description
  2943.    ──────────────────────────────────────────────────────────────────────────
  2944. 
  2945.    WS_DISABLED         Disables mouse and keyboard input to the window. This
  2946.                        style is used to temporarily prevent the user from
  2947.                        using the window.
  2948.  
  2949.    WS_CLIPCHILDREN     Prevents a window from painting over its child
  2950.                        windows.
  2951.  
  2952.    WS_CLIPSIBLINGS     Prevents a window from painting over its sibling
  2953.                        windows.
  2954.  
  2955.    WS_PARENTCLIP       Prevents a window from painting over its parent
  2956.                        window.
  2957.  
  2958.    WS_SAVEBITS         Saves the image under the window as a bitmap. When the
  2959.                        window is moved or hidden, the system restores the
  2960.                        image by copying the bits.
  2961.  
  2962.    WS_SYNCPAINT        Causes the window to immediately receive WM_PAINT
  2963.    Style               Description
  2964.    ──────────────────────────────────────────────────────────────────────────
  2965.   WS_SYNCPAINT        Causes the window to immediately receive WM_PAINT
  2966.                        messages after a part of the window becomes invalid.
  2967.                        Without this style, the window receives WM_PAINT
  2968.                        messages only if no other message is waiting to be
  2969.                        processed.
  2970.  
  2971.    WS_MINIMIZED        Reduces the window to the minimum size.
  2972.  
  2973.    WS_MAXIMIZED        Enlarges the window to the maximum size.
  2974.  
  2975.    WS_GROUP            Identifies the window as the first dialog item in a
  2976.                        group of dialog items. This style is used with
  2977.                        controls in dialog windows to permit the user to move
  2978.                        among the controls by pressing the direction keys.
  2979.  
  2980.    WS_TABSTOP          Identifies the window as a tabstop window. This style
  2981.                        is used with controls in dialog windows to permit the
  2982.                        user to move to the control by pressing the TAB key.
  2983.    ──────────────────────────────────────────────────────────────────────────
  2984.    Style               Description
  2985.    ──────────────────────────────────────────────────────────────────────────
  2986.   ──────────────────────────────────────────────────────────────────────────
  2987.  
  2988.  
  2989.  4.2.7  Window Destruction
  2990.  
  2991.    An application can destroy the windows it has created. When a window is
  2992.    destroyed, the system hides the window if it is visible, and then removes
  2993.    any internal data associated with the window. This invalidates the window
  2994.    handle; it can no longer be used in functions. An application destroys a
  2995.    window by using the WinDestroyWindow function.
  2996.  
  2997.    Most applications destroy the windows they create soon after creating
  2998.    them. For example, an application usually destroys any dialog windows as
  2999.    soon as the application has sufficient input from the user to continue its
  3000.    task. An application eventually destroys the main window of the
  3001.    application (before terminating). In general, an application must destroy
  3002.    all the windows it creates.
  3003.  
  3004.    Destroying a window does not affect the window class from which the window
  3005.    is created. New windows can still be created using that class and any
  3006.    existing windows of that class continue to operate.
  3007.  
  3008.    Destroying a window also destroys that window's child and owned windows.
  3009.    The WinDestroyWindow function sends a WM_DESTROY message to the window,
  3010.    which in turn sends the same message to all its child and owned windows.
  3011.    Each child and owned window passes the message on to other child and owned
  3012.    windows. In this way, all descendant windows of the window being destroyed
  3013.    are also destroyed.
  3014.  
  3015.    Before destroying a window, an application should save or remove any data
  3016.    associated with the window and release any resources. For example, a
  3017.    presentation space created for the window by the WinGetPS function must be
  3018.    released by calling the WinReleasePS function. This must be done before
  3019.    calling the WinDestroyWindow function. If a presentation space is
  3020.    associated with the device context for the window, the application should
  3021.    disassociate or destroy the presentation space by using the GpiAssociate
  3022.    or GpiDestroyPS function before calling WinDestroyWindow. Failing to
  3023.    release a resource can cause an error.
  3024.  
  3025.    The WinDestroyWindow function may send several messages to a window. The
  3026.    following is a list of possible messages sent by WinDestroyWindow:
  3027.  
  3028.    Message        Description
  3029.    ──────────────────────────────────────────────────────────────────────────
  3030.    WM_DESTROY     Always sent to the window being destroyed after it has been
  3031.                   hidden, but before its child windows have been destroyed.
  3032.  
  3033.    WM_ACTIVATE    Sent with the first message parameter equal to FALSE if the
  3034.                   window being destroyed is the active window.
  3035.  
  3036.    WM_OTHERWINDOWDESTROYED
  3037.                   Sent to all main windows of the window being destroyed and
  3038.                   to its descendant windows, if the window being destroyed
  3039.                   has been registered with the WinRegisterWindowDestroy
  3040.                   function.
  3041.  
  3042.    WM_RENDERALLFMTS
  3043.                   Sent if the clipboard owner is being destroyed and there
  3044.                   are unrendered formats on the clipboard.
  3045.    ──────────────────────────────────────────────────────────────────────────
  3046.  
  3047.    If the window being destroyed is the active window, both the active and
  3048.    focus states are transferred to another window. The window that becomes
  3049.    the active window is the next window (as defined by the ALT+ESC key
  3050.    combination). The new active window determines which window has the input
  3051.    focus.
  3052.  
  3053.  4.2.8  Locked Windows
  3054.  
  3055.    A window can be locked. An application typically locks a window to prevent
  3056.    it from being destroyed. This is useful whenever a window needs to access
  3057.    data that may be lost if the associated window is destroyed. An
  3058.    application can lock a window by using the WinLockWindow function.
  3059.  
  3060.    Each window has a lock count. When a window is created, its lock count is
  3061.    set to zero, meaning that the window is unlocked. An application can use
  3062.    the WinLockWindow function to increment or decrement the lock count. If
  3063.    the lock count is greater than zero, the window is locked. If the lock
  3064.    count is zero, the window is unlocked. The lock count can never be less
  3065.    than zero. An application can retrieve the current lock count by using the
  3066.    WinQueryWindowLockCount function.
  3067.  
  3068.    The WinQueryWindow, WinQueryActiveWindow, and WinQuerySysModalWindow
  3069.    functions also lock a window if specified.
  3070.  
  3071.  4.2.9  Disabled Windows
  3072.  
  3073.    A window can be disabled. A disabled window temporarily receives no
  3074.    keyboard or mouse input. An application typically disables a window to
  3075.    prevent the user from using the window. For example, the application may
  3076.    disable a push button in a dialog window to prevent the user from choosing
  3077.    it. An application can enable a disabled window at any time. Enabling a
  3078.    window restores normal input. An application enables or disables a window
  3079.    by using the WinEnableWindow function.
  3080.  
  3081.    By default, a window is enabled when created. The WS_DISABLED style can be
  3082.    specified, however, to disable a new window. If an application uses the
  3083.    WinEnableWindow function to disable an existing window, that window also
  3084.    loses the keyboard focus. The keyboard focus is set to NULL, meaning no
  3085.    window has the focus. If a child window or other descendant window has the
  3086.    keyboard focus, the descendant window loses it when the window is
  3087.    disabled.
  3088.  
  3089.    An application can determine whether a window is disabled by using the
  3090.    WinIsWindowEnabled function.
  3091.  
  3092.  
  3093.  4.3  System-Modal Windows
  3094.  
  3095.    System-modal windows require the user to respond immediately to warnings
  3096.    about the state of the system. Because the system-modal window receives
  3097.    all keyboard and mouse input, all other windows are effectively disabled
  3098.    when the system-modal window is set; the user cannot continue working in
  3099.    other windows until the system-modal window has been cleared. An
  3100.    application sets and clears the system-modal window by using the
  3101.    WinSetSysModalWindow function.
  3102.  
  3103.    Due to its absolute control of input, applications must use care when
  3104.    setting a system-modal window. Ideally, an application uses a system-modal
  3105.    window only when there is danger of losing data if the user does not
  3106.    respond to the problem immediately.
  3107.  
  3108.    Although an application can destroy a system-modal window, the new active
  3109.    window will also be the new system-modal window. An application can also
  3110.    make another window active while the system-modal window exists. Again,
  3111.    the new active window is also the new system-modal window. In general,
  3112.    once a system-modal window is set, a system-modal window will continue to
  3113.    exist in the Presentation Manager session until explicitly cleared.
  3114.  
  3115.  4.3.1  Window Data
  3116.  
  3117.    Every window has an associated data structure. The window data structure
  3118.    contains all the information specified for the window when it was created
  3119.    and any additional information supplied for the window since creation.
  3120.    Although the exact number and meaning of fields in the window data
  3121.    structure is private to the system, an application can directly access any
  3122.    of the following fields:
  3123.  
  3124.    ■  Pointer to window-class data structure
  3125.  
  3126.    ■  Pointer to window procedure
  3127.  
  3128.    ■  Parent-window handle
  3129.  
  3130.    ■  Owner-window handle
  3131.  
  3132.    ■  Handle of first child window
  3133.  
  3134.    ■  Handle of next sibling window
  3135.  
  3136.    ■  Window size and position (expressed as a rectangle)
  3137.  
  3138.    ■  Lock count
  3139.  
  3140.    ■  Window style
  3141.  
  3142.    ■  Window identifier
  3143.  
  3144.    ■  Update-region handle
  3145.  
  3146.    ■  Message-queue handle
  3147.  
  3148.    An application can examine and modify these fields by using functions such
  3149.    as WinQueryWindowUShort and WinSetWindowUShort. These functions let an
  3150.    application access fields, such as the lock count, which are stored as
  3151.    16-bit integers. Other functions let an application access fields
  3152.    containing 32-bits integers and pointers. There are several fields that
  3153.    indirectly affect the fields in the window data structure. For example,
  3154.    the WinLockWindow function modifies the lock-count field; the
  3155.    WinSubclassWindow function replaces the window-procedure pointer.
  3156.  
  3157.    An application can extend the number of available fields in the window
  3158.    data structure by specifying a count of extra bytes when it registers the
  3159.    corresponding window class. The window procedure can then use these bytes
  3160.    to store information about the window. Functions such as
  3161.    WinQueryWindowUShort and WinSetWindowUShort give direct access to the
  3162.    extra bytes.
  3163.  
  3164.    If a window needs more than a few bytes of storage added to the window
  3165.    data structure, using extra bytes alone is not the best solution. One
  3166.    common alternative is to dynamically allocate some memory and then store a
  3167.    pointer to that dynamic memory in the extra bytes of the window data
  3168.    structure.
  3169.  
  3170.  4.3.2  Subclassed Windows
  3171.  
  3172.    A subclassed window is any window whose original window procedure has been
  3173.    replaced with another window procedure. The original window procedure is
  3174.    specified by the window class used to create the window. An application
  3175.    typically subclasses a window (replaces the window procedure) so that it
  3176.    can support additional capabilities in a window created with a given
  3177.    class. For example, an application may subclass a push-button control so
  3178.    that it can add sound when the user chooses the button. An application
  3179.    subclasses a window by using the WinSubclassWindow function.
  3180.  
  3181.    Typically, a window procedure used to subclass a window will pass most (if
  3182.    not all) messages on to the original window procedure. The usual goal of
  3183.    subclassing is to add capability. The WinSubclassWindow function returns
  3184.    the address of the original window procedure, making it easy to call the
  3185.    original function from the new window procedure. The following code
  3186.    fragment shows the general format of a window procedure used for
  3187.    subclassing:
  3188.  
  3189.    PFNWP pfnwp;
  3190.  
  3191.    main() {
  3192.  
  3193.        /* Subclass in main function or other window procedure. */
  3194.  
  3195.        pfnwp = WinSubclassWindow(hwnd, MySubClass);
  3196.    }
  3197.  
  3198.    MRESULT CALLBACK MySubClass(hwnd, usMessage, mp1, mp2)
  3199.    HWND hwnd;
  3200.    USHORT usMessage;
  3201.    MPARAM mp1;
  3202.    MPARAM mp2;
  3203.    {
  3204.        switch (usMessage) {
  3205.          .
  3206.          . /* Process messages. */
  3207.          .
  3208.        }
  3209.        return (pfnwp(hwnd, usMessage, mp1, mp2));
  3210.    }
  3211.  
  3212.    Note that the replacement window procedure calls the original window
  3213.    procedure instead of the WinDefWindowProc function.
  3214.  
  3215.    An application can subclass only one window at a time. It cannot subclass
  3216.    an entire class.
  3217.  
  3218.  4.3.3  Window Relationships
  3219.  
  3220.    Window relationships define how windows interact with each other on the
  3221.    screen and through messages. There are parent-child window relationships
  3222.    and ownership relationships.
  3223.  
  3224.    The parent-child relationship determines how a window looks when drawn on
  3225.    the screen. It also determines what happens to a window when a related
  3226.    window is destroyed or hidden. The parent-child rules apply to all windows
  3227.    at all times and cannot be modified.
  3228.  
  3229.    Ownership determines how windows communicate using messages. Cooperative
  3230.    windows define the rules of ownership and then carry them out. Although
  3231.    some windows, such as windows belonging to the preregistered, public
  3232.    window class WC_FRAME, have quite complex rules of ownership, the
  3233.    application ordinarily defines the ownership rules.
  3234.  
  3235.    4.3.3.1  Parent-Child Relationship
  3236.  
  3237.    Most windows have a parent window. (The exceptions to this rule are the
  3238.    desktop and the desktop-object windows. These windows, created by the
  3239.    system when it first starts, have no parent windows.) An application sets
  3240.    the parent window when it creates the window; the system uses the parent
  3241.    window to determine where and how to draw the new window, as well as when
  3242.    to destroy the window.
  3243.  
  3244.    A window is drawn relative to its parent window. The coordinates given to
  3245.    specify the position of a window's lower-left corner are relative to the
  3246.    lower-left corner of its parent window. For example, a window whose
  3247.    coordinates are (10,10) is placed 10 pels left and 10 pels up from the
  3248.    lower-left corner of its parent window. A window is a top-level window if
  3249.    its parent window is the desktop window. Top-level windows are drawn
  3250.    relative to the lower-left corner of the screen (the desktop window's
  3251.    lower-left corner).
  3252.  
  3253.    Windows with the same parent window are called sibling windows. All
  3254.    top-level windows are sibling windows since they share a common parent
  3255.    window, the desktop window. Sibling windows can overlap; an application or
  3256.    a user can arrange the windows so that some appear on top of others. Every
  3257.    sibling window has a Z-order position that specifies where it lies in the
  3258.    stack of overlapping windows. The parent window for the sibling windows is
  3259.    always at the bottom of the stack.
  3260.  
  3261.    A window is clipped to its parent window. This means that no part of a
  3262.    child window is ever drawn outside of its parent window. If an application
  3263.    creates a child window that is larger than the parent window or positions
  3264.    a child window so that some or all of the window extends beyond the edges
  3265.    of the parent window, the system automatically clips (does not draw) the
  3266.    portion of the child window that extends beyond the edges. Depending on
  3267.    the window styles for a window, a window may also be clipped to its child
  3268.    and its sibling windows. When a window has the style WS_CLIPCHILDREN or
  3269.    WS_CLIPSIBLINGS, the system clips the window.
  3270.  
  3271.    A window is destroyed when its parent window is destroyed. When the parent
  3272.    window is destroyed, the system sends WM_DESTROY messages to each child
  3273.    window. This is convenient for composite windows (for example, the
  3274.    application's main window) since an application needs to destroy only the
  3275.    parent window; all the related windows, including the client window, are
  3276.    destroyed automatically. The parent window is always the last window to be
  3277.    destroyed. This allows the parent window to use any data saved or left
  3278.    behind by its child windows.
  3279.  
  3280.    While every window has only one parent window, a window can have any num-
  3281.    ber of child windows. Any child window can have child windows. Each child
  3282.    window in this chain of windows is a called a descendant window of the
  3283.    original parent window. Immediate child windows are child windows directly
  3284.    related to the parent window, not just descendant windows.
  3285.  
  3286.    An application can change a window's parent window at any time. Changing
  3287.    the parent window changes where and how the child window is drawn.
  3288.  
  3289.    4.3.3.2  Ownership
  3290.  
  3291.    Any window can have an owner window. An owner is a window, not necessarily
  3292.    a parent window, that controls some aspect of another window. Applications
  3293.    typically use ownership to establish a connection between windows so that
  3294.    together they can carry out useful tasks. For example, the title bar in an
  3295.    application's main window is owned by the frame window. Together they let
  3296.    the user move the entire main window by clicking the mouse in the title
  3297.    bar. An application can set the owner window when it creates the window,
  3298.    or it can set the owner window at a later time.
  3299.  
  3300.    Ownership establishes a relationship between windows that is independent
  3301.    of the parent-child relationship. Unlike parent and child windows, there
  3302.    are no predefined rules for how the owner and owned windows interact. The
  3303.    window procedures for the owner and owned windows must carry out any
  3304.    special interactions specified.
  3305.  
  3306.    The preregistered, public window classes provided by MS OS/2 recognize
  3307.    ownership. Control windows, created with classes such as WC_TITLEBAR and
  3308.    WC_SCROLLBAR, notify their owners of events; frame windows, created using
  3309.    the WC_FRAME class, receive and process notification messages from the
  3310.    control windows they own. For example, a title-bar control sends a
  3311.    notification message to its owner when it receives a mouse click. If the
  3312.    owner is a frame window, the frame window receives the notification
  3313.    message and prepares to move the frame window and its child windows.
  3314.  
  3315.    Owner and owned windows must be created by the same thread; that is, they
  3316.    must belong to the same message queue. Since ownership is independent of
  3317.    the parent-child relationship, the owner and owned windows do not have to
  3318.    be descendants of the same parent window. This means one window can be a
  3319.    descendant of the desktop window and the other a descendant of the
  3320.    desktop-object window. This can affect how windows are destroyed.
  3321.    Destroying the owner window does not necessarily destroy the owned window.
  3322.    An application must explicitly destroy any owned window that is not a
  3323.    descendant window of the owner.
  3324.  
  3325.    Frame windows often have owned windows that are not descendants (they are
  3326.    sibling windows instead). A frame window has the following special
  3327.    properties:
  3328.  
  3329.    ■  Destroys all owned windows, even if they are not descendants, when the
  3330.       frame window is destroyed.
  3331.  
  3332.    ■  Moves owned windows when the frame window moves. The owned windows that
  3333.       are not descendants maintain their position relative to the upper-left
  3334.       (not the usual lower-left) corner of the owner window. Any owned window
  3335.       with the style FS_NOMOVEWITHOWNER does not move.
  3336.  
  3337.    ■  Changes the Z-order position of all owned windows when the frame window
  3338.       changes.
  3339.  
  3340.    ■  Hides all owned windows when the frame window is minimized or hidden.
  3341.       Owned windows hidden in this way are restored when the frame window is
  3342.       restored.
  3343.  
  3344.    If an application needs the same special processing for its own window
  3345.    classes, it must provide that support in the window procedures for those
  3346.    classes.
  3347.  
  3348.    4.3.3.3  Object Windows
  3349.  
  3350.    Any descendant of the desktop-object window is called an object window. An
  3351.    object window is like any other window but it is not displayed.
  3352.    Applications typically use object windows to provide services for windows.
  3353.    For example, an application might use an object window to manage a shared
  3354.    database. The advantage of using an object window in this way is that a
  3355.    window can request information from the database by sending a message to
  3356.    the object window and receive a reply as a message.
  3357.  
  3358.    Because object windows are not displayed, the window procedure for an
  3359.    object window does not have to process input and paint messages. This
  3360.    means that an application can use object windows just as it would other
  3361.    objects in object-oriented environments. The object window processes
  3362.    messages that affect the data belonging to the object.
  3363.  
  3364.    The rules for parent-child relationship and ownership also apply to object
  3365.    windows. In particular, changing the parent window of an object window to
  3366.    the desktop window or to a descendant of the desktop window causes the
  3367.    system to display the window if it is visible.
  3368.  
  3369.  4.3.4  Visibility
  3370.  
  3371.    A window can be visible or invisible. The system displays visible windows
  3372.    on the screen. It hides invisible windows by not drawing them. If a window
  3373.    is visible, the user can supply input to the window and view output. If a
  3374.    window is invisible, the window is effectively disabled. An application
  3375.    sets a window's visibility state when it creates the window. Later, a user
  3376.    or the application can change these initial values.
  3377.  
  3378.    A window is visible if the style WS_VISIBLE is set for the window. An
  3379.    application can set this style when it creates the window. By default, the
  3380.    WinCreateWindow function creates invisible windows unless the WS_VISIBLE
  3381.    style is given. After a window is created, an application typically hides
  3382.    a window to hide the details of operation from the user. For example, an
  3383.    application may keep a new window invisible while it customizes the
  3384.    window's appearance.
  3385.  
  3386.    Even if a window is visible, the user may not be able to see the window on
  3387.    the screen. Other windows may completely overlap the window or the window
  3388.    may have been moved beyond the edge of the screen. The window is
  3389.    considered visible but it cannot be seen.
  3390.  
  3391.    A visible window is subject to the clipping rules established by its
  3392.    parent-child relationship. If the window's parent window is not visible,
  3393.    the window will not be visible. Since a child window is drawn relative to
  3394.    the parent's lower-left corner, if the parent window is moved beyond the
  3395.    edge of the screen, the child window will also move.
  3396.  
  3397.    A user may move only part of the parent window containing the child window
  3398.    off the edge of the screen, so although the window and its parent window
  3399.    are visible, the user may not be able to see them. An application
  3400.    determines whether the user can actually see a visible window by checking
  3401.    the window's current position.
  3402.  
  3403.  4.3.5  Size
  3404.  
  3405.    Every window has a size (width and height) given in pels. The size can be
  3406.    any integer value in the range 0 through 65,535. A window can have zero
  3407.    width and/or height. A window with zero width or height is not drawn on
  3408.    the screen even though it may be visible.
  3409.  
  3410.    Although an application can create very large windows, it should consider
  3411.    the size of the screen when choosing a window size. One way to choose an
  3412.    appropriate size is to use the WinGetMaxPosition function to retrieve the
  3413.    size of the maximized window. A window that is larger than its maximized
  3414.    size will also be larger than the screen.
  3415.  
  3416.    An application can retrieve the current size of the window by using the
  3417.    WinQueryWindowRect function.
  3418.  
  3419.  4.3.6  Position
  3420.  
  3421.    Every window has a position. The position is specified as the coordinates
  3422.    of the window's lower-left corner. The coordinates, sometimes called
  3423.    window coordinates, are always relative to the lower-left corner of the
  3424.    parent window.
  3425.  
  3426.    To improve drawing performance, a frame window may adjust its horizontal
  3427.    position so that it is a multiple of 8, relative to the screen origin (the
  3428.    lower-left corner of the screen). Coordinates that are multiples of 8
  3429.    correspond to byte boundaries in the screen-memory bitmap. It is usually
  3430.    faster to draw starting at a byte boundary. An application can override
  3431.    this action by using the FCF_NOBYTEALIGN style when creating the window.
  3432.  
  3433.    4.3.6.1  Size and Position Messages
  3434.  
  3435.    A window receives messages when it changes size or position. Before a
  3436.    change is actually made, the system may send a WM_ADJUSTWINDOWPOS
  3437.    message to allow the window procedure to make final adjustments to the
  3438.    window's size and position. This message includes an SWP structure that
  3439.    contains the width, height, and position requested. If the window
  3440.    procedure adjusts these values in the structure, the system uses the
  3441.    adjusted values to draw the new window. The WM_ADJUSTWINDOWPOS message is
  3442.    not sent if the change is a result of a call to the WinSetWindowPos
  3443.    function and the SWP_NOADJUST constant is specified.
  3444.  
  3445.    After a change has been made to a window, the system sends a WM_SIZE
  3446.    message to specify the new size of the window. If the window has the class
  3447.    style CS_MOVENOTIFY, the system also sends a WM_MOVE message. The WM_MOVE
  3448.    message includes the new position for the window. The system sends a
  3449.    WM_SHOW message if the visibility of the window has changed.
  3450.  
  3451.  4.3.7  Z Order
  3452.  
  3453.    Every window has a Z-order position. Imagine an axis extends outward from
  3454.    the screen toward the viewer. A window at the top of the Z order is
  3455.    displayed in front of its sibling windows when the windows overlap. A
  3456.    window at the bottom of the Z order is displayed behind its sibling
  3457.    windows when the windows overlap.
  3458.  
  3459.  4.3.8  Maximized and Minimized Windows
  3460.  
  3461.    A maximized window is a window that has been enlarged so it fills the
  3462.    screen. Although a window's size can be set so it exactly fills the
  3463.    screen, a maximized window is slightly different──the system automatically
  3464.    moves the window's title bar to the top of the screen and sets the
  3465.    WS_MAXIMIZED window style.
  3466.  
  3467.    A minimized window is a window whose size has been reduced so that it is
  3468.    exactly the size of an icon. Like a maximized window, a minimized window
  3469.    is more than just a window of a given size. The system typically moves the
  3470.    minimized window to the lower part of the screen and sets the WS_MINIMIZED
  3471.    style for that window. The lower part of the screen is sometimes call the
  3472.    icon area. The system moves a minimized window into the first available
  3473.    icon position in the icon area if no other position is specified.
  3474.  
  3475.    If a window is created with the styles WS_MAXIMIZED or WS_MINIMIZED, the
  3476.    system draws the window as a maximized or minimized window.
  3477.  
  3478.    An application can restore a maximized or minimized window to its previous
  3479.    size and position.
  3480.  
  3481.  4.3.9  Redrawing Windows
  3482.  
  3483.    After the system moves or changes the size of a window, it may invalidate
  3484.    all or part of the window. If at all possible, the system tries to
  3485.    preserve the contents of the window and simply copy them to the new
  3486.    position. But if a window's size has increased, the window must fill the
  3487.    area exposed by the size change. If a window has moved from behind an
  3488.    overlapping window, any area that was formerly obscured by the other
  3489.    window must be drawn. In these cases, the system invalidates the exposed
  3490.    areas and the window receives a WM_PAINT message.
  3491.  
  3492.    An application can require that the system invalidate the entire window
  3493.    for each move or size change by setting the CS_SIZEREDRAW class style in
  3494.    the corresponding window class. This class style is typically used for
  3495.    applications that use the window's current size and position to determine
  3496.    how to draw the window. For example, a clock application may always draw
  3497.    the face of the clock so that it exactly fills the window.
  3498.  
  3499.    An application can also explicitly specify which parts of the window to
  3500.    preserve during a move or size change. Before any change is made, the
  3501.    system sends a WM_CALCVALIDRECTS message to windows that do not have the
  3502.    style CS_SIZEREDRAW. This allows the window procedure to specify what part
  3503.    of the window to save and where to align it after the move or size change.
  3504.  
  3505.  4.3.10  System Commands
  3506.  
  3507.    An application that has a window with a System menu can change the size
  3508.    and position of that window by sending system commands. The system
  3509.    commands are usually generated by the user choosing commands from the
  3510.    System menu. An application can emulate the user action by sending a
  3511.    WM_SYSCOMMAND message to the window.
  3512.  
  3513.    Some of the system commands are listed here:
  3514.  
  3515.    Command           Description
  3516.    ──────────────────────────────────────────────────────────────────────────
  3517.    SC_SIZE           Starts a size command. The user can change the size of
  3518.                      the window by using the mouse or keyboard.
  3519.  
  3520.                      Starts a move command. The user can move the window by
  3521.                      using the mouse and keyboard.
  3522.  
  3523.    SC_MOVE           Starts a move command. The user can move the window by
  3524.                      using the mouse and keyboard.
  3525.  
  3526.    SC_MINIMIZE       Minimizes the window.
  3527.  
  3528.    SC_MAXIMIZE       Maximizes the window.
  3529.  
  3530.    SC_RESTORE        Restores a minimized or maximized window to its previous
  3531.                      size and position.
  3532.  
  3533.    SC_CLOSE          Closes the window. This command sends a WM_CLOSE message
  3534.                      to the window. The window carries out any steps needed
  3535.                      to clean up and destroy itself.
  3536.    ──────────────────────────────────────────────────────────────────────────
  3537.  
  3538.  
  3539.  4.4  Using Windows
  3540.  
  3541.    The following sections explain how to create and use windows in an
  3542.    application, how to manage ownership and parent-child window
  3543.    relationships, and how to move and size windows.
  3544.  
  3545.  4.4.1  Creating a Window
  3546.  
  3547.    You create windows by using the WinCreateWindow function.
  3548.  
  3549.    For all windows, the parent-child relationship is set when you create the
  3550.    window using the WinCreateWindow function or other window-creation
  3551.    function. You can set the ownership for a window at any time. (Note that a
  3552.    window does not need an owner window unless you want to establish a
  3553.    relationship other than the standard parent-child relationship for the
  3554.    window.)
  3555.  
  3556.    You can specify the initial size and position for a window when you create
  3557.    it. You can change these settings at any time.
  3558.  
  3559.  4.4.2  Creating a Frame Window
  3560.  
  3561.    Although WinCreateWindow can be used to create all windows, most
  3562.    applications do not call this function. Instead, they use the
  3563.    WinCreateStdWindow function to create frame windows and the WinDlgBox or
  3564.    WinCreateDlg function to create dialog windows.
  3565.  
  3566.  4.4.3  Destroying a Window
  3567.  
  3568.    You can destroy a window by using the WinDestroyWindow function. The
  3569.    following code fragment shows how to create and then destroy an
  3570.    entry-field control:
  3571.  
  3572.    HWND hwndMain;   /* application's main window */
  3573.    HWND hwnd;
  3574.  
  3575.    hwnd = WinCreateWindow(...);
  3576.  
  3577.    /* Read from the control. */
  3578.  
  3579.    WinDestroyWindow(hwnd);
  3580.  
  3581.  4.4.4  Setting and Querying Window Data
  3582.  
  3583.    You can examine the data associated with a window by using the
  3584.    WinQueryWindowUShort and WinQueryWindowULong functions.
  3585.  
  3586.    Each of these functions specifies a field to examine. The index value can
  3587.    be an integer representing a zero-based index or a constant (QW_) that
  3588.    specifies a specific field.
  3589.  
  3590.  4.4.5  Creating a Top-Level Window
  3591.  
  3592.    You can create a top-level window by setting the desktop window as the
  3593.    window's parent window. Almost all main windows for applications are
  3594.    top-level windows; the desktop window is frequently given in calls to the
  3595.    WinCreateStdWindow function.
  3596.  
  3597.    The following code fragment creates a top-level window for an application:
  3598.  
  3599.    /* Set the creation flags. */
  3600.  
  3601.    ULONG flCreationFlags =
  3602.        FCF_TITLEBAR |     /* title bar                     */
  3603.        FCF_SIZEBORDER |   /* size border                   */
  3604.        FCF_MINMAX |       /* minimize and maximize buttons */
  3605.        FCF_MENU |         /* menu                          */
  3606.        FCF_SYSMENU |      /* System menu                   */
  3607.        FCF_HORZSCROLL |   /* horizontal scroll bar         */
  3608.        FCF_VERTSCROLL; |  /* vertical scroll bar           */
  3609.  
  3610.    /*
  3611.     * Create a frame window with a client window that belongs to the
  3612.     * window class "MyPrivateClass".
  3613.     */
  3614.  
  3615.    hwndFrame = WinCreateStdWindow(
  3616.        HWND_DESKTOP,      /* owner is desktop window    */
  3617.        0L,                /* no styles for frame window */
  3618.        &flCreationFlags,  /* frame controls             */
  3619.        "MyPrivateClass",  /* window class for client    */
  3620.        "Sample Window",   /* window title               */
  3621.        0L,                /* no styles for client       */
  3622.        NULL,              /* use application's module   */
  3623.        1,                 /* resource ID                */
  3624.        &hwndClient);      /* client handle              */
  3625.  
  3626.  4.4.6  Creating an Object Window
  3627.  
  3628.    You can create an object window by using the WinCreateWindow function and
  3629.    setting the desktop-object window as the parent window.
  3630.  
  3631.    The following code fragment creates an object window:
  3632.  
  3633.    hwndObject = WinCreateWindow(
  3634.        HWND_OBJECT,       /* parent is object window       */
  3635.        "MyPrivateClass",  /* window class for client       */
  3636.        "Sample Window",   /* window title                  */
  3637.        0L,                /* no styles for object window   */
  3638.        0, 0,              /* lower-left corner             */
  3639.        0, 0,              /* width and height              */
  3640.        NULL,              /* no owner                      */
  3641.        HWND_TOP,          /* insert at top of Z order      */
  3642.        1,                 /* window ID                     */
  3643.        NULL,              /* no class-specific data        */
  3644.        NULL);             /* no presentation data          */
  3645.  
  3646.  4.4.7  Changing the Parent Window
  3647.  
  3648.    You can change a window's parent window by using the WinSetParent
  3649.    function. For example, an application that uses child windows to display
  3650.    documents may want only the active-document window to show a System menu.
  3651.    One way to do this is to change that menu's parent window back and forth
  3652.    between the document window and the object window when WM_ACTIVATE
  3653.    messages are received. This is shown in the following code fragment:
  3654.  
  3655.    case WM_ACTIVATE:
  3656.        hwndMenu = WinWindowFromID(hwnd, FID_MENU);
  3657.        if (SHORT1FROMMP(mp1) == TRUE)
  3658.            WinSetParent(hwndMenu, hwnd, TRUE);
  3659.        else
  3660.            WinSetParent(hwndMenu, HWND_OBJECT, TRUE);
  3661.  
  3662.  4.4.8  Finding a Parent, Child, or Owner Window
  3663.  
  3664.    You can determine the parent, child, and owner windows for any window by
  3665.    using the WinQueryWindow function. The function returns the window handle
  3666.    of the requested window. It can also lock that window. If a window is
  3667.    locked, it must be unlocked by using the WinLockWindow function.
  3668.  
  3669.    The following code fragment determines the parent window of the given
  3670.    window (it does not lock the parent window):
  3671.  
  3672.    HWND hwndParent;
  3673.  
  3674.    hwndParent = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  3675.  
  3676.    The following code fragment determines the topmost child window and locks
  3677.    it:
  3678.  
  3679.    HWND hwndChild;
  3680.  
  3681.    if (hwndChild = WinQueryWindow(hwnd, QW_TOP, TRUE)) {
  3682.  
  3683.        /* Lock the child window. */
  3684.  
  3685.        WinLockWindow(hwndChild, FALSE);
  3686.    }
  3687.  
  3688.    If a given window does not have an owner or child window, the function
  3689.    returns NULL.
  3690.  
  3691.  4.4.9  Setting an Owner Window
  3692.  
  3693.    You can set the owner for a window by using the WinSetOwner function.
  3694.    After setting the owner, a window typically notifies the owner window of
  3695.    the new relationship by sending a message.
  3696.  
  3697.    The following code fragment shows how to set the owner window and send it
  3698.    a message:
  3699.  
  3700.    #define NEW_OWNER   1
  3701.    HWND hwnd;                           /* window to get new owner    */
  3702.    HWND hwndOwner;                      /* window to become new owner */
  3703.  
  3704.    if (WinSetOwner(hwnd, hwndOwner)) {
  3705.  
  3706.        /* Send a notification message. */
  3707.  
  3708.        WinSendMsg(hwndOwner,       /* send to owner                    */
  3709.            WM_CONTROL,             /* control message for notification */
  3710.            MAKELONG(NEW_OWNER, 1), /* notification code and ID         */
  3711.            NULL);                  /* no extra data                    */
  3712.    }
  3713.  
  3714.    A window can have only one owner, so WinSetOwner removes any previous
  3715.    owner.
  3716.  
  3717.  4.4.10  Finding a Child or Owned Window
  3718.  
  3719.    A parent or owner window can retrieve the handle of a child or owned
  3720.    window by using the WinWindowFromID function and supplying the identifier
  3721.    of the child or owned window. WinWindowFromID searches all child and owned
  3722.    windows to locate the window having the given identifier. The window
  3723.    identifier is set when the application creates the child or owned window.
  3724.  
  3725.    An owner window typically uses the WinWindowFromID function to respond to
  3726.    a notification message from an owned window.
  3727.  
  3728.    The following code fragment retrieves the window handle of the owned
  3729.    window having the window identifier 1:
  3730.  
  3731.    hwndOwned = WinWindowFromID(hwndOwner, 1);
  3732.    WinSendMsg(hwndOwned, WM_ENABLE, MPFROM2SHORT(0, TRUE), NULL);
  3733.  
  3734.    You can also retrieve the handle of a child window by using the
  3735.    WinWindowFromPoint function and supplying a point in the corresponding
  3736.    parent window.
  3737.  
  3738.  4.4.11  Enumerating Top-Level Windows
  3739.  
  3740.    You can enumerate all top-level windows by using the WinBeginEnumWindows
  3741.    and WinGetNextWindow functions. An application can create a list of all
  3742.    child windows for a given parent window by using the WinBeginEnumWindows
  3743.    function. This list contains the window handles of immediate child
  3744.    windows. An application can retrieve, one at a time, the window handles
  3745.    from the list using the WinGetNextWindow function. When the application
  3746.    has finished using the list, it must release it by using the
  3747.    WinEndEnumWindows function.
  3748.  
  3749.    The following code fragment shows how to enumerate all top-level windows
  3750.    (all immediate child windows of the desktop window):
  3751.  
  3752.    /* Enumerate all top-level windows. */
  3753.  
  3754.    henum = WinBeginEnumWindows(HWND_DESKTOP);
  3755.  
  3756.    /*
  3757.     * Loop through all enumerated windows, performing the desired task
  3758.     * on each one.
  3759.     */
  3760.  
  3761.    while (hwnd = WinGetNextWindow(henum)) {
  3762.        .
  3763.        . /* Lock the window. */
  3764.        .
  3765.        WinLockWindow(hwnd, FALSE); /* unlock window when done    */
  3766.    }
  3767.  
  3768.    /* Return memory required for enumeration back to the system. */
  3769.  
  3770.    WinEndEnumWindows(henum);
  3771.  
  3772.  4.4.12  Moving and Sizing a Window
  3773.  
  3774.    You can move a window by using the WinSetWindowPos function and specifying
  3775.    the SWP_MOVE constant. The function changes the position of the window to
  3776.    the specified position. The position is always given as coordinates
  3777.    relative to the parent window.
  3778.  
  3779.    The following code fragment moves the window to the position (10,10):
  3780.  
  3781.    WinSetWindowPos(
  3782.        hwnd,       /* window handle                  */
  3783.        NULL,       /* not used for moving and sizing */
  3784.        10, 10      /* new position                   */
  3785.        0, 0,       /* not used for moving            */
  3786.        SWP_MOVE);  /* move and size                  */
  3787.  
  3788.    You can set the size of a window by using the WinSetWindowPos function and
  3789.    specifying the SWP_SIZE constant. The function changes the width and
  3790.    height of the window to the specified width and height.
  3791.  
  3792.    You can combine moving and sizing in a single function call, as shown in
  3793.    the following code fragment:
  3794.  
  3795.    WinSetWindowPos(
  3796.        hwnd,                 /* window handle                  */
  3797.        NULL,                 /* not used for moving and sizing */
  3798.        10, 10                /* new position                   */
  3799.        200, 200,             /* width and height               */
  3800.        SWP_MOVE | SWP_SIZE); /* move and size                  */
  3801.  
  3802.    You can retrieve the current size and position of a window by using the
  3803.    WinQueryWindowPos function. This function copies the current information
  3804.    to an SWP structure.
  3805.  
  3806.    The following code fragment uses the current size and position to change
  3807.    the height of the window, but leaves the width and position unchanged:
  3808.  
  3809.    SWP swpCurrent;
  3810.  
  3811.    WinQueryWindowPos(hwnd, &swpCurrent);
  3812.    WinSetWindowPos(
  3813.        hwnd,                 /* window handle                  */
  3814.        NULL,                 /* not used for moving and sizing */
  3815.        0, 0,                 /* not used for sizing            */
  3816.        swpCurrent.cx,        /* current width                  */
  3817.        swpCurrent.cy + 200,  /* new height                     */
  3818.        SWP_SIZE);            /* change the size                */
  3819.  
  3820.    You can also move and change the size of several windows at once by using
  3821.    the WinSetMultWindowPos function. This function takes an array of SWP
  3822.    structures. Each structure specifies the window to be moved or changed.
  3823.  
  3824.  4.4.13  Moving a Window in a Stack of Windows
  3825.  
  3826.    You can move a window to the top or bottom of the Z order by passing the
  3827.    SWP_ZORDER constant to the WinSetWindowPos function. You specify where to
  3828.    move the window by specifying HWND_TOP or HWND_BOTTOM.
  3829.  
  3830.    The following code fragment uses WinSetWindowPos to reorder a stack of
  3831.    child windows:
  3832.  
  3833.    HENUM henum;
  3834.    HWND hwndParent;
  3835.    HWND hwndNext;
  3836.  
  3837.    henum = WinBeginEnumWindows(hwndParent);
  3838.  
  3839.    while (hwndNext = WinGetNextWindow(henum)) {
  3840.        WinSetWindowPos(
  3841.            hwndNext,      /* next window to move  */
  3842.            HWND_TOP,      /* put window on top    */
  3843.            0, 0, 0, 0,    /* not used for Z order */
  3844.            SWP_ZORDER);   /* change Z order       */
  3845.  
  3846.        WinLockWindow(hwndNext, FALSE);    /* unlock window */
  3847.        .
  3848.        . /* Wait a little before doing the next window. */
  3849.        .
  3850.    }
  3851.  
  3852.    WinEndEnumWindows(henum);
  3853.  
  3854.    You can also specify the window you want the given window to move behind.
  3855.    In this case, you specify the window handle instead of the HWND_TOP or
  3856.    HWND_BOTTOM constant.
  3857.  
  3858.    If you enumerate windows as shown in the previous code fragment, the
  3859.    following code fragment will reverse the order of every other pair of
  3860.    windows:
  3861.  
  3862.    hwndExchange = WinGetNextWindow(henum);
  3863.  
  3864.    /* hwndNext has top window, hwndExchange has window under the top */
  3865.  
  3866.    WinSetWindowPos(
  3867.        hwndNext,      /* next window to move     */
  3868.        hwndExchange,  /* put lower window on top */
  3869.        0, 0, 0, 0,    /* not used for Z order    */
  3870.        SWP_ZORDER);   /* change Z order          */
  3871.  
  3872.  4.4.14  Showing and Hiding a Window
  3873.  
  3874.    Moving and sizing a window still applies if a window is not visible. The
  3875.    effects of moving and sizing cannot be seen until the window is visible.
  3876.    You can show and hide a window by using the WinShowWindow function. This
  3877.    function changes the WS_VISIBLE style for a window to the specified
  3878.    setting. You can also use the WinIsWindowVisible function to check the
  3879.    visibility of a window. The function returns TRUE if the window is
  3880.    visible.
  3881.  
  3882.  4.4.15  Maximizing, Minimizing, and Restoring a Window
  3883.  
  3884.    You can maximize, minimize, or restore a frame window by using the
  3885.    WinSetWindowPos function and specifying the constant SWP_MAXIMIZE,
  3886.    SWP_MINIMIZE, or SWP_RESTORE. Only a frame window can maximize and
  3887.    minimize by default. For any other window, you must provide support for
  3888.    these actions in the corresponding window procedure.
  3889.  
  3890.    The following code fragment shows how to maximize a frame window:
  3891.  
  3892.    SWP swpCurrent;
  3893.  
  3894.    WinQueryWindowPos(hwnd, &swpCurrent);
  3895.    WinSetWindowPos(
  3896.        hwnd,                /* window handle               */
  3897.        NULL,                /* not used to maximize        */
  3898.        swpCurrent.x,
  3899.        swpCurrent.y,        /* stored for restoring window */
  3900.        swpCurrent.cx,
  3901.        swpCurrent.cy,       /* stored for restoring window */
  3902.        SWP_MAXIMIZE | SWP_SIZE | SWP_MOVE);    /* maximize */
  3903.  
  3904.  
  3905.  4.5  Summary
  3906.  
  3907.    The following sections list all the functions and messages an application
  3908.    can use to create, maintain, and destroy windows; to manage window
  3909.    relationships; and to set, query, and initialize the size, position, and
  3910.    visibility of windows.
  3911.  
  3912.  4.5.1  Window Functions
  3913.  
  3914.    The following functions are used by an application to create, maintain,
  3915.    and destroy windows:
  3916.  
  3917.    WinCreateWindow  Creates a window. This is the most flexible, general
  3918.    purpose window-creation function. It can be used to create windows of any
  3919.    class. The function's parameters let you specify the window class, the
  3920.    parent window, the owner window, the window size and position, the Z-order
  3921.    position, the window identifier, general and class-specific window styles,
  3922.    and additional class-specific data. Other window-creation functions make
  3923.    one or more calls to this function to create their window(s).
  3924.  
  3925.    WinDestroyWindow  Destroys a window. Related child windows and owned
  3926.    windows will also be destroyed.
  3927.  
  3928.    WinEnableWindow  Enables or disables a window. A disabled window loses the
  3929.    focus and ignores input. This function clears or sets the WS_DISABLED
  3930.    style.
  3931.  
  3932.    WinIsWindow  Determines if a window handle is valid.
  3933.  
  3934.    WinIsWindowEnabled  Determines whether a window is enabled or disabled.
  3935.    The function tests the WS_DISABLED style.
  3936.  
  3937.    WinLockWindow  Increments or decrements a window lock count. The lock
  3938.    count is initialized to zero and must be zero for the window to be
  3939.    destroyed.
  3940.  
  3941.    WinQuerySysModalWindow  Determines the system-modal window. This function
  3942.    returns the system-modal window handle if successful or NULL if there is
  3943.    no system-modal window.
  3944.  
  3945.    WinQueryWindowLockCount  Retrieves the window lock count.
  3946.  
  3947.    WinQueryWindowPtr  Examines a pointer in a window data structure.
  3948.  
  3949.    WinQueryWindowULong  Examines a 32-bit field in a window data structure.
  3950.  
  3951.    WinQueryWindowUShort  Examines a 16-bit field in a window data structure.
  3952.  
  3953.    WinRegisterWindowDestroy  Notifies other applications when the specified
  3954.    window is destroyed.
  3955.  
  3956.    WinSetSysModalWindow  Sets a window as the system-modal window or ends the
  3957.    system-modal state. This function should be called only while processing
  3958.    keyboard or mouse input.
  3959.  
  3960.    WinSetWindowBits  Sets bits in a 32-bit field in a window data structure.
  3961.  
  3962.    WinSetWindowPtr  Sets a pointer in a window data structure.
  3963.  
  3964.    WinSetWindowULong  Sets a 32-bit field in a window data structure.
  3965.  
  3966.    WinSetWindowUShort  Sets a 16-bit field a window data structure.
  3967.  
  3968.    WinSubclassWindow  Changes a window procedure. If successful, the function
  3969.    returns a pointer to the previous window procedure.
  3970.  
  3971.  4.5.2  Standard Window Messages
  3972.  
  3973.    The following are standard window messages:
  3974.  
  3975.    WM_CREATE  Sent to a window during processing of the WinCreateWindow
  3976.    function, before the window is sized, positioned, or shown.
  3977.  
  3978.    WM_DESTROY  Sent to the window being destroyed. This message is sent after
  3979.    the window has been hidden on the device but before its child windows have
  3980.    been destroyed.
  3981.  
  3982.    WM_ENABLE  This message is sent when a window is being enabled.
  3983.  
  3984.    WM_OTHERWINDOWDESTROYED  Sent to all top-level windows when a window is
  3985.    destroyed.
  3986.  
  3987.    WM_QUERYWINDOWPARAMS  Sent to obtain certain window data. The data is
  3988.    specified and returned by using a WNDPARAMS data structure.
  3989.  
  3990.    WM_SETWINDOWPARAMS  Sent to set window data.
  3991.  
  3992.  4.5.3  Relationship Functions
  3993.  
  3994.    The following functions can be used to manage window relationships:
  3995.  
  3996.    WinBeginEnumWindows  Begins the window-enumeration process. This function
  3997.    creates an enumeration list of the immediate child windows of a window and
  3998.    returns the list handle.
  3999.  
  4000.    WinEndEnumWindows  Ends a window enumeration process. This function
  4001.    destroys the enumeration list (just the list, not the windows) created by
  4002.    the WinBeginEnumWindows function.
  4003.  
  4004.    WinGetNextWindow  Obtains a window handle from a window list created by a
  4005.    call to the WinBeginEnumWindows function. Each call returns the next
  4006.    window in the list or NULL at the end of the list. The function locks the
  4007.    window that has the returned handle. The application must unlock the
  4008.    window after processing. Calling this function after it has returned NULL
  4009.    causes it to wrap around to the beginning of the list.
  4010.  
  4011.    WinIsChild  Determines if one window is the child of another window.
  4012.  
  4013.    WinQueryDesktopWindow  Obtains a handle of the desktop window
  4014.    HWND_DESKTOP.
  4015.  
  4016.    WinQueryObjectWindow  Obtains a handle of the desktop-object window
  4017.    HWND_OBJECT.
  4018.  
  4019.    WinQueryWindow  Retrieves a window's parent, owner, or child windows. This
  4020.    function returns the handle of the specified window or NULL if no such
  4021.    window exists.
  4022.  
  4023.    WinSetOwner  Sets a window's owner window. Note that you can set the
  4024.    handle of the owner window to NULL, meaning it has no owner.
  4025.  
  4026.    WinSetParent  Sets a window's parent window. This allows you to change
  4027.    object windows to regular windows, descendant windows of top-level windows
  4028.    to top-level windows, and vice versa.
  4029.  
  4030.  4.5.4  Functions for Moving, Sizing, and Changing
  4031.  
  4032.    The following functions can be used to move and change the position of a
  4033.    window:
  4034.  
  4035.    WinGetMaxPosition  Obtains a window's maximized size and position. A
  4036.    window's maximized size is the size of its parent window plus an
  4037.    adjustment outward in all four directions equal to the size of its border.
  4038.    The adjustment is made because maximized windows do not show their border.
  4039.  
  4040.    WinGetMinPosition  Obtains an icon location for a minimized window. The
  4041.    function searches for an icon area, starting at the given point and
  4042.    continuing with subsequent positions until the next available icon
  4043.    position is found.
  4044.  
  4045.    WinIsWindowVisible  Determines whether a window is visible.
  4046.  
  4047.    WinQueryWindowPos  Determines a window's current size and position.
  4048.  
  4049.    WinQueryWindowRect  Determines a window's bounding rectangle, relative to
  4050.    its parent window. You can determine the window's size and position from
  4051.    the bounding rectangle.
  4052.  
  4053.    WinSetWindowPos  Sets a window's size, position, and Z order. Position is
  4054.    specified in window coordinates relative to the parent window's lower-left
  4055.    corner. Size is specified in device units. Z order is relative to a
  4056.    window's sibling windows.
  4057.  
  4058.    WinSetMultWindowPos  Sets the size, position, and Z order for an array of
  4059.    windows. This function and the WinSetWindowPos function are the same
  4060.    except for the number of windows each can affect.
  4061.  
  4062.    WinShowWindow  Makes a window visible or invisible.
  4063.  
  4064.  4.5.5  Messages for Moving, Sizing, and Changing
  4065.  
  4066.    The following messages are received by a window procedure when the
  4067.    corresponding window is moved or changes size or visibility:
  4068.  
  4069.    WM_ADJUSTWINDOWPOS  Sent to a window about to be moved or sized. This
  4070.    message allows the window to adjust the new size and position before they
  4071.    take effect. This message is sent, by default, during calls to the
  4072.    WinCreateWindow, WinSetWindowPos, and WinSetMultWindowPos functions.
  4073.  
  4074.    WM_CALCVALIDRECTS  Sent from the WinSetWindowPos and WinSetMultWindowPos
  4075.    functions when a window is about to be resized. Both these functions
  4076.    determine if there is a rectangular area of the window that can be
  4077.    preserved across the size change. If such a valid rectangle exists, its
  4078.    bitmap data can be simply and quickly copied to the new window image.
  4079.    Handlers of this message can specify the coordinates of the valid
  4080.    rectangle to be preserved, as well as determine where the valid rectangle
  4081.    will be placed within the resized window.
  4082.  
  4083.    WM_MOVE  Sent by the system when a window with CS_MOVENOTIFY style changes
  4084.    its absolute (relative to the screen) position. The window's new position
  4085.    can be obtained by calling the WinQueryWindowPos function.
  4086.  
  4087.    WM_SHOW  Sent by the system after a window's WS_VISIBLE style bit has
  4088.    changed. An mp1 value of TRUE indicates an invisible window has become
  4089.    visible. An mp1 value of FALSE indicates a visible window has become
  4090.    invisible. The default window procedure takes no action on this message.
  4091.  
  4092.    WM_SIZE  Sent after a window has changed size, but before any repainting
  4093.    has been performed. Resizing or repositioning of child windows resulting
  4094.    from the size change usually occurs during the processing of this message.
  4095.    This message is not sent when a window is created.
  4096.  
  4097.  
  4098.  
  4099.  ────────────────────────────────────────────────────────────────────────────
  4100.  Chapter 5  Messages and Message Queues
  4101.  
  4102.         5.1     Introduction
  4103.         5.2     About Messages and Message Queues
  4104.             5.2.1     Messages
  4105.             5.2.2     Message Queues
  4106.             5.2.3     Message Loop
  4107.             5.2.4     Messages and Window Procedures
  4108.             5.2.5     Application Messages
  4109.             5.2.6     System-Defined Messages
  4110.             5.2.7     Application-Defined Messages
  4111.             5.2.8     Semaphore Messages
  4112.             5.2.9     Message Priorities
  4113.             5.2.10    Message Filtering
  4114.         5.3     Using Messages in an Application
  4115.             5.3.1     Creating a Message Queue and Message Loop
  4116.             5.3.2     Examining the Message Queue
  4117.             5.3.3     Posting a Message to a Window
  4118.             5.3.4     Sending a Message to a Window
  4119.             5.3.5     Broadcasting a Message
  4120.             5.3.6     Using Message Macros
  4121.         5.4     Summary
  4122.  
  4123.  5.1  Introduction
  4124.  
  4125.    This chapter describes creating and using messages and message queues in
  4126.    MS OS/2 Presentation Manager applications. You should also be familiar
  4127.    with the following topics:
  4128.  
  4129.    ■  Windows
  4130.  
  4131.    ■  Window procedures
  4132.  
  4133.    ■  Threads, processes, and sessions
  4134.  
  4135.  
  4136.  5.2  About Messages and Message Queues
  4137.  
  4138.    Unlike traditional applications that take complete control of the
  4139.    computer's keyboard, mouse, and screen, Presentation Manager applications
  4140.    must share these resources with other applications running at the same
  4141.    time. Because all applications run independently, Presentation Manager
  4142.    applications rely on MS OS/2 to help them manage shared resources. The
  4143.    system manages shared resources by controlling the operation of each
  4144.    application, communicating with each application when there is keyboard
  4145.    and mouse input or when an application must move and size its windows. The
  4146.    system uses messages to communicate with an application and the windows
  4147.    belonging to that application.
  4148.  
  4149.    A message is information, a request for information, or a request for an
  4150.    action to be carried out by the application. The system communicates a
  4151.    message to an application so that the application can use the information
  4152.    or respond to the request. The system communicates in two ways: posting
  4153.    and sending.
  4154.  
  4155.    The system posts a message to an application's message queue if the
  4156.    message represents information or a request that does not need immediate
  4157.    action. The message queue is an application-created storage area used to
  4158.    hold messages. The application can then retrieve and process a message at
  4159.    the appropriate time. The system posts a message by copying the message
  4160.    data to the message queue.
  4161.  
  4162.    The system sends a message to an application when it needs an immediate
  4163.    response from the application. It sends a message by passing the message
  4164.    data as arguments to the window procedure. The window procedure carries
  4165.    out the request or lets the system carry out default processing for the
  4166.    message.
  4167.  
  4168.    The following sections describe messages and message queues in detail.
  4169.  
  4170.  5.2.1  Messages
  4171.  
  4172.    All messages contain information that an application uses to carry out
  4173.    tasks. There are two types of messages: queue messages and window
  4174.    messages. Queue messages are messages stored in a message queue. Window
  4175.    messages are messages sent to a window procedure. Although these message
  4176.    types have very different formats, the information they contain is nearly
  4177.    identical.
  4178.  
  4179.    Every message contains a message identifier. The message identifier is an
  4180.    integer value that determines whether the message is information or a
  4181.    request. When an application processes a message, it uses the message
  4182.    identifier to determine what to do.
  4183.  
  4184.    Every message contains a window handle. The window handle identifies the
  4185.    window for which the message is intended. The window handle is important
  4186.    because most message queues and window procedures serve more than one
  4187.    window. The window handle ensures that the application processes the
  4188.    message for the appropriate window.
  4189.  
  4190.    Messages contain two message parameters. A message parameter is a 32-bit
  4191.    value that specifies data or the location of data to be used in processing
  4192.    the message. The meaning and value of a message parameter depends on the
  4193.    message. Message parameters can be pointers to structures containing
  4194.    additional data, integer values, packed bit flags, and so on. Some
  4195.    messages do not use message parameters and typically set the parameters to
  4196.    zero. An application always checks the message identifier to determine how
  4197.    to interpret the message parameters.
  4198.  
  4199.    Queue messages also contain the message time and mouse position. The
  4200.    message time specifies the system time, in milliseconds, when the message
  4201.    was created. The mouse position specifies the location of the mouse
  4202.    pointer, in screen coordinates, when the message was created.
  4203.  
  4204.    A queue message is a QMSG data structure that contains six fields
  4205.    representing the window handle, message identifier, two message
  4206.    parameters, message time, and mouse position. The time and position are
  4207.    provided because most queue messages are input messages, representing
  4208.    keyboard or mouse input from the user. The time and position help the
  4209.    application identify the context of the message. The system posts a queue
  4210.    message by filling the QMSG structure and copying it to a message queue.
  4211.  
  4212.    A window message consists of the window handle, the message identifier,
  4213.    and two message parameters. A window message does not include the message
  4214.    time and mouse position because most window messages are requests to carry
  4215.    out a task that is not related to the current time or mouse-pointer
  4216.    position. The system sends a window procedure by passing these values as
  4217.    individual arguments to a window procedure.
  4218.  
  4219.  5.2.2  Message Queues
  4220.  
  4221.    Every Presentation Manager application needs a message queue. A message
  4222.    queue is the only means an application has to receive input from the
  4223.    keyboard or mouse. Only applications that create message queues can create
  4224.    windows.
  4225.  
  4226.    A message queue is internal storage reserved by the application for
  4227.    receiving and holding posted messages. An application creates a message
  4228.    queue by using the WinCreateMsgQueue function. This function returns a
  4229.    handle the application can use to access the message queue. After an
  4230.    application creates a message queue, the system posts messages intended
  4231.    for windows in the application to that queue. The application can retrieve
  4232.    queue messages by specifying the message-queue handle in a call to the
  4233.    WinGetMsg function. It can examine messages without retrieving them by
  4234.    using the WinPeekMsg function. When an application no longer needs the
  4235.    message queue, it can destroy it by using the WinDestroyMsgQueue function.
  4236.  
  4237.    Message queues serve all windows created by the application. This means a
  4238.    queue may hold messages for several windows. Most messages specify the
  4239.    windows to which they belong, so the application can easily apply a
  4240.    message to the appropriate window. Messages that do not specify a window
  4241.    apply to the entire application.
  4242.  
  4243.    An application that has more than one thread can create more than one
  4244.    message queue. The system allows one message queue for each thread. A
  4245.    message queue created by an application thread belongs to that thread and
  4246.    has no connection to other queues in that application. When an application
  4247.    creates a window in a given thread, the system associates the window with
  4248.    the message queue in that thread. The system then posts all subsequent
  4249.    messages intended for the window to that queue.
  4250.  
  4251.    Although multiple messages queues are possible, most Presentation Manager
  4252.    applications use threads sparingly and so use only one message queue.
  4253.  
  4254.    Since several windows typically use a message queue, it is important that
  4255.    the message queue be large enough to hold all possible messages that may
  4256.    be posted to it. An application can set the size of the message queue when
  4257.    it creates the queue by specifying the maximum number of messages the
  4258.    queue can hold.
  4259.  
  4260.    To minimize the queue size, several types of posted messages are not
  4261.    actually stored in a message queue. Instead, the system keeps a record in
  4262.    the queue of the message being posted and combines any information
  4263.    contained in the message with information from previous messages. Timer,
  4264.    semaphore, and paint messages are handled in this way. For example, if
  4265.    more than one WM_PAINT message is posted, the system combines the update
  4266.    regions for each into a single update region. Although there is no actual
  4267.    message in the queue, the system constructs one WM_PAINT message with the
  4268.    single update region when an application uses the WinGetMsg function.
  4269.  
  4270.    Mouse and keyboard input messages are also not stored in the message
  4271.    queue. These are stored in the system message queue. The system message
  4272.    queue is a system-owned queue that receives and holds messages for all
  4273.    mouse and keyboard input. The system does not copy these messages to
  4274.    application message queues. Instead, the WinGetMsg function searches the
  4275.    system queue for input messages belonging to the application when there
  4276.    are no other higher-priority messages in the application's message queue.
  4277.    The system message queue is usually large enough to hold all input
  4278.    messages, even if the user is typing or moving the mouse very quickly. If
  4279.    the system queue does run out of room, the system ignores the most recent
  4280.    keyboard input (usually beeping to indicate it is ignored) and collects
  4281.    mouse motions into a single motion.
  4282.  
  4283.    Every message queue has a corresponding data structure. The data structure
  4284.    specifies the identifiers of the process and thread that own the message
  4285.    queue and gives a count of the maximum number of messages the queue can
  4286.    receive. An application can retrieve the data structure by using the
  4287.    WinQueryQueueInfo function.
  4288.  
  4289.    A message queue also has a current status. The status specifies whether
  4290.    any messages are available in the queue. An application can retrieve the
  4291.    queue status by using the WinQueryQueueStatus function. Since this
  4292.    function is very fast, applications typically use it to check for messages
  4293.    rather than using the WinPeekMsg function, which inspects the thread's
  4294.    message queue.
  4295.  
  4296.  5.2.3  Message Loop
  4297.  
  4298.    Every application with a message queue is responsible for retrieving the
  4299.    messages from that queue. An application can do this by using a message
  4300.    loop. A message loop is a program loop, usually in the application's main
  4301.    function, that retrieves messages from the message queue and dispatches
  4302.    them to the appropriate windows. The message loop consists of two function
  4303.    calls: one to the WinGetMsg function, the other to the WinDispatchMsg
  4304.    function. The message loop has the following form:
  4305.  
  4306.    while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
  4307.        WinDispatchMsg(hab, &qmsg);
  4308.  
  4309.    An application starts the message loop after creating the message queue
  4310.    and at least one application window. Once started, the message loop
  4311.    continues to retrieve messages from the message queue and to dispatch
  4312.    (send) them to the appropriate windows. The WinDispatchMsg function sends
  4313.    each message to the window specified by the window handle in the message.
  4314.  
  4315.    Only one message loop is needed for a message queue, even if the queue
  4316.    contains messages for more than one window. Each queue message is a QMSG
  4317.    structure that contains the handle of the window to which the message
  4318.    belongs, so the WinDispatchMsg function always dispatches the message to
  4319.    the proper window. The WinGetMsg function retrieves messages from the
  4320.    queue in first-in, first-out (FIFO) order, so the messages are dispatched
  4321.    to windows in the same order they were put in the queue.
  4322.  
  4323.    If there are no messages in the queue, the system temporarily stops
  4324.    processing the WinGetMsg function until a message arrives. This means that
  4325.    CPU time slices that would otherwise be spent waiting for a message can be
  4326.    given to the applications (or threads) that do have messages in their
  4327.    queues.
  4328.  
  4329.    The message loop continues to retrieve and send messages until the
  4330.    WinGetMsg function retrieves a WM_QUIT message. This message causes the
  4331.    function to return FALSE, terminating the loop. In most cases, terminating
  4332.    the message loop is the first step in terminating the application. An
  4333.    application can terminate its own loop by posting the WM_QUIT message in
  4334.    its own queue.
  4335.  
  4336.    An application can modify its message loop in a variety of ways. For
  4337.    example, it can retrieve messages from the queue without dispatching them
  4338.    to a window. This is useful for applications that post messages that do
  4339.    not specify a window (these messages apply to the application rather than
  4340.    to a specific window; they have NULL window handles). An application can
  4341.    also direct the WinGetMsg function to search for specific messages,
  4342.    leaving other messages in the queue. This is useful for applications that
  4343.    temporarily need to bypass the usual first-in, first-out order of the
  4344.    message queue.
  4345.  
  4346.  5.2.4  Messages and Window Procedures
  4347.  
  4348.    When the system needs an immediate response from an application, it sends
  4349.    a message to a window procedure. A window procedure is a function that
  4350.    receives and processes all input and requests for action sent to the
  4351.    window by the system. Every window class has a window procedure and every
  4352.    window created using that class uses the window procedure to respond to
  4353.    messages.
  4354.  
  4355.    The system sends a message to the window procedure by passing the message
  4356.    data as arguments to the window procedure. The window procedure carries
  4357.    out an appropriate action for the given request. Most window procedures
  4358.    check the message identifier, then use the information specified by the
  4359.    message parameters to carry out the request. When it has completed
  4360.    processing the message, the window procedure returns a message result.
  4361.    Each message has a particular set of possible return values. The window
  4362.    procedure must return the appropriate value for the processing it carried
  4363.    out.
  4364.  
  4365.    A window procedure cannot ignore a message. If it does not process a
  4366.    message, it must pass the message back to the system for default
  4367.    processing. The window procedure can do this by calling the
  4368.    WinDefWindowProc function. This function carries out a default action and
  4369.    returns the message result. The window procedure must return this value as
  4370.    its own message result.
  4371.  
  4372.    A window procedure commonly processes messages for several windows. It
  4373.    uses the window handle specified in the message to identify the
  4374.    appropriate window. Most window procedures process a few types of messages
  4375.    and pass the others on to the system by calling the WinDefWindowProc
  4376.    function.
  4377.  
  4378.  5.2.5  Application Messages
  4379.  
  4380.    Any application can post and send messages. Like the system, an
  4381.    application posts a message by copying it to a message queue. It sends a
  4382.    message by passing the message data as arguments to a window procedure. An
  4383.    application can post a message by using the WinPostMsg function. It can
  4384.    send a message by using the WinSendMsg function.
  4385.  
  4386.    Typically, an application posts a message to notify a specific window to
  4387.    carry out a task. The WinPostMsg function creates a QMSG structure for
  4388.    each message and copies the message to the message queue corresponding to
  4389.    the given window. The application's message loop eventually retrieves the
  4390.    message and dispatches it to the appropriate window procedure. One message
  4391.    commonly posted is WM_QUIT. This message terminates the application by
  4392.    terminating the message loop.
  4393.  
  4394.    Typically, an application sends a message to notify a specific window
  4395.    procedure to immediately carry out a task. The WinSendMsg function passes
  4396.    the message to the window procedure corresponding to the given window. The
  4397.    function waits until the window procedure completes processing and then
  4398.    returns the message result. It is very common for parent and child windows
  4399.    to communicate by sending messages to each other. For example, a parent
  4400.    window that has an entry-field control (as its child window) can set the
  4401.    text of the control by sending the child window a message. The control can
  4402.    notify the parent window of changes to the text (carried out by the user)
  4403.    by sending messages back to the parent window.
  4404.  
  4405.    Occasionally, an application may need to send or post a message to all
  4406.    windows in the system. For example, if the application changes a system
  4407.    value, it must notify all windows about the change by sending a
  4408.    WM_SYSVALUECHANGED message. An application can send or post messages to
  4409.    any number of windows by using the WinBroadcastMsg function. The options
  4410.    in WinBroadcastMsg determine whether the message is sent or posted and
  4411.    specify the number of windows to receive the message.
  4412.  
  4413.    If an application has more than one thread, any thread in the application
  4414.    can post messages to a message queue, even if that thread has no message
  4415.    queue of its own. However, only threads that have a message queue can send
  4416.    messages. Posting or sending messages between threads is relatively
  4417.    uncommon. One reason for this is that it is costly in terms of system
  4418.    performance to send a message. If you do post messages between threads, it
  4419.    is likely to be for semaphore messages. Semaphore messages permit window
  4420.    procedures to jointly manage a shared resource.
  4421.  
  4422.    An application can post a message without specifying a window. If the
  4423.    application supplies a NULL window handle when it calls the WinPostMsg
  4424.    function, the function posts the message that is in the message queue of
  4425.    the thread calling the function. Because the message has no window handle,
  4426.    the message loop processes the message. This is one way to create messages
  4427.    that apply to the entire application instead of to a specific window.
  4428.  
  4429.    A window procedure can determine whether it is processing a message sent
  4430.    by another thread by using the WinInSendMsg function. This is useful when
  4431.    message processing depends on the origin of the message.
  4432.  
  4433.    A common programming error is to assume that the WinPostMsg function
  4434.    always posts a message. This is not true when the message queue is full.
  4435.    An application should check the return value of the function to see if the
  4436.    message has been posted. In general, if an application intends to post
  4437.    many messages to the queue, it should set the message queue to an
  4438.    appropriate size when it creates the queue. The default message-queue size
  4439.    is ten messages.
  4440.  
  4441.  5.2.6  System-Defined Messages
  4442.  
  4443.    There are many system-defined messages. The system uses these messages to
  4444.    control the operation of applications and to provide input and other
  4445.    information for applications to process. The system sends or posts a
  4446.    system-defined message when it communicates with an application. An
  4447.    application can also send or post system-defined messages. Applications
  4448.    typically use these messages to control the operation of control windows
  4449.    created using the preregistered window classes.
  4450.  
  4451.    Each system message has a unique message identifier and a corresponding
  4452.    symbolic constant. The symbolic constant, defined in MS OS/2 header files,
  4453.    typically states the purpose of the message. For example, the WM_PAINT
  4454.    constant represents the paint message. The paint message requests a window
  4455.    to paint its contents.
  4456.  
  4457.    The symbolic constants also specify the message category. System-defined
  4458.    messages can belong to several categories; the prefix identifies the type
  4459.    of window that can interpret and process the messages. The following list
  4460.    gives the prefixes and related message categories:
  4461.  
  4462.    Prefix          Message category
  4463.    ──────────────────────────────────────────────────────────────────────────
  4464.    BM              Button-control
  4465.  
  4466.    EM              Entry-field control
  4467.  
  4468.    LM              List-box control
  4469.  
  4470.    MM              Menu
  4471.  
  4472.    SBM             Scroll-bar control
  4473.  
  4474.    SM              Static control
  4475.  
  4476.    TBM             Title-bar control
  4477.  
  4478.    WM              General window
  4479.    ──────────────────────────────────────────────────────────────────────────
  4480.  
  4481.    General window messages cover a wide range of information and requests and
  4482.    include mouse and keyboard-input messages, menu and dialog-input messages,
  4483.    window-creation and window-management messages, and dynamic-data-exchange
  4484.    (DDE) messages.
  4485.  
  4486.  5.2.7  Application-Defined Messages
  4487.  
  4488.    An application can create its own messages to use in its own windows. If
  4489.    an application creates messages, the window procedure that receives the
  4490.    message must interpret the message and provide appropriate processing.
  4491.  
  4492.    MS OS/2 reserves the message-identifier values in the range 0x0000 through
  4493.    (WM_USER-1) for system-defined messages. Applications cannot use these
  4494.    values for private messages. Values in the range WM_USER through 0xBFFF
  4495.    are available for message identifiers defined by an application for use in
  4496.    that application. Values in the range 0xC000 through 0xFFFF are reserved
  4497.    for message identifiers defined by an application using the atom-manager
  4498.    registration for use in any application.
  4499.  
  4500.  5.2.8  Semaphore Messages
  4501.  
  4502.    The semaphore messages are a way of signaling the end of an event through
  4503.    the message queue. Applications use these messages like they use MS OS/2
  4504.    semaphore functions to coordinate events by passing signals. Semaphore
  4505.    messages are often used in conjunction with MS OS/2 semaphores.
  4506.  
  4507.    There are four semaphore messages: WM_SEM1, WM_SEM2, WM_SEM3, and WM_SEM4.
  4508.    An application posts one of the semaphore messages to signal the end of
  4509.    the given event. The window that is waiting for the given event receives
  4510.    the semaphore message when the message loop retrieves and dispatches the
  4511.    message.
  4512.  
  4513.    Each semaphore message includes a bit flag that can be used to uniquely
  4514.    identify 32 possible semaphores for each semaphore message. The
  4515.    application passes the bit flag (with the appropriate bit set) as a
  4516.    message parameter with the message. The window procedure that receives the
  4517.    message then uses the bit flag to identify the semaphore.
  4518.  
  4519.    To save space in a message queue, the system does not store semaphore
  4520.    messages in the message queue. Instead, it sets a record in the queue,
  4521.    indicating the semaphore message has been received, and then combines the
  4522.    bit flag for the message with the bit flags from previous messages. When
  4523.    the window procedure eventually receives the message, the bit flag
  4524.    specifies each semaphore message posted since the last message was
  4525.    retrieved.
  4526.  
  4527.  5.2.9  Message Priorities
  4528.  
  4529.    The WinGetMsg function retrieves messages from the message queue based on
  4530.    message priority. The function retrieves messages with higher priority
  4531.    first. If it finds more than one message at a particular priority level,
  4532.    it retrieves the oldest message first. Messages have the following
  4533.    priority:
  4534.  
  4535.    Priority    Message
  4536.    ──────────────────────────────────────────────────────────────────────────
  4537.    1           WM_SEM1
  4538.  
  4539.    2           Messages posted using WinPostMsg
  4540.  
  4541.    3           Input messages from the keyboard or mouse
  4542.  
  4543.    4           WM_SEM2
  4544.  
  4545.    5           WM_PAINT
  4546.  
  4547.    6           WM_SEM3
  4548.  
  4549.    7           WM_TIMER
  4550.  
  4551.    8           WM_SEM4
  4552.    ──────────────────────────────────────────────────────────────────────────
  4553.  
  4554.  5.2.10  Message Filtering
  4555.  
  4556.    Applications can choose specific messages to retrieve from the message
  4557.    queue (ignoring other messages) by specifying a message filter with the
  4558.    WinGetMsg or WinPeekMsg function. The message filter is a range of message
  4559.    identifiers (specified by a first and last identifier), a window handle,
  4560.    or both. The functions use the message filter to select the messages to
  4561.    retrieve from the queue. Message filtering is useful if an application
  4562.    needs to search ahead in the message queue for messages that have a lower
  4563.    priority or that arrived in the queue later than other less important
  4564.    messages.
  4565.  
  4566.    Any application that filters messages must ensure that a message
  4567.    satisfying the message filter can be posted. For example, filtering for a
  4568.    WM_CHAR message in a window that does not have the input focus prevents
  4569.    the WinGetMsg function from returning. Some messages, such as WM_COMMAND,
  4570.    are generated from other messages; filtering for them may also prevent
  4571.    WinGetMsg from returning.
  4572.  
  4573.    The WM_BUTTONCLICKFIRST and WM_BUTTONCLICKLAST, WM_MOUSEFIRST and
  4574.    WM_MOUSELAST, and WM_DDE_FIRST and WM_DDE_LAST constants can be used to
  4575.    filter button, mouse, and DDE messages.
  4576.  
  4577.  
  4578.  5.3  Using Messages in an Application
  4579.  
  4580.    This section explains how to use the message and message-queue functions
  4581.    to create and manage message queues and to post and send messages between
  4582.    windows.
  4583.  
  4584.  5.3.1  Creating a Message Queue and Message Loop
  4585.  
  4586.    Your application needs a message queue and message loop to process
  4587.    messages for windows. You create a message queue by using the
  4588.    WinCreateMsgQueue function. You create a message loop by using the
  4589.    WinGetMsg and WinDispatchMsg functions. You must create and show at least
  4590.    one window after creating the queue but before starting the message loop.
  4591.    The window is required because it is the only way the user can supply
  4592.    input to the message queue. The following code fragment shows how to
  4593.    create a message queue and a message loop:
  4594.  
  4595.    HAB hab;      /* anchor-block handle     */
  4596.    HMQ hmq;      /* message-queue handle    */
  4597.    QMSG qmsg;    /* queue-message structure */
  4598.  
  4599.    VOID cdecl main()
  4600.    {
  4601.        hab = WinInitialize(NULL);
  4602.        hmq = WinCreateMsgQueue(hab, DEFAULT_QUEUE_SIZE);
  4603.  
  4604.        /*
  4605.         * Use WinRegisterClass to register your window class.
  4606.         * Use WinCreateStdWindow to create your window.
  4607.         */
  4608.  
  4609.        while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
  4610.            WinDispatchMsg(hab, &qmsg);
  4611.  
  4612.        /* Use WinDestroyWindow to destroy your window. */
  4613.  
  4614.        WinDestroyMsgQueue(hmq);
  4615.        WinTerminate(hab);
  4616.    }
  4617.  
  4618.    Both the WinGetMsg and WinDispatchMsg functions take a pointer to a QMSG
  4619.    structure as a parameter. If a message is available, WinGetMsg copies it
  4620.    to the QMSG structure; WinDispatchMsg then uses the fields of the
  4621.    structure as arguments for the window procedure.
  4622.  
  4623.    Occasionally, you may need to process the message before dispatching it.
  4624.    This can occur, for example, if a window procedure posts a message to the
  4625.    queue for which a NULL window handle has been specified. Because the
  4626.    WinDispatchMsg function needs a window handle to dispatch the message, the
  4627.    message loop must process the message before dispatching it. The following
  4628.    code fragment shows how the message loop might process messages that have
  4629.    NULL window handles:
  4630.  
  4631.    while (WinGetMsg(hab, &qmsg, NULL, 0, 0)) {
  4632.        If (qmsg.hwnd == NULL) {
  4633.            .
  4634.            . /* Process the message. */
  4635.            .
  4636.        }
  4637.        else
  4638.            WinDispatchMsg(hab, &qmsg);
  4639.    }
  4640.  
  4641.  5.3.2  Examining the Message Queue
  4642.  
  4643.    You can examine the contents of the message queue by using the WinPeekMsg
  4644.    or WinQueryQueueStatus function. It is useful to examine the queue if you
  4645.    start a lengthy operation that additional user input can affect, or if you
  4646.    need to look ahead in the queue to anticipate a response to user input.
  4647.  
  4648.    You can use the WinPeekMsg function to check for specific messages in the
  4649.    message queue. The function is useful for extracting messages for a
  4650.    specific window from the queue. The function returns immediately if there
  4651.    is no message in the queue. This function can be used in a loop without
  4652.    requiring the loop to wait for a message to arrive. The following code
  4653.    segment checks the queue for WM_CHAR messages:
  4654.  
  4655.    if (WinPeekMsg(hab, &qmsg, NULL, WM_CHAR, WM_CHAR, PM_NOREMOVE))
  4656.  
  4657.    You can also use the WinQueryQueueStatus function to check for messages in
  4658.    the queue. This function is very fast and returns information about the
  4659.    kinds of messages available in the queue and which messages have been
  4660.    recently posted. Most applications use this function in program loops that
  4661.    need to be as fast as possible.
  4662.  
  4663.    If you have a very long operation to carry out, you should consider
  4664.    creating a separate thread for the operation. Despite the MS OS/2
  4665.    multitasking features, any application thread having a message queue that
  4666.    does not periodically relinquish control by calling the WinGetMsg or
  4667.    WinWaitMsg function risks monopolizing the CPU and seriously degrading
  4668.    system performance.
  4669.  
  4670.  5.3.3  Posting a Message to a Window
  4671.  
  4672.    You can use the WinPostMsg function to post a message to a window. The
  4673.    message goes to the window's message queue. For example, the following
  4674.    code fragment posts the WM_QUIT message:
  4675.  
  4676.    if (!WinPostMsg(hwnd, WM_QUIT, 0L, 0L))
  4677.  
  4678.        /* Message was not posted. */
  4679.  
  4680.    The function returns FALSE if the queue was full and the message could not
  4681.    be posted.
  4682.  
  4683.  5.3.4  Sending a Message to a Window
  4684.  
  4685.    You can use the WinSendMsg function to send a message directly to a
  4686.    window. Applications typically use this function to send messages to child
  4687.    windows. For example, the following code fragment directs a button control
  4688.    to draw a check mark by sending the BM_SETCHECK message to the control:
  4689.  
  4690.    WinSendMsg(hwndButton, BM_SETCHECK, MPFROMSHORT(1), 0L);
  4691.  
  4692.    WinSendMsg calls the window's window procedure and waits for that
  4693.    procedure to handle the message and return a result. A message can be sent
  4694.    to any window in the system; all that is required is a handle to the
  4695.    window. The message is not stored in the message queue. The thread making
  4696.    the call must have a message queue.
  4697.  
  4698.  5.3.5  Broadcasting a Message
  4699.  
  4700.    You can send messages to multiple windows by using the WinBroadcastMsg
  4701.    function. This function is useful after an application changes a system
  4702.    value, for broadcasting the WM_SYSVALUECHANGED message. The following code
  4703.    fragment shows how to broadcast this message to all frame windows in all
  4704.    applications:
  4705.  
  4706.    WinBroadcastMsg(
  4707.        hwnd,                                /* window handle         */
  4708.        WM_SYSVALUECHANGED,                  /* message ID            */
  4709.        0L,                                  /* no message parameters */
  4710.        0L,
  4711.        BMSG_FRAMEONLY | BMSG_POSTQUEUE);    /* all frame windows     */
  4712.  
  4713.    You can broadcast messages to all windows, to just frame windows, or to
  4714.    just the windows in your application.
  4715.  
  4716.  5.3.6  Using Message Macros
  4717.  
  4718.    The MS OS/2 include files define several macros that help create and
  4719.    interpret message parameters.
  4720.  
  4721.    One set of macros helps you construct message parameters. Macros are
  4722.    useful for sending and posting messages. For example, the following code
  4723.    fragment uses the MPFROMSHORT macro to convert a 16-bit integer into the
  4724.    32-bit message parameter:
  4725.  
  4726.    WinSendMsg(hwndButton, BM_SETCHECK, MPFROMSHORT(1), 0L);
  4727.  
  4728.    A second set of macros helps you extract values from a message parameter.
  4729.    They are useful for handling messages in a window procedure. The following
  4730.    code fragment illustrates this:
  4731.  
  4732.    case WM_FOCUSCHANGE:
  4733.        fsFocusChange = SHORT2FROMMP(mp2);
  4734.        if (SHORT1FROMMP(mp2))
  4735.             hwndLoseFocus = HWNDFROMMP(mp1);
  4736.  
  4737.    A third set of macros helps you construct a message result. They are
  4738.    useful for returning message results in a window procedure. This is
  4739.    illustrated by the following code fragment:
  4740.  
  4741.    return (MRFROM2SHORT(1, 2));
  4742.  
  4743.  
  4744.  5.4  Summary
  4745.  
  4746.    The following are the functions and the message you can use to create and
  4747.    use message queues and messages:
  4748.  
  4749.    WinBroadcastMsg  Sends or posts messages to one or more windows or posts
  4750.    messages to all message queues.
  4751.  
  4752.    WinCallMsgFilter  Calls a message-filter hook procedure, passing it a
  4753.    message and a message-filter control code.
  4754.  
  4755.    WinCreateMsgQueue  Creates a message queue for the current thread and
  4756.    returns a handle to the queue.
  4757.  
  4758.    WinDefDlgProc  Carries out default processing for messages sent to a
  4759.    dialog window.
  4760.  
  4761.    WinDefWindowProc  Carries out default processing for messages sent to a
  4762.    window.
  4763.  
  4764.    WinDestroyMsgQueue  Destroys a particular message queue. This function
  4765.    must be called before terminating a thread that has a message queue.
  4766.  
  4767.    WinDispatchMsg  Sends a message to a specified window.
  4768.  
  4769.    WinGetMsg  Retrieves the next message from a message queue, removing that
  4770.    message from the queue. This function does not return until a message is
  4771.    available.
  4772.  
  4773.    WinInSendMsg  Determines whether the current thread is processing a
  4774.    message sent from another thread. WinMsgMuxSemWait  Waits for one of a
  4775.    list of semaphores to clear. This function is similar to the DosMuxSemWait
  4776.    function, except that the thread can continue to process messages sent to
  4777.    it from other threads.
  4778.  
  4779.    WinMsgSemWait  Waits for a semaphore to clear. This function is similar to
  4780.    the DosSemWait function, except that a thread can continue to process
  4781.    messages sent to it from other threads.
  4782.  
  4783.    WinPeekMsg  Copies the next message from a message queue without removing
  4784.    it from the queue. This function returns immediately, whether or not a
  4785.    message is available.
  4786.  
  4787.    WinPostMsg  Posts a message to the message queue for a specified window.
  4788.    After placing the message in the queue, the function returns immediately.
  4789.  
  4790.    WinPostQueueMsg  Posts a message in a specified message queue in the
  4791.    system. The function returns immediately after placing the message in the
  4792.    queue.
  4793.  
  4794.    WinQueryMsgPos  Retrieves the mouse-pointer position (in screen
  4795.    coordinates) that was stored with a posted message.
  4796.  
  4797.    WinQueryMsgTime  Retrieves the system time (milliseconds since the system
  4798.    was booted) that the message was posted.
  4799.  
  4800.    WinQueryQueueInfo  Retrieves information about a message queue.
  4801.  
  4802.    WinQueryQueueStatus  Retrieves status information about a message queue.
  4803.  
  4804.    WinSendDlgItemMsg  Sends a message to a control window that belongs to the
  4805.    specified dialog window.
  4806.  
  4807.    WinSendMsg  Sends a message directly to the window procedure of a
  4808.    specified window. The function does not return until the message has been
  4809.    processed by the window procedure.
  4810.  
  4811.    WinTranslateAccel  Translates a WM_CHAR message to a WM_COMMAND message if
  4812.    there is an entry for the specific character in the accelerator table.
  4813.  
  4814.    WinWaitMsg  Waits until a particular type of message appears in a message
  4815.    queue.
  4816.  
  4817.    WM_QUIT  Marks the end of message processing for a message queue. This
  4818.    message causes the WinGetMsg function to return FALSE.
  4819.  
  4820.  
  4821.  
  4822.  ────────────────────────────────────────────────────────────────────────────
  4823.  Chapter 6  Window Classes
  4824.  
  4825.         6.1     Introduction
  4826.         6.2     About Window Classes
  4827.             6.2.1     Custom Window Classes
  4828.             6.2.2     Class Styles
  4829.             6.2.3     Window Procedures
  4830.             6.2.4     Public Window Classes
  4831.             6.2.5     Preregistered Window Classes
  4832.             6.2.6     Custom Public Classes
  4833.             6.2.7     Class Data
  4834.         6.3     Using Window Classes
  4835.             6.3.1     Registering a Private Window Class
  4836.             6.3.2     Registering an Imported Window Procedure
  4837.         6.4     Summary
  4838.  
  4839.  6.1  Introduction
  4840.  
  4841.    This chapter describes how applications create and use window classes. You
  4842.    should also be familiar with the following topics:
  4843.  
  4844.    ■  Windows
  4845.  
  4846.    ■  Window procedures
  4847.  
  4848.    ■  Messages and message queues
  4849.  
  4850.    ■  The os2.ini file
  4851.  
  4852.  
  4853.  6.2  About Window Classes
  4854.  
  4855.    A window class determines the window styles and window procedure given to
  4856.    windows of that class when they are created. Every window created by an
  4857.    application is a member of a window class. Each window class has an
  4858.    associated window procedure that it shares with all windows of that same
  4859.    class. The window procedure handles messages for all windows of that class
  4860.    and therefore defines the behavior and appearance of the window.
  4861.  
  4862.    When an application creates a window, it must specify a window class. The
  4863.    WinCreateWindow function requires that the class be given explicitly.
  4864.    Other window-creation functions use specific classes by default. In all
  4865.    cases, a window class must be registered before it can be used to create
  4866.    windows. An application can register its own (private) window classes or
  4867.    use pregistered, public window classes.
  4868.  
  4869.  6.2.1  Custom Window Classes
  4870.  
  4871.    A custom (or private) window class is any window class registered by an
  4872.    application. The application defines the window procedure, class style,
  4873.    and window data size for the class and then registers the class by using
  4874.    the WinRegisterClass function. The window class is available to the
  4875.    application, but only to that application. Classes created in this way are
  4876.    private and cannot be shared by other applications. When the application
  4877.    terminates, the system removes any data associated with the private window
  4878.    class and invalidates the class name.
  4879.  
  4880.    An application can register its own window classes at any time. Typically,
  4881.    an application registers window classes as part of its initialization, but
  4882.    this is not required. The only restriction is that no window of a
  4883.    particular class can be created until that class is registered by the
  4884.    application.
  4885.  
  4886.    When an application registers a window class, it must supply the following
  4887.    information:
  4888.  
  4889.    ■  Class name
  4890.  
  4891.    ■  Class styles
  4892.  
  4893.    ■  Window procedure
  4894.  
  4895.    ■  Window data size
  4896.  
  4897.    The class name identifies the window class. The application uses the class
  4898.    name when creating a window, specifying the class to use. The class name
  4899.    can be a character string or an integer value. The class name must be
  4900.    unique. The system checks to see if a public class or a class already
  4901.    registered by the application has the same name. If the class name is not
  4902.    unique, an error is returned.
  4903.  
  4904.    The class style is one or more values that tell the system what initial
  4905.    window styles to give a window created with this class. Some class styles
  4906.    (for example, CS_SYNCPAINT) cause a new window to be given the
  4907.    corresponding window style when it is created. Styles such as
  4908.    CS_MOVENOTIFY direct the system to send messages to the window procedure
  4909.    when it ordinarily would not.
  4910.  
  4911.    The window procedure is a function that receives and processes all
  4912.    messages sent to the window by the system. It is the chief component of
  4913.    the window class because it explicitly defines the appearance and behavior
  4914.    of each window created with the class. The window procedure can be part of
  4915.    the application or part of a dynamic-link library. In either case, it must
  4916.    be an exported function. When a window procedure is in a dynamic-link
  4917.    library rather than in the application, the application must import the
  4918.    window procedure by using an import library when linking, using the
  4919.    IMPORTS statement in the application's module-definition file, or using
  4920.    the DosLoadModule and DosGetProcAddr functions to retrieve the function
  4921.    address.
  4922.  
  4923.    The window data size is a value that specifies the number of extra bytes
  4924.    to allocate for each window data structure. The system creates a window
  4925.    data structure for each window. The extra bytes can be used by an
  4926.    application to store additional information about a particular window.
  4927.  
  4928.    Once created, a window-class data structure cannot be changed. However, it
  4929.    is relatively easy to change the window styles and window procedure of a
  4930.    window created with that class. An application cannot deregister a window
  4931.    class. Window classes remain registered and available until the
  4932.    application terminates.
  4933.  
  4934.    An application that registers a window class can also support its own set
  4935.    of window styles for windows of that class. Standard window styles──for
  4936.    example, WS_VISIBLE and WS_SYNCPAINT──still apply to these windows.
  4937.    However, since a window style is a 32-bit integer and only the high 16
  4938.    bits are used for the standard window styles, an application can use the
  4939.    low 16 bits for styles unique to the custom window.
  4940.  
  4941.    MS OS/2 has unique window styles for all preregistered window classes.
  4942.    Styles such as FS_BORDER and BS_PUSHBUTTON are processed by the window
  4943.    procedure for the corresponding class and not by the system. This means
  4944.    that an application can build the support for its own window styles into
  4945.    the window procedure for its custom class. Using a window style designed
  4946.    for one window class will not work with another window class.
  4947.  
  4948.    If more than one instance of an application is running at the same time,
  4949.    the window classes in one instance are not available to any other
  4950.    instance. This means a second instance must register the classes for
  4951.    itself. If an instance of an application terminates, the window classes
  4952.    for any other instance of that application remain unchanged.
  4953.  
  4954.  6.2.2  Class Styles
  4955.  
  4956.    Each window class has one or more class styles. A class style tells the
  4957.    system what initial window style to give a window created with that class.
  4958.    An application sets the class styles for a window class when it registers
  4959.    the class. The styles cannot be changed.
  4960.  
  4961.    When you register a window class, you can specify one or more class
  4962.    styles, combining them as necessary by using the bitwise OR operator.
  4963.  
  4964.    An application can examine the class style for any window class by using
  4965.    the WinQueryClassInfo function. There are ten class styles, as listed
  4966.    below:
  4967.  
  4968. ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
  4969.    Style              Description
  4970.    ──────────────────────────────────────────────────────────────────────────
  4971.    CS_CLIPCHILDREN    Sets the WS_CLIPCHILDREN style for windows created with
  4972.                       this class.
  4973.  
  4974.    CS_CLIPSIBLINGS    Sets the WS_CLIPSIBLINGS style for windows created with
  4975.                       this class.
  4976.  
  4977.    CS_PARENTCLIP      Sets the WS_PARENTCLIP style for windows created with
  4978.                       this class.
  4979.    Style              Description
  4980.    ──────────────────────────────────────────────────────────────────────────
  4981.                      this class.
  4982.  
  4983.    CS_SAVEBITS        Sets the WS_SAVEBITS style for windows created with
  4984.                       this class.
  4985.  
  4986.    CS_SYNCPAINT       Sets the WS_SAVEBITS style for windows created with
  4987.                       this class.
  4988.  
  4989.    CS_FRAME           Identifies windows created with this class as frame
  4990.                       windows.
  4991.  
  4992.    CS_PUBLIC          Creates a public window class.
  4993.  
  4994.    CS_HITTEST         Directs the system to send WM_HITTEST messages to
  4995.                       windows of this class whenever the mouse pointer moves
  4996.                       in the window.
  4997.  
  4998.    CS_SIZEREDRAW      Directs the system to invalidate the entire window
  4999.                       whenever the size of the window changes.
  5000.    Style              Description
  5001.    ──────────────────────────────────────────────────────────────────────────
  5002.                      whenever the size of the window changes.
  5003.  
  5004.    CS_MOVENOTIFY      Directs the system to send WM_MOVE messages to the
  5005.                       window whenever the window is moved.
  5006.    ──────────────────────────────────────────────────────────────────────────
  5007.  
  5008.  
  5009.  6.2.3  Window Procedures
  5010.  
  5011.    The window procedure for a window class handles the messages sent to
  5012.    windows of that class. One window procedure is shared by all windows of a
  5013.    class, so applications must ensure that no conflicts arise when two
  5014.    windows of the same class attempt to access the same global data. In other
  5015.    words, the window procedure must protect global data and other shared
  5016.    resources.
  5017.  
  5018.  6.2.4  Public Window Classes
  5019.  
  5020.    Although MS OS/2 allows an application to register its own window classes,
  5021.    most applications rarely register more than one window class. This window
  5022.    class supports the client window in the application's main window. For all
  5023.    other windows, the application generally uses public window classes.
  5024.    Public window classes support frame windows, controls, menus, and dialog
  5025.    windows.
  5026.  
  5027.    Public window classes are available to all applications. An application
  5028.    does not need to register a public window class to use it. The window
  5029.    procedure for a public window class always resides in a dynamic-link
  5030.    library and is accessible to all applications. An application does not
  5031.    need to import the window procedure to use a public window class.
  5032.  
  5033.  6.2.5  Preregistered Window Classes
  5034.  
  5035.    MS OS/2 provides several preregistered, public window classes.
  5036.    Applications can use these public window classes to create frame windows,
  5037.    dialog windows, menus, push buttons, entry fields, and other controls. The
  5038.    window procedures for these classes are predefined so the application does
  5039.    not register the class before using it.
  5040.  
  5041.    An application uses a preregistered, public window class by specifying its
  5042.    class in a call to the WinCreateWindow function. The class names for the
  5043.    preregistered, public window classes are integer values represented by the
  5044.    following constant names:
  5045.  
  5046. ╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
  5047.    Class name         Description
  5048.    ──────────────────────────────────────────────────────────────────────────
  5049.    WC_FRAME           Creates a frame window. Has class styles CS_FRAME,
  5050.                       CS_HITTEST, CS_SYNCPAINT, CS_PUBLIC, and
  5051.                       CS_CLIPSIBLINGS.
  5052.  
  5053.    WC_BUTTON          Creates a button control. Has class styles
  5054.                       CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, and
  5055.                       CS_PUBLIC.
  5056.  
  5057.    WC_ENTRYFIELD      Creates a text-entry control field. Has class styles
  5058.                       CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, and
  5059.                       CS_PUBLIC.
  5060.  
  5061.    WC_LISTBOX         Creates a list box. Has class styles CS_PARENTCLIP,
  5062.                       CS_SYNCPAINT, and CS_PUBLIC.
  5063.    Class name         Description
  5064.    ──────────────────────────────────────────────────────────────────────────
  5065.                      CS_SYNCPAINT, and CS_PUBLIC.
  5066.  
  5067.    WC_MENU            Creates a menu. Has class styles CS_SYNCPAINT,
  5068.                       CS_SIZEREDRAW, and CS_PUBLIC.
  5069.  
  5070.    WC_SCROLLBAR       Creates a scroll bar. Has class styles CS_HITTEST,
  5071.                       CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, and
  5072.                       CS_PUBLIC.
  5073.  
  5074.    WC_STATIC          Creates a static control. Has class styles
  5075.                       CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, CS_HITTEST,
  5076.                       and CS_PUBLIC.
  5077.  
  5078.    WC_TITLEBAR        Creates a title bar. Has class styles CS_HITTEST,
  5079.                       CS_PARENTCLIP, CS_SYNCPAINT, CS_SIZEREDRAW, and
  5080.                       CS_PUBLIC.
  5081.    ──────────────────────────────────────────────────────────────────────────
  5082.  
  5083.  
  5084.    Each preregistered, public window class also supports several window
  5085.    styles that an application can use to customize a window. For example, a
  5086.    window created with the WC_BUTTON class can have any one of four different
  5087.    behaviors and appearances. The application specifies the style (and the
  5088.    behavior and appearance of the window) in the call to the WinCreateWindow
  5089.    function. For a list of the available styles and more detailed information
  5090.    on each of the preregistered, public window classes, see Chapter 10,
  5091.    "Control Windows."
  5092.  
  5093.    An application must not use the preregistered, public window-class names
  5094.    when it registers its own window classes.
  5095.  
  5096.  6.2.6  Custom Public Classes
  5097.  
  5098.    An application can create its own public window class, but this must be
  5099.    done in a special manner at system initialization. Only the shell can
  5100.    register a public window class and only when the system starts.
  5101.    Registering a public window class requires a special load entry in the
  5102.    os2.ini file that instructs the shell to load a dynamic-link library whose
  5103.    initialization routine registers the window class. Public window classes
  5104.    must be registered by using the WinRegisterClass function and must have
  5105.    the class style CS_PUBLIC. A public window class registered in this way
  5106.    can have the same name as an existing public window class, but this
  5107.    replaces the original window class.
  5108.  
  5109.    If a dynamic-link library replaces a public window class, it can also save
  5110.    the previous window-procedure address and use it to subclass the original
  5111.    window class. The dynamic-link library retrieves the original
  5112.    window-procedure address by using the WinQueryClassInfo function. The new
  5113.    window procedure then passes unprocessed messages to the original window
  5114.    procedure. All windows created using this revised public window class will
  5115.    automatically be subclassed.
  5116.  
  5117.    When subclassing a public window class, the window data size cannot be
  5118.    smaller than the original window data size. All public window classes
  5119.    defined by MS OS/2 use four extra bytes for storing a pointer to custom
  5120.    window data. This size is not guaranteed for public window classes defined
  5121.    by dynamic-link modules not belonging to MS OS/2.
  5122.  
  5123.  6.2.7  Class Data
  5124.  
  5125.    An application can examine a registered window class by using the
  5126.    WinQueryClassInfo function. This is useful for checking the class styles
  5127.    of a public window class. An application can also retrieve the name of the
  5128.    class for a given window by using the WinQueryClassName function. Using
  5129.    the window class name, you can then call the WinQueryClassInfo function to
  5130.    retrieve the window class data.
  5131.  
  5132.    The WinQueryClassName function retrieves the name of the window class. If
  5133.    the window is one of the preregistered, public window classes, the window
  5134.    class name returned is in the form #nnnnn, where nnnnn is up to five
  5135.    digits representing the value of the window class name constant.
  5136.  
  5137.    The WinQueryClassInfo function retrieves information about a window class.
  5138.    It copies the class style, window-procedure address, and window data size
  5139.    to a CLASSINFO data structure. The CLASSINFO structure has the following
  5140.    form:
  5141.  
  5142.    typedef struct _CLASSINFO {    /* clsi */
  5143.        ULONG  flClassStyle;
  5144.        PFNWP  pfnWindowProc;
  5145.        USHORT cbWindowData;
  5146.    } CLASSINFO;
  5147.  
  5148.  
  5149.  6.3  Using Window Classes
  5150.  
  5151.    The following sections explain how to register and use window classes in
  5152.    your applications.
  5153.  
  5154.  6.3.1  Registering a Private Window Class
  5155.  
  5156.    You can register a private window class at any time by using the
  5157.    WinRegisterClass function. You must define the window procedure in your
  5158.    application, choose a unique name, and set the window class styles for the
  5159.    class. The following code fragment shows how to register the window class
  5160.    name "MyPrivateName".
  5161.  
  5162.    WinRegisterClass(hab,    /* anchor-block handle      */
  5163.        "MyPrivateName",     /* class name               */
  5164.        MyWindowProc,        /* far pointer to procedure */
  5165.        CS_SIZEREDRAW,       /* class style              */
  5166.        0);                  /* window data              */
  5167.  
  5168.  6.3.2  Registering an Imported Window Procedure
  5169.  
  5170.    You do not have to limit window procedures to your application's code
  5171.    segments. You can also register a window procedure that is imported from a
  5172.    dynamic-link library. You can do this in several ways. The easiest way is
  5173.    to import the window-procedure name by using either the IMPORTS statement
  5174.    in the application's module-definition file or by linking with an import
  5175.    library that contains an import record for the function.
  5176.  
  5177.  
  5178.  6.4  Summary
  5179.  
  5180.    An application can use the following functions to register and use window
  5181.    classes:
  5182.  
  5183.    WinQueryClassInfo  Obtains information about a window class. The class is
  5184.    specified by name. The function fills a CLASSINFO data structure. This
  5185.    gives you the long word of the window-class style, a pointer to its window
  5186.    procedure, and the number of additional words stored as part of the class.
  5187.  
  5188.    WinQueryClassName  Obtains a window class name for a given window. If the
  5189.    window class is one of the preregistered, public classes, the class name
  5190.    returned is in the form #nnnnn, where nnnnn is up to five digits
  5191.    representing the value of the window class name constant.
  5192.  
  5193.    WinRegisterClass  Registers a window class.
  5194.  
  5195.  
  5196.  
  5197.  ────────────────────────────────────────────────────────────────────────────
  5198.  Chapter 7  Window Procedures
  5199.  
  5200.         7.1     Introduction
  5201.         7.2     About Window Procedures
  5202.             7.2.1     Structure of a Window Procedure
  5203.                 7.2.1.1    Calling Convention
  5204.                 7.2.1.2    Arguments
  5205.                 7.2.1.3    Return Value
  5206.             7.2.2     Default Window Procedure
  5207.         7.3     Using a Window Procedure
  5208.             7.3.1     Associating a Window Procedure and Classes
  5209.             7.3.2     Processing a Default Window Procedure
  5210.         7.4     Summary
  5211.             7.4.1     Window-Procedure Syntax
  5212.             7.4.2     Messages Processed by the Default Window Procedure
  5213.  
  5214.  7.1  Introduction
  5215.  
  5216.    This chapter describes window procedures and the default window procedure.
  5217.    You should also be familiar with the following topics:
  5218.  
  5219.    ■  Standard user-interface guidelines
  5220.  
  5221.    ■  Window classes
  5222.  
  5223.    ■  Window messages and message queues
  5224.  
  5225.    ■  Dialog windows and dialog procedures
  5226.  
  5227.  
  5228.  7.2  About Window Procedures
  5229.  
  5230.    Every window in MS OS/2 is associated with a window procedure that
  5231.    controls all aspects of the window: its appearance, how it responds to
  5232.    state changes, and how it processes user input.
  5233.  
  5234.    Each window class has an associated window procedure, and all windows of
  5235.    that class use the same window procedure. For example, the system defines
  5236.    a window procedure for the frame window class, and all frame windows use
  5237.    that window procedure.
  5238.  
  5239.    Applications typically define at least one new window class and an
  5240.    associated window procedure. The application can then create many
  5241.    instances of windows with that class, all of which use the same window
  5242.    procedure. Note that this means that the same piece of code may be called
  5243.    from several sources simultaneously. Therefore, care must be used when
  5244.    modifying shared resources from a window procedure.
  5245.  
  5246.    Dialog procedures have the same structure and function as window
  5247.    procedures. All material referring to window procedures in this chapter
  5248.    also applies to dialog procedures. The only real difference between a
  5249.    dialog procedure and a window procedure is the recommended default
  5250.    procedure and what messages are handled.
  5251.  
  5252.    The rest of this chapter shows how to write a window procedure and
  5253.    associate it with a window class.
  5254.  
  5255.  7.2.1  Structure of a Window Procedure
  5256.  
  5257.    All window procedures share a common syntax and structure. Because all
  5258.    messages must use the same calling syntax, the arguments and return value
  5259.    for window procedures are interpreted differently depending on the message
  5260.    being handled. The following sections describe the syntax and structure of
  5261.    a window procedure.
  5262.  
  5263.    7.2.1.1  Calling Convention
  5264.  
  5265.    From a programmer's point of view, a window procedure is a function that
  5266.    takes four arguments and returns a long word. The function must use Pascal
  5267.    calling conventions; that is, the arguments are pushed on the stack from
  5268.    left to right in the function definition and the function must clear the
  5269.    arguments from the stack before returning. This is different from the
  5270.    normal C-language calling convention, so the Microsoft C Optimizing
  5271.    Compiler provides the pascal keyword for defining functions that use the
  5272.    Pascal calling convention.
  5273.  
  5274.    You should use the EXPENTRY macro when defining window procedures to
  5275.    ensure that the functions are declared appropriately.
  5276.  
  5277.    Finally, you must ensure that the data-segment register is properly set up
  5278.    on entry to the window procedure. When the system calls the window
  5279.    procedure, it passes the proper data segment in the ax register. If you
  5280.    are programming in Microsoft C, use the _loadds keyword in your
  5281.    window-procedure definitions. This causes the compiler to insert the
  5282.    proper prolog and epilog code in your window procedures so that the data
  5283.    segment is initialized and restored properly. If you are programming in
  5284.    assembly language, you should load the ds register from ax on entry and
  5285.    restore the ds register on exit. If you are using another development
  5286.    environment, consult the relevant documentation for the appropriate
  5287.    compiler switch.
  5288.  
  5289.    Because a window procedure can be called recursively, it is probably best
  5290.    to minimize the number of local variables used in the window procedure. To
  5291.    avoid overusing local variables and possible stack overflow in deep
  5292.    recursion, you should call other functions outside your window procedure
  5293.    to process individual messages.
  5294.  
  5295.    7.2.1.2  Arguments
  5296.  
  5297.    A window procedure takes four arguments: The first is a window handle; the
  5298.    second is a USHORT message designator; and the last two arguments are
  5299.    declared with the MPARAM data type, which is defined in the include files
  5300.    as a far pointer to the VOID data type (a generic pointer). The message
  5301.    arguments often contain information in both the low and high words of the
  5302.    long word. There are several macros defined in the pmwin.h include file
  5303.    that make it easier to extract bytes or integers from the fbMPARAM value.
  5304.    These macros include SHORT1FROMMP, which extracts the low-order word from
  5305.    an MPARAM value.
  5306.  
  5307.    The window-procedure arguments are described in the following list:
  5308.  
  5309.    Argument  Description
  5310.    ──────────────────────────────────────────────────────────────────────────
  5311.    hwnd      Window handle of the window receiving the message.
  5312.  
  5313.    msg       Message identifier. The message will generally correspond to one
  5314.              of the predefined constants (for example, WM_CREATE) defined in
  5315.              the system include files. This argument can also be equal to an
  5316.              application-defined message identifier. Application-defined
  5317.              messages must be greater than WM_USER. If a window procedure
  5318.              does not process a message, it is strongly recommended that it
  5319.              pass the message to the WinDefWindowProc function. This allows
  5320.              the default processing for the message to occur.
  5321.  
  5322.    mp1       Message parameter. Its interpretation depends on the particular
  5323.              message.
  5324.  
  5325.    mp2       Message parameter. Its interpretation depends on the particular
  5326.              message.
  5327.    ──────────────────────────────────────────────────────────────────────────
  5328.  
  5329.    7.2.1.3  Return Value
  5330.  
  5331.    The return value of a window procedure is defined as an MRESULT type. This
  5332.    is defined in the include files as a far pointer to a VOID data type. The
  5333.    actual interpretation of the return value depends on the particular
  5334.    message. Consult the description of each message to determine the
  5335.    appropriate return value.
  5336.  
  5337.  7.2.2  Default Window Procedure
  5338.  
  5339.    All windows in MS OS/2 share certain fundamental behavior. This basic
  5340.    behavior is encapsulated in the WinDefWindowProc function, the default
  5341.    window procedure. The default window procedure is provided so you can get
  5342.    the minimal functionality for a window by calling WinDefWindowProc.
  5343.    Control windows defined by the system can also call WinDefWindowProc for
  5344.    default processing.
  5345.  
  5346.  
  5347.  7.3  Using a Window Procedure
  5348.  
  5349.    The following code fragments show a sample window procedure. It shows how
  5350.    to use the message argument in a switch statement with individual messages
  5351.    handled by each case statement. Notice that each case returns a value
  5352.    specifically for that message. Consult the description of each message to
  5353.    determine the appropriate return value.
  5354.  
  5355.    The window procedure calls the WinDefWindowProc function for any messages
  5356.    that it does not handle itself. WinDefWindowProc performs default
  5357.    processing for essential messages sent to windows.
  5358.  
  5359.    MRESULT CALLBACK MyWindowProc(hwnd, msg, mp1, mp2)
  5360.    HWND   hwnd;
  5361.    USHORT msg;
  5362.    MPARAM mp1;
  5363.    MPARAM mp2;
  5364.    {
  5365.        /* local variables */
  5366.  
  5367.        switch (msg) {
  5368.  
  5369.            case WM_CREATE:
  5370.            /* Initialize private window data. */
  5371.  
  5372.                return 0L;
  5373.  
  5374.            case WM_PAINT:
  5375.            /* Paint the window. */
  5376.  
  5377.                return 0L;
  5378.  
  5379.            case WM_DESTROY:
  5380.            /* Clean up private window data. */
  5381.  
  5382.                return 0L;
  5383.  
  5384.            default:
  5385.                break;
  5386.        }
  5387.        return (WinDefWindowProc(hwnd, msg, mp1, mp2));
  5388.    }
  5389.  
  5390.    A dialog procedure is exactly like a window procedure except that it
  5391.    receives a WM_INITDLG message instead of the WM_CREATE message. A dialog
  5392.    procedure should pass all unprocessed messages to the WinDefDlgProc
  5393.    function instead of passing them to the WinDefWindowProc function.
  5394.  
  5395.    It is possible to write a window procedure that passes all messages to
  5396.    WinDefWindowProc, but the window will have no personality of its own. At
  5397.    the very least, a window procedure should handle the WM_PAINT message to
  5398.    draw itself. Typically, it should handle mouse and keyboard messages as
  5399.    well. Consult the descriptions of individual messages to determine if your
  5400.    window procedure should handle them.
  5401.  
  5402.    There are times when you may want to create a window that does not change
  5403.    the default window behavior. That window's sole purpose is to keep track
  5404.    of its child windows. Object windows are often used this way. An easy way
  5405.    to create a window that does not change the default window behavior is to
  5406.    specify the WinDefWindowProc function as your window procedure when
  5407.    registering the window class. The application then does not write a
  5408.    separate window procedure for windows of this class.
  5409.  
  5410.  7.3.1  Associating a Window Procedure and Classes
  5411.  
  5412.    A window procedure is associated with a window class by passing a far
  5413.    pointer to the window procedure to the WinRegisterClass function. Once
  5414.    registered this way, the window procedure will be associated with each new
  5415.    window created with that class.
  5416.  
  5417.    The following code fragment shows how to associate a window procedure with
  5418.    a window class:
  5419.  
  5420.    WinRegisterClass(hab,    /* anchor-block handle      */
  5421.        szClassName,         /* class name               */
  5422.        MyWindowProc,        /* far pointer to procedure */
  5423.        CS_SIZEREDRAW,       /* class style              */
  5424.        0);                  /* window data              */
  5425.  
  5426.    Another useful option is to subclass a window of an existing class. This
  5427.    is most often used to add functionality or to alter the behavior of frame
  5428.    windows.
  5429.  
  5430.    To subclass a window, call the WinSubclassWindow function. This function
  5431.    returns a pointer to the window procedure for the window. Subclassing
  5432.    allows you to process messages using your own window procedure before
  5433.    passing unprocessed messages to the original window procedure. In this
  5434.    way, you can use the original window procedure instead of WinDefWindowProc
  5435.    for default window processing.
  5436.  
  5437.  7.3.2  Processing a Default Window Procedure
  5438.  
  5439.    Typically, you call the WinDefWindowProc function for any messages that
  5440.    are not handled in your window procedure. For each message handled you
  5441.    should return an explicit value that depends on the particular message.
  5442.    For all other messages you should return the WinDefWindowProc function.
  5443.    The following code fragment shows how to structure a window procedure to
  5444.    call the default window procedure for any unused messages:
  5445.  
  5446.    switch (usMessage) {
  5447.        case WM_PAINT:
  5448.            hps = WinBeginPaint(hwnd, NULL, &rect);
  5449.            WinFillRect(hps, &rect, CLR_WHITE);
  5450.            WinEndPaint(hps);
  5451.            return 0L;
  5452.        default:
  5453.            break;
  5454.    }
  5455.    return (WinDefWindowProc(hwnd, usMessage, mp1, mp2));
  5456.  
  5457.    You can also call WinDefWindowProc as part of your own processing of a
  5458.    window message. In these cases, you may want to modify the parameters to
  5459.    the message before passing it to WinDefWindowProc, or you may want to
  5460.    continue with the default processing after performing your own operations.
  5461.  
  5462.  
  5463.  7.4  Summary
  5464.  
  5465.    This section gives the window-procedure syntax and lists the messages
  5466.    processed by the default window procedure.
  5467.  
  5468.  7.4.1  Window-Procedure Syntax
  5469.  
  5470.    The following shows the syntax for a window procedure:
  5471.  
  5472.      MRESULT CALLBACK WindowProc(HWND hwnd, USHORT msg,
  5473.          MPARAM mp1, MPARAM mp2)
  5474.  
  5475.  7.4.2  Messages Processed by the Default Window Procedure
  5476.  
  5477.    The following messages are handled by the WinDefWindowProc function. For
  5478.    each message, the default processing is described; typical reasons for
  5479.    overriding the default behavior are also given:
  5480.  
  5481.    WM_BUTTON1DBLCLK  The default window procedure passes this message to the
  5482.    owner window. Processing this message allows you to add functionality to
  5483.    mouse clicks and to differentiate the three possible mouse buttons.
  5484.  
  5485.    WM_BUTTON1DOWN  The default window procedure activates the window by
  5486.    calling the WinSetActiveWindow function. Processing this message allows
  5487.    you to add functionality to mouse clicks and to differentiate the three
  5488.    possible mouse buttons.
  5489.  
  5490.    WM_BUTTON1UP  The default window procedure passes this message to the
  5491.    owner window. Processing this message allows you to add functionality to
  5492.    mouse clicks and to differentiate the three possible mouse buttons.
  5493.  
  5494.    WM_BUTTON2DBLCLK  The default window procedure passes this message to the
  5495.    owner window. Processing this message allows you to add functionality to
  5496.    mouse clicks and to differentiate the three possible mouse buttons.
  5497.  
  5498.    WM_BUTTON2DOWN  The default window procedure activates the window by
  5499.    calling the WinSetActiveWindow function. Processing this message allows
  5500.    you to add functionality to mouse clicks and to differentiate the three
  5501.    possible mouse buttons.
  5502.  
  5503.    WM_BUTTON2UP  The default window procedure passes this message to the
  5504.    owner window. Processing this message allows you to add functionality to
  5505.    mouse clicks and to differentiate the three possible mouse buttons.
  5506.  
  5507.    WM_BUTTON3DBLCLK  The default window procedure passes this message to the
  5508.    owner window. Processing this message allows you to add functionality to
  5509.    mouse clicks and to differentiate the three possible mouse buttons.
  5510.  
  5511.    WM_BUTTON3DOWN  The default window procedure activates the window by
  5512.    calling the WinSetActiveWindow function. Processing this message allows
  5513.    you to add functionality to mouse clicks and to differentiate the three
  5514.    possible mouse buttons.
  5515.  
  5516.    WM_BUTTON3UP  The default window procedure passes this message to the
  5517.    owner window. Processing this message allows you to add functionality to
  5518.    mouse clicks and to differentiate the three possible mouse buttons.
  5519.  
  5520.    WM_CALCVALIDRECTS  The default window procedure returns the long-word
  5521.    value. Processing this message allows you to specify the portion of the
  5522.    window that is preserved when the window is resized and to specify where
  5523.    the preserved area is aligned when the window is redrawn.
  5524.  
  5525.    WM_CHAR  The default window procedure passes this message to the window
  5526.    owner. You can process this message to evaluate incoming keyboard events.
  5527.    In the case of standard control windows, unused WM_CHAR messages are
  5528.    passed to the WinDefWindowProc function and passed up the parent- and
  5529.    child-window hierarchy until reaching a frame or dialog window where
  5530.    default dialog effects, such as pressing the TAB key to move from control
  5531.    to control, are implemented.
  5532.  
  5533.    WM_CLOSE  The default window procedure posts a WM_QUIT message to the
  5534.    queue, which causes the message loop to terminate. Processing this message
  5535.    allows you to prevent the Close menu item in the System menu from
  5536.    terminating the program. This is particularly useful with child frame
  5537.    windows in a multiple-document application.
  5538.  
  5539.    WM_CONTROLHEAP  The default window procedure returns the heap handle for
  5540.    the heap maintained by the system for the window message queue. You
  5541.    process this message if the window maintains a separate heap.
  5542.  
  5543.    WM_CONTROLPOINTER  The default window procedure returns the mouse pointer
  5544.    passed in the mp2 parameter, thus allowing the default pointer shape. This
  5545.    message is sent to the owner of a control window to allow it to change the
  5546.    shape of the mouse pointer when the pointer is over the control window.
  5547.    You can return a different mouse-pointer handle to override the mouse
  5548.    pointer chosen by the control window. For example, a special control that
  5549.    handles its mouse-movement message by sending a WM_CONTROLPOINTER message
  5550.    to its owner with its special pointer. The owner window then determines
  5551.    what pointer to use. The default window procedure would use the control's
  5552.    special pointer.
  5553.  
  5554.    WM_DDE_INITIATE  The default window procedure frees the selector in the
  5555.    mp2 parameter and returns FALSE. You should process this message if your
  5556.    application supports the dynamic-data-exchange (DDE) protocol.
  5557.  
  5558.    WM_DDE_INITIATEACK  The default window procedure frees the selector in the
  5559.    mp2 parameter and returns FALSE. You should process this message if your
  5560.    application supports the dynamic-data-exchange (DDE) protocol.
  5561.  
  5562.    WM_FOCUSCHANGE  The default window procedure passes the message to the
  5563.    owner window (if one exists) or to the parent window if no owner exists.
  5564.    If no owner or parent window exists, the default window procedure does
  5565.    nothing. Generally, this message is passed up the parent- and child-window
  5566.    hierarchy until it reaches a frame window, where the appropriate
  5567.    WM_ACTIVATE, WM_SETSELECTION, and WM_SETFOCUS messages are generated. This
  5568.    message is the first indication of a focus change.
  5569.  
  5570.    WM_HELP  The default window procedure passes this message to the parent
  5571.    window (if one exists). You process this message to provide
  5572.    context-sensitive help.
  5573.  
  5574.    WM_HITTEST  The default window procedure returns HT_ERROR if the window is
  5575.    disabled; otherwise, it returns HT_NORMAL. Processing this message to
  5576.    return HT_NORMAL for a disabled window allows the disabled window to
  5577.    receive mouse messages.
  5578.  
  5579.    WM_MENUSELECT  The default window procedure returns TRUE, which means the
  5580.    menu selection should be processed normally. You can process this message
  5581.    if you want to perform context-sensitive actions──for example, processing
  5582.    explanatory messages, each time a menu item is selected.
  5583.  
  5584.    WM_MOUSEMOVE  The default window procedure sets the mouse pointer to the
  5585.    arrow pointer. You normally process this message for mouse tracking after
  5586.    a mouse button-down message. This message is also useful for setting the
  5587.    mouse-pointer shape, depending on where the mouse is in the window.
  5588.  
  5589.    WM_PAINT  The default window procedure calls the WinBeginPaint and
  5590.    WinEndPaint functions to empty the update region for the window. If you do
  5591.    not process this message, the window will not be drawn.
  5592.  
  5593.    WM_QUERYCONVERTPOS  The default window procedure returns the cursor size
  5594.    and positional data pointed to by the mp1 parameter and returns
  5595.    QCP_CONVERT to signify that the RECTL structure passed was properly
  5596.    converted.
  5597.  
  5598.    WM_QUERYFOCUSCHAIN  The default window procedure performs the default
  5599.    processing of this message, which defines the focus chain for that window.
  5600.  
  5601.    WM_QUERYFRAMECTLCOUNT  The default window procedure passes this message to
  5602.    the parent window until it finds a frame window, where it will be
  5603.    processed.
  5604.  
  5605.    WM_QUERYWINDOWPARAMS  The default window procedure sets all window
  5606.    parameters in the passed structure to zero and returns FALSE to indicate
  5607.    that the operation was not successful.
  5608.  
  5609.    WM_SETWINDOWPARAMS  The default window procedure does nothing except
  5610.    return FALSE.
  5611.  
  5612.    WM_TIMER  The default window procedure blinks the cursor for the window if
  5613.    the timer message has the TID_CURSOR timer ID. You process this message
  5614.    only if they create their own timers. Applications should pass a WM_TIMER
  5615.    (TID_CURSOR) message to the WinDefWindowProc function even if the
  5616.    application processes its own timers.
  5617.  
  5618.    WM_TRANSLATEACCEL  The default window procedure passes this message to the
  5619.    parent window (if one exists). This message is usually passed from a child
  5620.    window to its parent window until it reaches a frame window, where the
  5621.    default frame-window procedure calls the WinTranslateAccel function to
  5622.    determine if the key pressed is a valid accelerator key.
  5623.  
  5624.  
  5625.  
  5626.  ────────────────────────────────────────────────────────────────────────────
  5627.  Chapter 8  Mouse and Keyboard Input
  5628.  
  5629.         8.1     Introduction
  5630.         8.2     About Mouse and Keyboard Input
  5631.             8.2.1     The System Message Queue
  5632.             8.2.2     Mouse Capture
  5633.             8.2.3     Keyboard Focus
  5634.             8.2.4     Window Activation
  5635.         8.3     Using the Mouse and Keyboard in an Application
  5636.             8.3.1     Responding to Activation Events
  5637.             8.3.2     Responding to Mouse Messages
  5638.                 8.3.2.1    Responding to Button Clicks
  5639.                 8.3.2.2    Responding to Mouse Movement
  5640.             8.3.3     Changing the Mouse Capture
  5641.             8.3.4     Keyboard Messages
  5642.             8.3.5     Responding to Keyboard Messages
  5643.                 8.3.5.1    Key-Down or Key-Up Events
  5644.                 8.3.5.2    Repeat-Count Events
  5645.                 8.3.5.3    Character Codes
  5646.                 8.3.5.4    Virtual-Key Codes
  5647.                 8.3.5.5    Scan Codes
  5648.                 8.3.5.6    Accelerator-Table Entries
  5649.             8.3.6     Changing the Keyboard Focus
  5650.         8.4     Summary
  5651.             8.4.1     Functions
  5652.             8.4.2     Messages
  5653.                 8.4.2.1    Focus Change and Activation Messages
  5654.                 8.4.2.2    Mouse Messages
  5655.                 8.4.2.3    Keyboard Message
  5656.  
  5657.  8.1  Introduction
  5658.  
  5659.    This chapter describes how to use mouse and keyboard input in your
  5660.    applications. You should also be familiar with the following topics:
  5661.  
  5662.    ■  Standard user-interface guidelines
  5663.  
  5664.    ■  Window messages and message queues
  5665.  
  5666.    ■  Accelerator tables
  5667.  
  5668.  
  5669.  8.2  About Mouse and Keyboard Input
  5670.  
  5671.    MS OS/2 Presentation Manager applications should support input from both
  5672.    the mouse and keyboard. The mouse can have either one, two, or three
  5673.    buttons. Only one window at a time can receive mouse input and only one
  5674.    window at a time can receive keyboard input. These windows are not
  5675.    necessarily the same, although they can be.
  5676.  
  5677.  8.2.1  The System Message Queue
  5678.  
  5679.    All mouse and keyboard input is routed through a single system message
  5680.    queue. The system takes input events, such as keys being pressed or mouse
  5681.    movements, out of the system queue and routes them to the appropriate
  5682.    application. Generally, mouse input is directed to the application that
  5683.    owns the window in which the mouse-pointer event occurs. An application
  5684.    can route all mouse input, regardless of mouse position, to a particular
  5685.    window by setting the mouse capture window. Keyboard input is sent to the
  5686.    application that owns the "keyboard focus" window. Keyboard focus and
  5687.    mouse capture are discussed more fully later in this chapter.
  5688.  
  5689.    The system takes messages out of the system message queue and places them
  5690.    in the appropriate application message queue. An application receives
  5691.    input messages from its own queue by calling the WinGetMsg or WinPeekMsg
  5692.    function.
  5693.  
  5694.    Mouse and keyboard events in the system queue are strictly ordered so that
  5695.    an input event cannot be processed until all previous input events have
  5696.    been fully processed. This is because the destination window of an input
  5697.    event is not known until all previous input has been processed.
  5698.  
  5699.    For example, if a user types a command in one window, uses the mouse to
  5700.    activate another window, and then types another command in the second
  5701.    window, the destination of the second keyboard command depends on how the
  5702.    mouse click is handled. An application might not activate its window in
  5703.    response to the mouse click. The second keyboard event goes to the second
  5704.    window only if that window becomes active as a result of the mouse click,
  5705.    which also depends on how the application processes the mouse click.
  5706.  
  5707.    Because the input queue is strictly ordered and events cannot be processed
  5708.    until all previous input has been processed, it is very important that
  5709.    applications process input events quickly to avoid slowing user
  5710.    interactions with the system.
  5711.  
  5712.  8.2.2  Mouse Capture
  5713.  
  5714.    Generally, a mouse message goes to the window under the mouse pointer at
  5715.    the time the event is read from the system queue. Applications can change
  5716.    this by setting the mouse capture window, in which case all mouse input is
  5717.    sent to the mouse capture window until the mouse capture is released or
  5718.    set to another window. Mouse capture is useful if a window should receive
  5719.    all mouse input even when the mouse pointer moves outside the window. For
  5720.    example, it is common to track the mouse-pointer position after a mouse
  5721.    button-down event, following the mouse pointer until a mouse button-up
  5722.    event is received. If you do not set the mouse capture to a particular
  5723.    window and the user moves the mouse pointer outside the window and
  5724.    releases the mouse button, your application will not receive the mouse
  5725.    button-up message. If you set the mouse capture to a particular window
  5726.    while tracking the mouse pointer, your application will receive the mouse
  5727.    button-up message even if the mouse moves outside the window.
  5728.  
  5729.  8.2.3  Keyboard Focus
  5730.  
  5731.    Only one window at a time receives keyboard input. The window receiving
  5732.    the keyboard input is called the keyboard-focus window. Applications can
  5733.    allow the system to set the keyboard-focus window by default as windows
  5734.    are activated and deactivated, or an application can specifically set the
  5735.    keyboard focus to a specific window. If there is no keyboard-focus window
  5736.    specified, the system sends keyboard input to the currently active frame
  5737.    window.
  5738.  
  5739.  8.2.4  Window Activation
  5740.  
  5741.    Because there can be many windows belonging to many applications on the
  5742.    screen at the same time, MS OS/2 provides a way to arbitrate input among
  5743.    windows and applications. There is at most one active application at any
  5744.    time in the Presentation Manager screen group. The active application
  5745.    usually has only one active frame window, although it is possible to have
  5746.    more than one active frame window. For example, an application with a
  5747.    multiple-document interface can have several child frame windows.
  5748.  
  5749.    The activation state of a window is important when an application responds
  5750.    to mouse clicks. It is also important because activation and keyboard
  5751.    focus are closely related window attributes.
  5752.  
  5753.    The WinQueryActiveWindow function returns the currently active frame
  5754.    window. Note that a client window is never returned by this function.
  5755.    Activation of the client window is an attribute of frame windows.
  5756.  
  5757.  
  5758.  8.3  Using the Mouse and Keyboard in an Application
  5759.  
  5760.    An application that uses the mouse and keyboard for input must respond to
  5761.    activation, mouse, and keyboard events. The following sections describe
  5762.    how to handle these three related topics.
  5763.  
  5764.  8.3.1  Responding to Activation Events
  5765.  
  5766.    A client window receives a WM_ACTIVATE message when its parent frame
  5767.    window is being activated or deactivated. The activation or deactivation
  5768.    message is usually accompanied by messages to set or lose the keyboard
  5769.    focus. Therefore, applications should not use the WM_ACTIVATE message to
  5770.    change the keyboard focus.
  5771.  
  5772.    The low word of the first message parameter is TRUE if the window is
  5773.    activated, and FALSE if the window is deactivated.
  5774.  
  5775.    One use for the WM_ACTIVATE message is to toggle the state of an
  5776.    application's private variable that tells whether a window is active or
  5777.    not, as shown in the following code fragment:
  5778.  
  5779.    case WM_ACTIVATE:
  5780.         fActivated = (BOOL) mp1;
  5781.         return(0L);
  5782.  
  5783.    It is important to know the activation state of a window in order to
  5784.    correctly handle mouse-button clicks.
  5785.  
  5786.  8.3.2  Responding to Mouse Messages
  5787.  
  5788.    Mouse messages occur when a user presses or releases one of the mouse
  5789.    buttons (a click) and when the mouse is moved. All mouse messages contain
  5790.    the x- and y-coordinates of the mouse-pointer hot spot (relative to the
  5791.    window coordinates of the window receiving the message) at the time the
  5792.    event occurs.
  5793.  
  5794.    The system sends a WM_HITTEST message to the window that is about to
  5795.    receive a mouse message. The window can determine if it should actually
  5796.    receive the mouse message or not. The default processing of this message
  5797.    in the WinDefWindowProc function is to return HT_NORMAL if the window is
  5798.    enabled and HT_ERROR if the window is disabled. If the return value is
  5799.    HT_ERROR, the system does not send the mouse message to the window. Most
  5800.    applications pass WM_HITTEST messages on to the WinDefWindowProc function
  5801.    by default so disabled windows do not receive mouse messages. Windows that
  5802.    specifically respond to WM_HITTEST messages can change this default
  5803.    behavior.
  5804.  
  5805.    Because windows process WM_HITTEST and mouse messages, an application can
  5806.    ignore hit-test code in a mouse message unless the application returns
  5807.    special values for hit-test code. One possible use for hit-test code is to
  5808.    react differently to a mouse click in a disabled window.
  5809.  
  5810.    The contents of the mouse-message arguments (mp1 and mp2) are listed
  5811.    below:
  5812.  
  5813.    ■  The x-position is in low word of mp1.
  5814.  
  5815.    ■  The y-position is in high word of mp1.
  5816.  
  5817.    ■  The hit-test code is in low word of mp2.
  5818.  
  5819.    8.3.2.1  Responding to Button Clicks
  5820.  
  5821.    Applications typically respond to mouse button-down events differently
  5822.    depending on whether the window is currently active. The first button-down
  5823.    event in an inactive window should activate a window. A subsequent
  5824.    button-down event in an active window produces an application-specific
  5825.    action.
  5826.  
  5827.    Typically, an application processes mouse clicks in the client window of a
  5828.    standard frame window. Because the activated/deactivated status of a
  5829.    window is a frame-window characteristic, the system does not provide an
  5830.    easy way to determine if the client window is active. That is, the window
  5831.    handle returned by the WinQueryActiveWindow function is the active
  5832.    frame-window handle rather than the client window owned by the frame.
  5833.  
  5834.    The following are two typical methods for determining if a client is an
  5835.    active frame window:
  5836.  
  5837.    ■  Call the WinQueryActiveWindow function and compare the window handle it
  5838.       returns with the frame window that contains the client window, as shown
  5839.       in the following code fragment:
  5840.  
  5841.       fActivated = (WinQueryWindow(hwndClient, QW_PARENT, FALSE) ==
  5842.           WinQueryActiveWindow(HWND_DESKTOP, FALSE))
  5843.  
  5844.    ■  Maintain a private variable for the client window that is set and
  5845.       cleared when processing WM_ACTIVATE messages. Each time the frame
  5846.       window is activated, the client window receives a WM_ACTIVATE message
  5847.       with the low word of the first parameter equal to TRUE. When the frame
  5848.       window is deactivated, the client window receives a WM_ACTIVATE message
  5849.       with a FALSE activation indicator. The following code fragment shows
  5850.       how to use activation messages to toggle a private-status variable:
  5851.  
  5852.       case WM_ACTIVATE:
  5853.            fActivated = (BOOL) mp1;
  5854.            return (0L);
  5855.  
  5856.    Depending on the method used to determine if a client window is active, a
  5857.    mouse button-down message is passed to the WinDefWindowProc function if
  5858.    the window is not active at the time of the message. The default
  5859.    processing activates the window and its frame.
  5860.  
  5861.    A common problem for an application processing WM_BUTTON1DOWN or similar
  5862.    messages is the failure to activate or set the window focus. If the window
  5863.    processes character messages, the window procedure should call the
  5864.    WinSetFocus function to make sure the window receives the input focus and
  5865.    is activated. If the window does not need the keyboard focus, an
  5866.    application should call the WinSetActiveWindow function.
  5867.  
  5868.    8.3.2.2  Responding to Mouse Movement
  5869.  
  5870.    The system sends mouse-move messages to the window under the mouse pointer
  5871.    or the current mouse-capture window, if any, whenever the mouse pointer
  5872.    moves. This is useful for tracking the mouse pointer and changing its
  5873.    shape based on its location in a window. For example, the mouse pointer
  5874.    changes shape when it passes over the size border of a standard frame
  5875.    window.
  5876.  
  5877.    All standard control windows use mouse-move messages to set the
  5878.    mouse-pointer shape. If your application handles WM_MOUSEMOVE messages in
  5879.    some situations but not others, unused messages should be passed to the
  5880.    WinDefWindowProc function to change the shape of the mouse pointer.
  5881.  
  5882.  8.3.3  Changing the Mouse Capture
  5883.  
  5884.    Mouse messages are usually routed to the window under the mouse pointer.
  5885.    Applications can call the WinSetCapture function to process all mouse
  5886.    messages by a specified window. This is particularly useful when an
  5887.    application is tracking the mouse pointer after a button-down message.
  5888.  
  5889.    For example, in a paint application that uses a button-down message to
  5890.    start a drawing operation, the application tracks the mouse using
  5891.    mouse-move messages until a button-up message is received. If a user drags
  5892.    the mouse pointer outside the window and releases the button, the
  5893.    button-up message will not go to the original window unless the
  5894.    application has called the WinSetCapture function for that window.
  5895.  
  5896.    Some applications must receive a button-up message to match a button-down
  5897.    message. When processing a button-down message, these applications call
  5898.    the WinSetCapture function to set the capture to their own window, and
  5899.    then they call the WinSetCapture function with a NULL window handle to
  5900.    release the mouse capture when processing a matching button-up message.
  5901.  
  5902.  8.3.4  Keyboard Messages
  5903.  
  5904.    All keyboard messages come to a window as WM_CHAR messages. The system
  5905.    reads the keyboard and collects keyboard events in the system queue. It
  5906.    then routes these messages to the appropriate windows depending on the
  5907.    current keyboard-focus window at the time the message is sent. WM_CHAR
  5908.    messages are sent to the window that has the keyboard focus. If no window
  5909.    has the keyboard focus, then WM_CHAR messages are posted to the active
  5910.    frame-window queue. The following are two typical situations where
  5911.    applications receive WM_CHAR messages:
  5912.  
  5913.    ■  An application has a client window or custom control window, each of
  5914.       which can have the keyboard focus. If a window procedure for the client
  5915.       or control window does not process characters, it should pass them to
  5916.       its owner window, which can be accomplished by passing them through to
  5917.       the WinDefWindowProc function. This is especially true for
  5918.       dialog-control items, as this is how the TAB and direction-key control
  5919.       processing is implemented in the user interface.
  5920.  
  5921.    ■  An application window owns a control window that handles some, but not
  5922.       all WM_CHAR messages. This is common in dialog windows. If a control
  5923.       window that has the focus in a dialog window cannot process a WM_CHAR
  5924.       message, it can call the WinDefWindowProc function to send the message
  5925.       to its owner, which is usually a dialog-frame window. The application
  5926.       dialog procedure then receives the WM_CHAR message. This is also the
  5927.       case when an application client window owns a control window.
  5928.  
  5929.  8.3.5  Responding to Keyboard Messages
  5930.  
  5931.    A WM_CHAR message may represent a key-down or key-up transition. It may
  5932.    contain a character code, a virtual-key code, or a scan code. This message
  5933.    also contains information about the state of the SHIFT, CONTROL, and ALT
  5934.    keys.
  5935.  
  5936.    Each time a user presses a key, at least two WM_CHAR messages are
  5937.    generated: one when the key is pressed down, and one when the key is
  5938.    released. If the key is held down long enough to trigger the keyboard
  5939.    repeat, multiple WM_CHAR key-down messages are generated.
  5940.  
  5941.    If the keyboard repeats faster than the application can retrieve the
  5942.    events from the event queue, the system combines repeating character
  5943.    events into one WM_CHAR event representing multiple-key events for the
  5944.    same key. WM_CHAR messages contain a count byte indicating the number of
  5945.    keystrokes represented by the message. Generally, this byte is set to 1,
  5946.    but it should be checked every time a WM_CHAR message is processed to
  5947.    avoid missing keystrokes.
  5948.  
  5949.    A control may ignore the repeat count; for example, it may ignore the
  5950.    count on direction keys. If the system is slow, it may be more aesthetic
  5951.    to have a cursor move slowly than to see it jump 40 characters.
  5952.  
  5953.    Applications decode WM_CHAR messages by examing individual bits in the
  5954.    flag word contained in the low word of the first argument passed with
  5955.    every WM_CHAR message. These bits may be set in various combinations. For
  5956.    example, a WM_CHAR message can have the KC_KEYDOWN, KC_CHAR, KC_SCANCODE,
  5957.    and KC_SHIFT attribute bits all set at the same time.
  5958.  
  5959.    The mp1 and mp2 parameters that are part of the message contain different
  5960.    information depending on the nature of the keyboard event, as follows:
  5961.  
  5962.    ■  The flag word is in low word of mp1.
  5963.  
  5964.    ■  The repeat-key count is in low byte of high word of mp1.
  5965.  
  5966.    ■  The scan code is in high byte of high word of mp1.
  5967.  
  5968.    ■  The character code (ASCII) is in low word of mp2.
  5969.  
  5970.    ■  The virtual-key code is in high word of mp2.
  5971.  
  5972.    An application window procedure should return TRUE if it processes a
  5973.    particular WM_CHAR message, or FALSE otherwise. Typically, applications
  5974.    respond to key-down events and ignore key-up events.
  5975.  
  5976.    The following sections describe the different types of WM_CHAR messages.
  5977.    Generally, decoding these messages consists of layers of conditional
  5978.    statements to eliminate and discriminate the different combinations of
  5979.    attributes that can occur in a keyboard message.
  5980.  
  5981.    8.3.5.1  Key-Down or Key-Up Events
  5982.  
  5983.    Generally, the first attribute that an application checks in a WM_CHAR
  5984.    message is the key-down or key-up events. The distinction between a
  5985.    key-down and a key-up event is found by examining the KC_KEYUP bit of the
  5986.    low word of the first message parameter. If this flag bit is set, then the
  5987.    message is from a key-up event. If the bit is clear, then the message is
  5988.    from a key-down event. The following code fragment shows how to decode a
  5989.    message for this information:
  5990.  
  5991.    case WM_CHAR:
  5992.        fs = SHORT1FROMMP(mp1);
  5993.  
  5994.        if ((fs & KC_KEYUP))
  5995.  
  5996.            /* this is a key-up event   */
  5997.  
  5998.        else
  5999.  
  6000.            /* this is a key-down event */
  6001.  
  6002.        return TRUE;
  6003.  
  6004.    8.3.5.2  Repeat-Count Events
  6005.  
  6006.    Applications should always check the key repeat-count part of a WM_CHAR
  6007.    message to see if the message represents more than one keystroke. The
  6008.    count is greater than one if the keyboard is sending characters to the
  6009.    system queue faster than the application can retrieve them. If the system
  6010.    queue fills up, the system combines consecutive keyboard events for each
  6011.    key in a single WM_CHAR message with the repeat count set to the number of
  6012.    combined events. The repeat count is in the low byte of the high word of
  6013.    the first message parameter.
  6014.  
  6015.    8.3.5.3  Character Codes
  6016.  
  6017.    The most typical use of WM_CHAR messages is to extract a character code
  6018.    from the message and display the character on the screen. When the KC_CHAR
  6019.    bit is set in the WM_CHAR message, the low word of the second message
  6020.    parameter contains a character code based on the current code page.
  6021.    Generally, this value is a glyph code (typically an ASCII code) for the
  6022.    character for the key that was pressed.
  6023.  
  6024.    The following code fragment shows how to respond to a character message:
  6025.  
  6026.        fs = SHORT1FROMMP(mp1);
  6027.  
  6028.        if (fs & KC_CHAR) {
  6029.  
  6030.            /* CHAR is in SHORT1FROMMP(mp2) */
  6031.  
  6032.            /* handle the key character */
  6033.  
  6034.            return(TRUE);
  6035.    }
  6036.  
  6037.    Note that if the KC_CHAR bit is not set, the SHORT1FROMMP(mp2) parameter
  6038.    may still contain useful information. If either the ALT or CTRL key, or
  6039.    both, are down, the KC_CHAR bit will not be set when the user presses
  6040.    another key. For example, pressing the a key when the ALT key is down, the
  6041.    low word of mp2 will contain a 0x0041, the KC_ALT bit will be set, and the
  6042.    KC_CHAR bit will be clear. If the translation does not generate any valid
  6043.    characters, the char field is set to zero.
  6044.  
  6045.    8.3.5.4  Virtual-Key Codes
  6046.  
  6047.    WM_CHAR messages often contain virtual-key codes that correspond to
  6048.    various function keys and direction keys on a typical keyboard. These keys
  6049.    do not correspond to any particular glyph code but are used to initiate
  6050.    operations. When the KC_VIRTUALKEY bit is set in flag word of a WM_CHAR
  6051.    message, the high word of the second message parameter contains a
  6052.    virtual-key code for the key.
  6053.  
  6054.    Note that some keys, such as the ENTER key, have both a valid character
  6055.    code and a virtual-key code. WM_CHAR messages for these keys will contain
  6056.    character codes for newline characters (ASCII 11) and virtual-key codes
  6057.    (VK_ENTER).
  6058.  
  6059.    The following code fragment shows how to decode a WM_CHAR message
  6060.    containing a valid virtual-key code:
  6061.  
  6062.    fs = SHORT1FROMMP(mp1);
  6063.  
  6064.    if (fs & KC_VIRTUALKEY) {
  6065.  
  6066.        /* virtual key is in SHORT2FROMMP(mp2) */
  6067.  
  6068.        switch (SHORT2FROMMP(mp2)) {
  6069.            case VK_TAB:
  6070.  
  6071.                /* handle the TAB key   */
  6072.  
  6073.                return (TRUE);
  6074.  
  6075.            case VK_LEFT:
  6076.  
  6077.                /* handle the LEFT key  */
  6078.  
  6079.                return (TRUE);
  6080.  
  6081.            case VK_UP:
  6082.  
  6083.                /* handle the UP key    */
  6084.  
  6085.                return (TRUE);
  6086.  
  6087.            case VK_RIGHT:
  6088.  
  6089.                /* handle the RIGHT key */
  6090.  
  6091.                return (TRUE);
  6092.  
  6093.            case VK_DOWN:
  6094.  
  6095.                /* handle the DOWN key  */
  6096.  
  6097.                return (TRUE);
  6098.            .
  6099.            .
  6100.            .
  6101.            default:
  6102.                return (FALSE);
  6103.        }
  6104.    }
  6105.  
  6106.    8.3.5.5  Scan Codes
  6107.  
  6108.    A third possible value in a WM_CHAR message is the scan code for the key
  6109.    pressed. The scan code represents the value generated by the keyboard
  6110.    hardware when a key is pressed. An application can use the scan code to
  6111.    identify the physical key pressed, as opposed to the character code
  6112.    represented by the same key. The byte-length value for the scan code is in
  6113.    the high byte of the high word of the first message parameter.
  6114.  
  6115.    All WM_CHAR messages that are generated by the keyboard have valid scan
  6116.    codes. WM_CHAR messages that are posted by other applications may or may
  6117.    not have valid scan codes. The following code fragment shows how to
  6118.    extract a scan code from a WM_CHAR message:
  6119.  
  6120.    fs = SHORT1FROMMP(mp1);
  6121.  
  6122.    if (fs & KC_SCANCODE) {
  6123.  
  6124.        /* scan code is in HIBYTE(HIWORD(mp1)) */
  6125.  
  6126.        return (TRUE);
  6127.    }
  6128.  
  6129.    8.3.5.6  Accelerator-Table Entries
  6130.  
  6131.    The system checks all incoming keyboard messages to see if they match any
  6132.    existing accelerator-table entries, either in the system queue or in the
  6133.    application-message queue. The translation first checks the accelerator
  6134.    table associated with the active frame window, and if no match is found,
  6135.    it uses the accelerator table associated with the message queues. If the
  6136.    keyboard event corresponds to an accelerator-table entry, the WM_CHAR
  6137.    message changes to a WM_COMMAND, WM_SYSCOMMAND, or WM_HELP message,
  6138.    depending on the attributes of the accelerator table. The original WM_CHAR
  6139.    message is not processed by the application.
  6140.  
  6141.    Accelerator tables should be used to implement keyboard shortcuts in
  6142.    applications rather than translating command keystrokes. For example, if
  6143.    an application uses the F2 key to save a document, a keyboard accelerator
  6144.    entry for the F2 virtual key should be created so that it generates a
  6145.    WM_COMMAND message rather than a WM_CHAR message.
  6146.  
  6147.  8.3.6  Changing the Keyboard Focus
  6148.  
  6149.    Applications can change the keyboard focus window by calling the
  6150.    WinSetFocus function for the new focus window.
  6151.  
  6152.    The WinSetFocus function causes the following events to occur:
  6153.  
  6154.    ■  If a window currently has the focus, it receives a WM_SETFOCUS message
  6155.       indicating the loss of focus.
  6156.  
  6157.    ■  If a window currently has the focus, it receives a WM_SETSELECTION
  6158.       message indicating that it should deselect the current selection.
  6159.  
  6160.    ■  If changing focus causes a change in the active window and there is a
  6161.       currently active window, a WM_ACTIVATE message is sent to the active
  6162.       window indicating the loss of active status.
  6163.  
  6164.    ■  A new active window, new focus window, and the active application are
  6165.       established.
  6166.  
  6167.    ■  If the active window is changing, a WM_ACTIVATE message is sent to the
  6168.       new main window indicating the acquisition of active status.
  6169.  
  6170.    ■  The new focus window is sent a WM_SETSELECTION message indicating that
  6171.       it should select the current selection.
  6172.  
  6173.    ■  The new focus window is sent a WM_SETFOCUS message indicating the
  6174.       acquisition of focus.
  6175.  
  6176.    Using the WinQueryActiveWindow or WinQueryFocus function while processing
  6177.    the WinSetFocus function causes the previous active and focus windows to
  6178.    be returned until new active and focus windows are established. In other
  6179.    words, even though WM_SETFOCUS and WM_ACTIVATE messages with the fFocus
  6180.    parameter equal to FALSE may have been sent to the previous windows, those
  6181.    windows are considered active and have the focus until the system
  6182.    establishes new active and focus windows.
  6183.  
  6184.    If the WinSetFocus function is called during the WM_ACTIVATE message
  6185.    processing, a WM_SETFOCUS message with the fFocus parameter equal to FALSE
  6186.    is not sent because no window has the focus.
  6187.  
  6188.  
  6189.  8.4  Summary
  6190.  
  6191.    The following sections describe the functions and messages associated with
  6192.    activation and keyboard/mouse input.
  6193.  
  6194.  8.4.1  Functions
  6195.  
  6196.    The following are the functions associated with activation, keyboard, and
  6197.    mouse input:
  6198.  
  6199.    WinEnablePhysInput  Enables or disables mouse and keyboard input,
  6200.    depending on the fEnable argument. Because this call affects the system
  6201.    queue, it is important that any application that disables input should
  6202.    enable it again as soon as possible.
  6203.  
  6204.    WinFocusChange  A version of the WinSetFocus function that allows more
  6205.    control over messages generated for the old and new focus windows. For
  6206.    example, if an application sets the focus to a new window without
  6207.    deselecting text in the old focus window, this function should be used.
  6208.  
  6209.    WinGetKeyState  Used to determine whether a specified virtual key is up,
  6210.    down, or toggled. A key, such as the CAPSLOCK key, is toggled if it has
  6211.    been pressed an odd number of times. This function can also be used to
  6212.    obtain the state of the mouse buttons that use the VK_BUTTON1, VK_BUTTON2,
  6213.    and VK_BUTTON3 virtual key codes.
  6214.  
  6215.    WinGetPhysKeyState  Returns information about the asynchronous (interrupt
  6216.    level) state of a specified virtual key. This function returns the
  6217.    physical state of the key; it is not synchronized to the processing of
  6218.    input and is not affected by calls to the WinSetKeyboardStateTable
  6219.    function.
  6220.  
  6221.    WinIsPhysInputEnabled  Returns the status, on or off, of mouse and
  6222.    keyboard input.
  6223.  
  6224.    WinQueryCapture  Returns the window handle of the window currently holding
  6225.    the mouse capture. If the fLock argument is TRUE, the window is returned
  6226.    locked and remains locked until it is unlocked by calling the
  6227.    WinLockWindow function with fLock set to FALSE.
  6228.  
  6229.    WinQueryFocus  Returns the keyboard focus window, or NULL if no focus
  6230.    window exists. If the fLock argument is TRUE, the window is returned
  6231.    locked and remains locked until it is unlocked by calling the
  6232.    WinLockWindow function with fLock set to FALSE.
  6233.  
  6234.    WinSetCapture  Sends all mouse messages to a specified window. Specifying
  6235.    a NULL window handle releases the mouse capture so that mouse input is
  6236.    sent to the window beneath the mouse pointer.
  6237.  
  6238.    WinSetFocus  Sets the focus window to the specified window, or to no
  6239.    window if a NULL window is specified for the hwndSetFocus argument. This
  6240.    function can cause activation and deactivation messages to go to the
  6241.    current and new focus windows. The window losing focus receives
  6242.    WM_SETFOCUS(FALSE)and WM_SETSELECTION(FALSE) messages. The frame window
  6243.    losing the focus receives a WM_ACTIVATE(FALSE) message, and by default
  6244.    passes it to its FID_CLIENT window. The frame window receiving the focus
  6245.    receives a WM_ACTIVATE(TRUE) message, which it passes to its FID_CLIENTp
  6246.    window by default. The window receiving the focus receives the
  6247.    WM_SETSELECTION(TRUE), and WM_SETFOCUS(TRUE) messages.
  6248.  
  6249.    WinSetKeyboardStateTable  This function receives or sets the
  6250.    keyboard-state table. To change the state of one virtual key, call the
  6251.    WinSetKeyboardStateTable function with the fSet argument set to FALSE to
  6252.    copy the current state table into a 256-byte table (pointed to by the
  6253.    pKeyStateTable argument). It is then possible to modify a virtual-key
  6254.    entry in the table and call the WinSetKeyboardStateTable function using
  6255.    the same table and fSet argument set to TRUE. This call does not change
  6256.    the physical state of the keyboard. It affects the result of subsequent
  6257.    calls to the WinGetKeyState function, but not the result of calls to the
  6258.    WinGetPhysKeyState function.
  6259.  
  6260.  8.4.2  Messages
  6261.  
  6262.    The following sections describe the messages associated with focus change,
  6263.    activation, the mouse, and the keyboard.
  6264.  
  6265.    8.4.2.1  Focus Change and Activation Messages
  6266.  
  6267.    The following messages are associated with focus change and activation:
  6268.  
  6269.    WM_ACTIVATE  Sent to a window when it is activated or deactivated. This
  6270.    function can be used for tracking the activation state of a client window.
  6271.  
  6272.    WM_FOCUSCHANGE  Sent to a window when the focus is changing. Most
  6273.    applications pass this message to the WinDefWindowProc function, which
  6274.    sends it to the parent frame window. The frame window uses this message to
  6275.    generate appropriate WM_ACTIVATE, WM_SETFOCUS, and WM_SETSELECTION
  6276.    messages for the old and new focus windows.
  6277.  
  6278.    WM_QUERYFOCUSCHAIN  Used to define the focus chain (that is, to keep from
  6279.    hard wiring the focus chain to the parent-window relationship).
  6280.  
  6281.    WM_SETFOCUS  Sent to a window when it is losing or receiving the keyboard
  6282.    focus. A typical response is to display a text-insertion cursor when
  6283.    receiving the focus and hide the cursor when losing the focus.
  6284.  
  6285.    WM_SETSELECTION  Sent to a window when it is receiving or losing the
  6286.    keyboard focus. A typical response is to highlight the currently selected
  6287.    text when receiving the focus and unhighlight the selection when losing
  6288.    the focus.
  6289.  
  6290.    8.4.2.2  Mouse Messages
  6291.  
  6292.    The following messages are associated with mouse events:
  6293.  
  6294.    WM_BUTTON1DBLCLK  Sent to the window under the mouse pointer or the
  6295.    current mouse capture window, if any, when the user clicks the first mouse
  6296.    button twice in a system-specified time limit. The amount of time between
  6297.    clicks necessary to make the action a double-click is a system parameter
  6298.    that a user can set using Control Panel. The application receives a
  6299.    WM_BUTTON1DOWN and WM_BUTTON1UP message for the first click of a
  6300.    double-click.
  6301.  
  6302.    WM_BUTTON1DOWN  Sent to the window under the mouse pointer or the current
  6303.    mouse capture window, if any, when the user presses the first mouse
  6304.    button.
  6305.  
  6306.    WM_BUTTON1UP  Sent to the window under the mouse pointer or the current
  6307.    mouse capture window, if any, when the user releases the first mouse
  6308.    button.
  6309.  
  6310.    WM_BUTTON2DBLCLK  Like WM_BUTTON1DBLCLK but for the second mouse button.
  6311.  
  6312.    WM_BUTTON2DOWN  Like WM_BUTTON1DOWN but for the second mouse button.
  6313.  
  6314.    WM_BUTTON2UP  Like WM_BUTTON1UP but for the second mouse button.
  6315.  
  6316.    WM_BUTTON3DBLCLK  Like WM_BUTTON1DBLCLK but for the third mouse button.
  6317.  
  6318.    WM_BUTTON3DOWN  Like WM_BUTTON1DOWN but for the third mouse button.
  6319.  
  6320.    WM_BUTTON3UP  Like WM_BUTTON1UP but for the third mouse button.
  6321.  
  6322.    WM_HITTEST  This message occurs when an application requests a message by
  6323.    calling the WinPeekMsg or WinGetMsg function. If the message represents a
  6324.    mouse event, it is sent to the the window under the mouse pointer or to
  6325.    the current capture window, if any, to determine whether the message is
  6326.    destined for the window. The default window procedure returns HT_ERROR if
  6327.    the window is disabled; otherwise, it returns HT_NORMAL. The handling of
  6328.    this message determines whether a disabled window can process mouse
  6329.    clicks.
  6330.  
  6331.    WM_MOUSEMOVE  Sent to the window under the mouse pointer or the window
  6332.    with the mouse capture, if any, when the mouse pointer moves. The system
  6333.    generates this message only as often as the application requests new
  6334.    messages. The distance the mouse pointer moves before this message is
  6335.    posted depends on how fast the application executes its message loops.
  6336.  
  6337.    8.4.2.3  Keyboard Message
  6338.  
  6339.    The following message is associated with keyboard events:
  6340.  
  6341.    WM_CHAR  Posted to the current focus window whenever there is a keyboard
  6342.    event. The message contains a flag word that indicates the composition of
  6343.    the message. The following list of flag values can be used to test the
  6344.    flag word to determine the nature of a message:
  6345.  
  6346. ╓┌─┌─────────────────┌───────────────────────────────────────────────────────╖
  6347.    Flag              Meaning
  6348.    ──────────────────────────────────────────────────────────────────────────
  6349.    KC_ALT            The ALT key was down when this message was generated.
  6350.  
  6351.    KC_CHAR           The message contains a valid character code for a key.
  6352.                      Typically, this code is an ASCII code.
  6353.  
  6354.    KC_COMPOSITE      In combination with the KC_CHAR flag this flag bit means
  6355.                      that the character code is a combination of the key that
  6356.                      was pressed and the previous dead key. This is used to
  6357.                      create characters with diacritical marks.
  6358.  
  6359.    KC_CTRL           The CONTROL key was down when this message was
  6360.                      generated.
  6361.  
  6362.    KC_DEADKEY        In combination with a KC_CHAR flag this flag bit means
  6363.                      that the character code represents a dead-key glyph
  6364.                      (such as an accent). An application displays the
  6365.    Flag              Meaning
  6366.    ──────────────────────────────────────────────────────────────────────────
  6367.                     (such as an accent). An application displays the
  6368.                      dead-key glyph and does not advance the cursor.
  6369.                      Typically, the next WM_CHAR message is a KC_COMPOSITE
  6370.                      message containing the character associated with the
  6371.                      dead-key character.
  6372.  
  6373.    KC_INVALIDCHAR    The current character is not valid for the current
  6374.                      translation tables.
  6375.  
  6376.    KC_INVALIDCOMP    The current character is not valid in combination with
  6377.                      the previous dead key.
  6378.  
  6379.    KC_KEYUP          The message was generated when the user released the
  6380.                      key. If this flag bit is clear, the message was
  6381.                      generated when the user pressed the key. Use this bit to
  6382.                      determine key-down and key-up events.
  6383.  
  6384.    KC_LONEKEY        No other key was pressed while this key was down.
  6385.                      Typically used to indicate that the user pressed the ALT
  6386.    Flag              Meaning
  6387.    ──────────────────────────────────────────────────────────────────────────
  6388.                     Typically used to indicate that the user pressed the ALT
  6389.                      key by itself.
  6390.  
  6391.    KC_PREVDOWN       In combination with a KC_VIRTUALKEY flag this flag bit
  6392.                      means that the virtual key was previously down. If this
  6393.                      flag bit is clear, the virtual key was previously up.
  6394.  
  6395.    KC_SCANCODE       The message contains a valid raw scan code generated by
  6396.                      the keyboard when the key is pressed. The scan code is
  6397.                      used by the system to identify the character code in the
  6398.                      current code page, therefore, most applications do not
  6399.                      need the scan code unless they cannot identify the key
  6400.                      that was pressed. WM_CHAR messages generated by actual
  6401.                      user keyboard input generally have a valid scan code,
  6402.                      but WM_CHAR messages posted to the queue by other
  6403.                      applications might not contain a scan code.
  6404.  
  6405.    KC_SHIFT          The SHIFT key was down when this message was generated.
  6406.  
  6407.    Flag              Meaning
  6408.    ──────────────────────────────────────────────────────────────────────────
  6409. 
  6410.    KC_TOGGLE         The KC_TOGGLE bit toggles "on" and "off" every time the
  6411.                      key is pressed. For example, it is set "on" every odd
  6412.                      number of presses and "off" every even number of
  6413.                      presses. This is important for keys like NUMLOCK, which
  6414.                      have an on or off state.
  6415.  
  6416.    KC_VIRTUALKEY     The message contains a valid virtual-key code for a key.
  6417.                      Virtual keys typically correspond to function keys.
  6418.    ──────────────────────────────────────────────────────────────────────────
  6419.  
  6420.  
  6421.  
  6422.  
  6423.  
  6424.  ────────────────────────────────────────────────────────────────────────────
  6425.  Chapter 9  Frame Windows
  6426.  
  6427.         9.1     Introduction
  6428.         9.2     About Frame Windows
  6429.             9.2.1     Main Window
  6430.             9.2.2     Frame Controls
  6431.             9.2.3     Client Window
  6432.             9.2.4     Sizing Border and Minimize and Maximize Buttons
  6433.             9.2.5     Frame-Control Identifiers
  6434.             9.2.6     Frame-Window Creation
  6435.             9.2.7     Frame-Control Flags
  6436.             9.2.8     Frame-Window Styles
  6437.             9.2.9     Frame-Window Resources
  6438.             9.2.10    Frame-Window Class Data
  6439.             9.2.11    Frame-Window Data
  6440.             9.2.12    Frame-Window Operation
  6441.             9.2.13    Nonstandard Frame Windows
  6442.             9.2.14    Default Frame-Window Behavior
  6443.         9.3     Using Frame Windows
  6444.             9.3.1     Creating a Main Window
  6445.             9.3.2     Retrieving Frame Handles
  6446.         9.4     Summary
  6447.             9.4.1     Functions
  6448.             9.4.2     Messages
  6449.  
  6450.  9.1  Introduction
  6451.  
  6452.    This chapter describes creating and using frame windows in Presentation
  6453.    Manager applications. You should also be familiar with the following
  6454.    topics:
  6455.  
  6456.    ■  Standard user-interface guidelines
  6457.  
  6458.    ■  Windows
  6459.  
  6460.    ■  Window relationships
  6461.  
  6462.    ■  Control windows
  6463.  
  6464.    ■  Messages and message queues
  6465.  
  6466.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  6467.  
  6468.  
  6469.  9.2  About Frame Windows
  6470.  
  6471.    A frame window is the basic window used by most Presentation Manager
  6472.    applications. A frame window provides a base for the application's main
  6473.    window, dialog windows, and message boxes. Although applications rarely
  6474.    use frame windows alone, applications nearly always start with a frame
  6475.    window to create a composite window that consists of the frame window,
  6476.    several frame controls, and a client window. The frame window coordinates
  6477.    the actions of the other windows, allowing the composite window to act as
  6478.    if it were a single unit.
  6479.  
  6480.    A frame window is a window of the preregistered, public-window class
  6481.    WC_FRAME. The frame-window class, like the preregistered control classes,
  6482.    defines the appearance and behavior of the frame window. The appearance
  6483.    and behavior of a frame window are designed to match the standard
  6484.    user-interface guidelines for MS OS/2 Presentation Manager applications,
  6485.    including applications that use the multiple-document interface. This
  6486.    means that applications that use frame windows have a quick and efficient
  6487.    way to create the "standard" windows recommended by the user-interface
  6488.    guidelines.
  6489.  
  6490.    Although frame windows are an important part of dialog windows, dialog
  6491.    windows are not described in this chapter. For a complete description of
  6492.    dialog windows, see Chapter 19, "Dialog Windows."
  6493.  
  6494.  9.2.1  Main Window
  6495.  
  6496.    An application's main window is typically made up of a frame window with
  6497.    control windows such as a title bar, System menu, menu bar, and scroll
  6498.    bar. The main window also typically includes a client window.
  6499.  
  6500.    The frame window is sometimes under other windows. Although it is not
  6501.    visible, it provides the standard services the user expects from the
  6502.    window──for example, moving, sizing, minimizing, and maximizing. The frame
  6503.    window receives input from the control windows (called frame controls). It
  6504.    sends messages to the frame controls and to the client window to tell what
  6505.    action is needed next.
  6506.  
  6507.  9.2.2  Frame Controls
  6508.  
  6509.    When an application creates a frame window, it can specify that one or
  6510.    more control windows be created as child windows of the frame window. A
  6511.    frame window can have a title-bar, System-menu, menu, and scroll-bar
  6512.    controls. Each is a unique window created from a preregistered
  6513.    control-window class.
  6514.  
  6515.    These frame controls provide a particular aspect of the user interface for
  6516.    a "standard" application window. A title bar appears at the top of the
  6517.    window and displays the application and/or window title. A System menu
  6518.    appears at the left end of the title bar. It contains the commands used to
  6519.    move, size, and close the window. A menu appears below the title bar and
  6520.    contains the commands the user can choose to carry out work with the
  6521.    application. The scroll bars appear at the right edge and bottom of the
  6522.    frame window. These let the user scroll the contents of the client window.
  6523.  
  6524.    Although all frame controls are optional, most, if not all, application
  6525.    main windows use the title-bar and System-menu controls. These provide the
  6526.    minimum functionality for a window that meets the user-interface
  6527.    guidelines.
  6528.  
  6529.    Each frame control is a child window of the frame window. Each frame
  6530.    control is owned by the frame window. That is, the frame window is the
  6531.    owner as well as the parent window for each frame control. Because the
  6532.    main role of a frame window is to coordinate the activities of other
  6533.    windows, ownership of the frame controls is very important. Ownership
  6534.    gives the frame controls a way to send notification messages to the frame
  6535.    window. Notification messages tell the frame window what the user does
  6536.    with the frame control.
  6537.  
  6538.    For example, a user can move a window by clicking the title bar and then
  6539.    dragging the window to a new position using a mouse. The title bar
  6540.    responds to the click by sending a message to the frame window notifying
  6541.    it of the user's request to move the window. The frame window can then
  6542.    track the mouse motion and move the frame window and all its child windows
  6543.    to the new position.
  6544.  
  6545.    An application can add frame controls to a frame window by specifying the
  6546.    FCF_TITLEBAR, FCF_SYSMENU, FCF_MENU, FCF_VERTSCROLL, and FCF_HORZSCROLL
  6547.    styles. Frame controls are described in separate chapters. For a general
  6548.    discussion of controls, see Chapter 10, "Control Windows."
  6549.  
  6550.  9.2.3  Client Window
  6551.  
  6552.    Every main window has a client window. The client window is the part of
  6553.    the main window where the application displays output and receives mouse
  6554.    and keyboard input. What an application displays in the client window, how
  6555.    it displays it, and how it interprets input to the window is controlled
  6556.    entirely by the application.
  6557.  
  6558.    An application creates the client window when it creates the frame window.
  6559.    The client window is specific to the application; it is nearly always
  6560.    created by using a private window class (a class registered by the
  6561.    application). Like frame controls, the client window is a child window and
  6562.    an owned window of the frame window. This means, for example, that the
  6563.    client window moves when the frame window moves, that the client window is
  6564.    clipped to the frame-window size, and that the client window is destroyed
  6565.    when the frame window is destroyed.
  6566.  
  6567.    The relationship between the frame window and the client window allows the
  6568.    frame window to pass messages from other frame controls to the client
  6569.    window and vice versa. For example, a scroll-bar control notifies the
  6570.    frame window when the user requests scrolling; the frame window then sends
  6571.    a message to the client window. The client window requests that the frame
  6572.    window change the window title; the frame window sends a message to the
  6573.    title-bar control.
  6574.  
  6575.  9.2.4  Sizing Border and Minimize and Maximize Buttons
  6576.  
  6577.    Although the sizing border and minimize and maximize buttons are not frame
  6578.    controls, they act very much like controls for the frame window. However,
  6579.    they are different than frame controls because the frame window draws and
  6580.    maintains these items; frame controls draw and maintain themselves.
  6581.  
  6582.    The sizing border, enclosing the frame window, lets the user change the
  6583.    size of the window by using a mouse. The minimize button, at the right end
  6584.    of the title bar, lets the user shrink the frame window to an icon. The
  6585.    maximize button, next to the minimize button, lets the user enlarge the
  6586.    window so that it fills the screen. An application can add these items to
  6587.    a frame window by using the FCF_SIZEBORDER, FCF_MAXBUTTON, and
  6588.    FCF_MINBUTTON (or the FCF_MINMAX) styles. (The FCF_MINMAX style adds both
  6589.    a minimize and a maximize button.)
  6590.  
  6591.  9.2.5  Frame-Control Identifiers
  6592.  
  6593.    A frame window uses a set of standard constants to identify the frame
  6594.    controls and the client window. The frame-control identifiers all begin
  6595.    with the prefix FID_ and can be used in functions such as WinWindowFromID
  6596.    to uniquely identify a given control or the client window. The frame
  6597.    controls also use these identifiers in notification messages they send to
  6598.    the frame window. The following are the frame-control identifiers:
  6599.  
  6600.    ■  FID_CLIENT
  6601.  
  6602.    ■  FID_HORZSCROLL
  6603.  
  6604.    ■  FID_MENU
  6605.  
  6606.    ■  FID_MINMAX
  6607.  
  6608.    ■  FID_SYSMENU
  6609.  
  6610.    ■  FID_TITLEBAR
  6611.  
  6612.    ■  FID_VERTSCROLL
  6613.  
  6614.  9.2.6  Frame-Window Creation
  6615.  
  6616.    An application can create a frame window by using the WinCreateWindow
  6617.    function and specifying the WC_FRAME window class. This creates the frame
  6618.    window but does not add the frame controls and client window that
  6619.    accompany most frame windows in applications. To add these additional
  6620.    windows, the application can continue to call the WinCreateWindow
  6621.    function, specifying the original frame window as the parent and owner
  6622.    window for each frame control and for the client window. Or the
  6623.    application can call WinCreateStdWindow, which automatically carries out
  6624.    the individual calls to WinCreateWindow.
  6625.  
  6626.    Frame windows are also used to create dialog windows. In this case, the
  6627.    frame window contains control windows but no client window. An application
  6628.    can create a dialog window by using the WinLoadDlg or WinCreateDlg
  6629.    function. These functions require an appropriate dialog template from the
  6630.    application's resources on disk or from memory. The dialog template
  6631.    specifies the styles and dimensions for the frame window and the control
  6632.    windows that make up the dialog window.
  6633.  
  6634.  9.2.7  Frame-Control Flags
  6635.  
  6636.    An application can specify both the frame-window style and the frame
  6637.    controls for a frame window by using the frame-control flags with the
  6638.    WinCreateStdWindow function. The following are the frame-control flags:
  6639.  
  6640. ╓┌─┌─────────────────────────┌───────────────────────────────────────────────╖
  6641.    Flag                      Description
  6642.    ──────────────────────────────────────────────────────────────────────────
  6643.    FCF_TITLEBAR              Creates a title bar.
  6644.  
  6645.    FCF_SYSMENU               Creates a System menu.
  6646.  
  6647.    FCF_MENU                  Creates a menu. This flag loads a menu from the
  6648.                              application's resources on disk.
  6649.  
  6650.    FCF_MINBUTTON             Creates a minimize button.
  6651.  
  6652.    FCF_MAXBUTTON             Creates a maximize button.
  6653.  
  6654.    FCF_MINMAX                Creates both a minimize and a maximize button.
  6655.  
  6656.    FCF_VERTSCROLL            Creates a vertical scroll bar.
  6657.  
  6658.    FCF_HORZSCROLL            Creates a horizontal scroll bar.
  6659.    Flag                      Description
  6660.    ──────────────────────────────────────────────────────────────────────────
  6661.   FCF_HORZSCROLL            Creates a horizontal scroll bar.
  6662.  
  6663.    FCF_SIZEBORDER            Creates a sizing border. A sizing border lets
  6664.                              the user adjust the size of the window.
  6665.  
  6666.    FCF_BORDER                Creates a border. Use this flag for windows that
  6667.                              must not change size.
  6668.  
  6669.    FCF_DLGBORDER             Creates a dialog border. Use this flag for
  6670.                              dialog windows.
  6671.  
  6672.    FCF_SHELLPOSITION         Directs the frame window to request an initial
  6673.                              size and position from Start Programs.
  6674.  
  6675.    FCF_TASKLIST              Adds the window title to the switch list of Task
  6676.                              Manager. If the process creating a frame window
  6677.                              already has an entry in the switch list, the
  6678.                              window title is appended to the previous entry.
  6679.  
  6680.    Flag                      Description
  6681.    ──────────────────────────────────────────────────────────────────────────
  6682. 
  6683.    FCF_NOBYTEALIGN           Enables the frame window to be moved to any
  6684.                              position on the screen. If this flag is not
  6685.                              given, a frame window always adjusts its
  6686.                              position so that the x-coordinate of its left
  6687.                              edge is a multiple of 8. Using this flag affects
  6688.                              how quickly the system can draw the frame
  6689.                              window.
  6690.  
  6691.    FCF_NOMOVEWITHOWNER       Enables the frame window to maintain its
  6692.                              position even if its owner window moves. This
  6693.                              applies only to frame windows that are not child
  6694.                              windows of the owner. If this flag is not given,
  6695.                              the frame window moves when the owner window
  6696.                              moves.
  6697.  
  6698.    FCF_ICON                  Loads an icon from the application's resources
  6699.                              on disk. The icon is used whenever the frame
  6700.                              window is minimized.
  6701.    Flag                      Description
  6702.    ──────────────────────────────────────────────────────────────────────────
  6703.                             window is minimized.
  6704.  
  6705.    FCF_ACCELTABLE            Loads an accelerator table from the
  6706.                              application's resources on disk. The accelerator
  6707.                              table is used for all keyboard input to the
  6708.                              frame window.
  6709.  
  6710.    FCF_SYSMODAL              Creates a system-modal frame window. Setting
  6711.                              this flag is the same as using the
  6712.                              WinSetSysModalWindow function.
  6713.  
  6714.    FCF_SCREENALIGN           Aligns the initial position of the frame window
  6715.                              relative to the screen origin instead of to the
  6716.                              parent window.
  6717.  
  6718.    FCF_MOUSEALIGN            Aligns the initial position of the frame window
  6719.                              relative to the mouse position instead of to the
  6720.                              parent window. An application can use this flag
  6721.                              to position the default button in a dialog
  6722.    Flag                      Description
  6723.    ──────────────────────────────────────────────────────────────────────────
  6724.                             to position the default button in a dialog
  6725.                              window under the mouse pointer.
  6726.  
  6727.    FCF_STANDARD              Combines the FCF_TITLEBAR FCF_SYSMENU, FCF_MENU,
  6728.                              FCF_SIZEBORDER, FCF_MINMAX, FCF_ICON,
  6729.                              FCF_ACCELTABLE, FCF_SHELLPOSITION, and
  6730.                              FCF_TASKLIST styles.
  6731.    ──────────────────────────────────────────────────────────────────────────
  6732.  
  6733.  
  6734.    When the WinCreateStdWindow function is called without any of these flags
  6735.    set, the standard window is created invisible, behind all its sibling
  6736.    windows, in Z order, with a width and height of zero, positioned at the
  6737.    lower-left of its parent window. When WinCreateStdWindow returns, you can
  6738.    call WinSetWindowPos to change the window's size, x- and y-positions,
  6739.    Z-order position, and visibility.
  6740.  
  6741.    When WinCreateStdWindow is called with the FCF_SHELLPOSITION frame-control
  6742.    flag, the window is created in front of its sibling windows, in Z order,
  6743.    with a standard size and x- and y-positions obtained from the shell
  6744.    program.
  6745.  
  6746.  9.2.8  Frame-Window Styles
  6747.  
  6748.    The frame-window class, like other preregistered window classes, provides
  6749.    many class-specific window styles that applications can use to adapt the
  6750.    appearance and behavior of a frame window. The frame-window styles,
  6751.    specified as constants starting with the FS_ prefix, can be combined with
  6752.    the standard window styles when creating a frame window. The following are
  6753.    the frame-window styles:
  6754.  
  6755. ╓┌─┌──────────────────────┌──────────────────────────────────────────────────╖
  6756.    Style                  Description
  6757.    ──────────────────────────────────────────────────────────────────────────
  6758.    FS_ACCELTABLE          Loads an accelerator table from the application's
  6759.                           resources on disk. The frame window uses the
  6760.                           accelerator table to translate keyboard input.
  6761.  
  6762.    FS_BORDER              Creates a single-line border. Use this style when
  6763.                           the window must not change size.
  6764.    Style                  Description
  6765.    ──────────────────────────────────────────────────────────────────────────
  6766.                          the window must not change size.
  6767.  
  6768.    FS_SIZEBORDER          Creates a sizing border. Use this style to let the
  6769.                           user adjust the size of the window.
  6770.  
  6771.    FS_DLGBORDER           Creates a double-line dialog border. Use this style
  6772.                           for dialog windows.
  6773.  
  6774.    FS_ICON                Loads an icon from the application's resources on
  6775.                           disk. The frame window draws the icon when the
  6776.                           window is minimized.
  6777.  
  6778.    FS_SCREENALIGN         Aligns the initial position of the frame window
  6779.                           relative to the screen origin instead of to the
  6780.                           parent window.
  6781.  
  6782.    FS_MOUSEALIGN          Aligns the initial position of the frame window
  6783.                           relative to the mouse position instead of to the
  6784.                           parent window. An application can use this style to
  6785.    Style                  Description
  6786.    ──────────────────────────────────────────────────────────────────────────
  6787.                          parent window. An application can use this style to
  6788.                           position the default button in a dialog window
  6789.                           under the mouse pointer.
  6790.  
  6791.    FS_NOBYTEALIGN         Enables the frame window to be moved to any
  6792.                           position on the screen. If this style is not given,
  6793.                           a frame window always adjusts its position so that
  6794.                           the x-coordinate of its left edge is a multiple of
  6795.                           8. Using this style affects how quickly the system
  6796.                           can draw the frame window.
  6797.  
  6798.    FS_NOMOVEWITHOWNER     Enables the frame window to keep its position even
  6799.                           if its owner window moves. This applies only to
  6800.                           frame windows that are not child windows of the
  6801.                           owner window. If this style is not given, the frame
  6802.                           window moves when the owner window moves.
  6803.  
  6804.    FS_SHELLPOSITION       Directs the frame window to request an initial size
  6805.                           and position from Start Programs.
  6806.    Style                  Description
  6807.    ──────────────────────────────────────────────────────────────────────────
  6808.                          and position from Start Programs.
  6809.  
  6810.    FS_SYSMODAL            Creates a system-modal window. Using this style is
  6811.                           the same as calling the WinSetSysModalWindow
  6812.                           function for the frame window.
  6813.  
  6814.    FS_TASKLIST            Adds the window title to the switch list of Task
  6815.                           Manager. If the process creating a frame window
  6816.                           already has an entry in the switch list, the window
  6817.                           title is appended to the previous entry.
  6818.  
  6819.    FS_STANDARD            Combines the FS_ICON, FS_ACCELTABLE,
  6820.                           FS_SHELLPOSITION, and FS_TASKLIST styles.
  6821.    ──────────────────────────────────────────────────────────────────────────
  6822.  
  6823.  
  6824.    The FS_ window styles are rarely used. Although the constants are useful
  6825.    for creating a frame window without also creating frame controls, most
  6826.    applications use frame controls and therefore use the JFCF_ constants to
  6827.    specify the frame-window styles. For each FS_ constant there is an
  6828.    equivalent FCF_ constant For more information, see the following section.
  6829.  
  6830.  9.2.9  Frame-Window Resources
  6831.  
  6832.    If the FCF_MENU, FCF_ICON, FCF_ACCELTABLE, FCF_STANDARD, FS_ICON,
  6833.    FS_ACCELTABLE, or FS_STANDARD style is specified when creating the frame
  6834.    window, the application must provide the appropriate resources to support
  6835.    these styles. Depending on the style, a frame window may attempt to load
  6836.    one or more resources from the application's resources on disk.
  6837.  
  6838.    You can use Resource Compiler to add icon and accelerator-table resources
  6839.    to the application's executable file. Each resource must have a resource
  6840.    identifier that matches the resource identifier specified in the
  6841.    FRAMECDATA structure passed to the WinCreateWindow function or in the
  6842.    idResources parameter of the WinCreateStdWindow function.
  6843.  
  6844.    The following list gives the frame-control flags and styles that require
  6845.    resources and describes what the resource should be:
  6846.  
  6847.    Style               Resource
  6848.    ──────────────────────────────────────────────────────────────────────────
  6849.    FCF_ICON            Requires an icon resource. The frame window draws the
  6850.    FS_ICON             icon whenever the window is minimized.
  6851.  
  6852.    FCF_MENU            Requires a menu-template resource. A frame window uses
  6853.                        the menu template to create a menu containing the
  6854.                        commands and menus specified by the resource.
  6855.  
  6856.    FCF_ACCELTABLE      Requires an accelerator-table resource. The frame
  6857.    FS_ACCELTABLE       window uses the accelerator table to translate WM_CHAR
  6858.                        messages to WM_COMMAND, WM_SYSCOMMAND, or WM_HELP
  6859.                        messages.
  6860.  
  6861.    FCF_STANDARD        Requires a menu template, an accelerator table, and an
  6862.    FS_STANDARD         icon resource.
  6863.    ──────────────────────────────────────────────────────────────────────────
  6864.  
  6865.    The application must specify the module containing the resources
  6866.    (typically the application's executable file) when it creates the frame
  6867.    window. The resources must have the same resource identifier and the
  6868.    application must supply this identifier when creating the window.
  6869.  
  6870.  9.2.10  Frame-Window Class Data
  6871.  
  6872.    An application can specify class-specific data for a frame window by
  6873.    passing a FRAMECDATA structure to the WinCreateWindow function. The
  6874.    class-specific data contains the frame-control flags, resource-module
  6875.    handle, and resource identifier to be used when creating the frame window.
  6876.  
  6877.    Frame-control flags specify what controls to create for the frame window
  6878.    and what window styles to apply to the frame window. The frame-control
  6879.    flags are the same flags (FCF_) used in the WinCreateStdWindow function.
  6880.    The resource-module handle and the resource identifier specify where to
  6881.    find resources for the frame window.
  6882.  
  6883.    Supplying class-specific data with WinCreateWindow is similar to using the
  6884.    WinCreateStdWindow function without creating a client window.
  6885.  
  6886.  9.2.11  Frame-Window Data
  6887.  
  6888.    Frame-window data specifies the state of the frame window at a given time.
  6889.    An application can retrieve the frame-window data by calling the
  6890.    WinQueryWindowUShort function. A frame window has the following state
  6891.    flags:
  6892.  
  6893. ╓┌─┌───────────────────────┌─────────────────────────────────────────────────╖
  6894.    Flag                    Description
  6895.    ──────────────────────────────────────────────────────────────────────────
  6896.    FF_ACTIVE               The frame window is activated.
  6897.  
  6898.    FF_DLGDISMISSED         A frame window that is a dialog window has been
  6899.                            dismissed by a call to the WinDismissDlg function.
  6900.  
  6901.    FF_FLASHHILITE          The frame window is flashing and its flash state
  6902.                            is TRUE.
  6903.  
  6904.    FF_FLASHWINDOW          The frame window flashes as the result of a call
  6905.                            to the WinFlashWindow function or a WM_FLASHWINDOW
  6906.                            message.
  6907.  
  6908.    FF_NOACTIVATESWP        The system should do no Z ordering on this frame
  6909.                            window.
  6910.  
  6911.    Flag                    Description
  6912.    ──────────────────────────────────────────────────────────────────────────
  6913. 
  6914.    FF_OWNERHIDDEN          The frame window's owner window is hidden or
  6915.                            minimized so the frame window is also hidden.
  6916.  
  6917.    FF_OWNERDISABLED        For a frame window that is a dialog window, this
  6918.                            flag indicates whether the owner window was
  6919.                            enabled or disabled when the dialog window was
  6920.                            loaded.
  6921.  
  6922.    FF_SELECTED             The frame window has selection turned on.
  6923.  
  6924.    FI_FRAME                The window is a frame window.
  6925.  
  6926.    FI_OWNERHIDE            The frame window should be hidden or shown as a
  6927.                            result of its owner window being hidden, shown,
  6928.                            minimized, or maximized.
  6929.  
  6930.    FI_ACTIVATEOK           The window can be activated.
  6931.  
  6932.    Flag                    Description
  6933.    ──────────────────────────────────────────────────────────────────────────
  6934. 
  6935.    FI_NOMOVEWITHOWNER      The window should move when its owner window
  6936.                            moves.
  6937.    ──────────────────────────────────────────────────────────────────────────
  6938.  
  6939.  
  6940.  9.2.12  Frame-Window Operation
  6941.  
  6942.    The frame window maintains the size, position, and visibility of itself,
  6943.    its frame controls, and its client window. It responds to user requests to
  6944.    move, size, minimize, maximize, and redraw the window. It also responds to
  6945.    requests to close (destroy) the window and to change the focus and
  6946.    activation.
  6947.  
  6948.    When moving or sizing a frame window, all owned windows maintain their
  6949.    position relative to owner window's upper-left corner.
  6950.  
  6951.    Whenever the frame window redraws itself (for example, after moving or
  6952.    sizing), it draws the frame controls first, then lets the application draw
  6953.    the client window. This order ensures that the rapidly drawn frame
  6954.    controls are drawn before the relatively slowly drawn client window.
  6955.  
  6956.    The order in which the frame controls are drawn depends on the Z-order
  6957.    position of the controls. Because the frame controls are sibling windows,
  6958.    the Z-order position of one is relative to the others. The following list
  6959.    specifies the Z-order position of the frame controls (from top to bottom):
  6960.  
  6961.          FID_SYSMENU
  6962.          FID_TITLEBAR
  6963.          FID_MENU
  6964.          FID_VERTSCROLL
  6965.          FID_HORZSCROLL
  6966.          FID_CLIENT
  6967.  
  6968.    Although an application can change the Z-order position of any window,
  6969.    changing the relative positions of frame controls is not recommended.
  6970.  
  6971.    When a frame window receives a request to minimize the window, it locates
  6972.    an available icon space in the lower part of the screen, hides all frame
  6973.    controls and the client window, and draws its icon. If the frame window
  6974.    has no icon (that is, the window was created without the FCF_ICON style),
  6975.    the frame window hides all but the client window. The client window must
  6976.    then draw the minimized window. An application can determine the size of a
  6977.    minimized frame window by calling WinQueryWindowUShort and specifying the
  6978.    QWS_XMINIMIZE and QWS_YMINIMIZE indexes.
  6979.  
  6980.    When a frame window is maximized, it grows to the size of its parent
  6981.    window, plus an additional amount on each of its four sides equal to the
  6982.    width of its sizing border. Because a window is always clipped to its
  6983.    parent window, a maximized standard frame window does not show its sizing
  6984.    border.
  6985.  
  6986.    Frame controls owned by a frame window or windows owned by child windows
  6987.    of a frame window are automatically destroyed when the frame window
  6988.    processes the WM_DESTROY message.
  6989.  
  6990.  9.2.13  Nonstandard Frame Windows
  6991.  
  6992.    Although most applications use frame windows to create main window and
  6993.    dialog windows, they are not limited to frame windows. Applications can
  6994.    create nonstandard frame windows and still use the standard frame
  6995.    controls, such as the title bar and System menu, within the nonstandard
  6996.    windows. One reason for creating nonstandard frame windows is to expand
  6997.    the capability of the frame window to support special features such as the
  6998.    multiple-document interface.
  6999.  
  7000.    There are two ways to create nonstandard frame windows: subclass a frame
  7001.    window or create a private frame-window class. An application that
  7002.    subclasses a frame window can intercept the messages sent to the window
  7003.    and process them in new ways. An application that creates private
  7004.    frame-window classes essentially rewrites the frame-window procedure. In
  7005.    either case, the application gains much more control over the placement of
  7006.    frame controls in the frame window by creating nonstandard frame windows.
  7007.  
  7008.    The messages WM_FORMATFRAME, WM_UPDATEFRAME, and WM_CALCVALIDRECTS control
  7009.    the arrangement of frame controls for applications that subclass. By
  7010.    intercepting these messages, an application can rearrange the placement of
  7011.    frame controls in a frame window.
  7012.  
  7013.    For applications that create private frame-window classes, the
  7014.    WinCreateFrameControls, WinCalcFrameRect, and WinFormatFrame functions
  7015.    provide much the same capability as frame windows to maintain the size and
  7016.    position of frame controls.
  7017.  
  7018.  9.2.14  Default Frame-Window Behavior
  7019.  
  7020.    This section describes all the messages specifically handled by the
  7021.    predefined frame-window class.
  7022.  
  7023. ╓┌─┌─────────────────────────┌───────────────────────────────────────────────╖
  7024.    Message                   Description
  7025.    ──────────────────────────────────────────────────────────────────────────
  7026.    WM_ACTIVATE               Sent to a title bar or sizing border so its
  7027.                              highlight state matches the frame window's
  7028.                              activation state.
  7029.  
  7030.    WM_BUTTON1DOWN            If the frame window is minimized, captures the
  7031.                              mouse. If the window is not minimized, activates
  7032.                              the window.
  7033.  
  7034.    WM_BUTTON2DOWN            Activates the frame window.
  7035.  
  7036.    WM_BUTTON3DOWN            Activates the frame window.
  7037.    Message                   Description
  7038.    ──────────────────────────────────────────────────────────────────────────
  7039.   WM_BUTTON3DOWN            Activates the frame window.
  7040.  
  7041.    WM_BUTTON1UP              Processes messages from minimized window frames.
  7042.  
  7043.    WM_BUTTON2UP              Not processed.
  7044.  
  7045.    WM_BUTTON3UP              Not processed.
  7046.  
  7047.    WM_BUTTON1DBLCLK          If the frame window is minimized, posts a
  7048.                              WM_SYSCOMMAND message to itself. Otherwise,
  7049.                              activates the frame window and any control
  7050.                              clicked.
  7051.  
  7052.    WM_BUTTON2DBLCLK          Not processed.
  7053.  
  7054.    WM_BUTTON3DBLCLK          Not processed.
  7055.  
  7056.    WM_HITTEST                If the frame control is minimized, returns
  7057.                              HT_ERROR if the window is disabled; otherwise,
  7058.    Message                   Description
  7059.    ──────────────────────────────────────────────────────────────────────────
  7060.                             HT_ERROR if the window is disabled; otherwise,
  7061.                              returns TF_MOVE.
  7062.  
  7063.    WM_CALCVALIDRECTS         If there is no client window or the client
  7064.                              window has the style CS_SIZEREDRAW, returns
  7065.                              CVR_REDRAW to invalidate the entire window.
  7066.  
  7067.    WM_CLOSE                  If there is a client window, passes this message
  7068.                              to it; otherwise, this message returns
  7069.                              WinDefWindowProc.
  7070.  
  7071.    WM_CONTROLHEAP            Attempts to allocate a heap for the frame
  7072.                              controls. Returns a handle if successful;
  7073.                              otherwise, returns NULL.
  7074.  
  7075.    WM_CREATE                 Creates specified frame controls by calling
  7076.                              WinCreateFrameControls. Also creates any
  7077.                              accelerator tables, loads icons, and adds itself
  7078.                              to the switch list in Task Manager. These
  7079.    Message                   Description
  7080.    ──────────────────────────────────────────────────────────────────────────
  7081.                             to the switch list in Task Manager. These
  7082.                              actions depend on the frame window and
  7083.                              frame-control styles specified for the window.
  7084.  
  7085.    WM_DESTROY                If the focus is held by a child window of the
  7086.                              frame window, sets the focus to the frame
  7087.                              window's parent window. Destroys any windows
  7088.                              owned by the frame window. Destroys any child
  7089.                              windows. Frees any control heaps. Destroys any
  7090.                              icon created with the FS_ICON style. Destroys
  7091.                              any accelerator table created with the
  7092.                              FS_ACCELTABLE style.
  7093.  
  7094.    WM_ENABLE                 Returns WinDefWindowProc.
  7095.  
  7096.    WM_ERASEBACKGROUND        Sent by the frame window to itself during
  7097.                              WM_PAINT processing. Returns TRUE, signaling
  7098.                              that the window should erase the client-window
  7099.                              area.
  7100.    Message                   Description
  7101.    ──────────────────────────────────────────────────────────────────────────
  7102.                             area.
  7103.  
  7104.    WM_FORMATFRAME            Calls WinFormatFrame and WinSetMultWindowPos to
  7105.                              format and position the frame controls.
  7106.  
  7107.    WM_MINMAXFRAME            If there is a client window, passes a message to
  7108.                              it; otherwise, passes a message via the
  7109.                              WinDefWindowProc function.
  7110.  
  7111.    WM_MOUSEMOVE              Determines the correct mouse pointer to use and
  7112.                              returns WinDefWindowProc.
  7113.  
  7114.    WM_PAINT                  If the frame window is minimized, sends
  7115.                              WM_QUERYICON and WM_ERASEBACKGROUND messages to
  7116.                              itself and draws the icon. Otherwise, paints
  7117.                              all of its controls, sends a WM_ERASEBACKGROUND
  7118.                              message to the client window, and paints the
  7119.                              client window.
  7120.  
  7121.    Message                   Description
  7122.    ──────────────────────────────────────────────────────────────────────────
  7123. 
  7124.    WM_QUERYTRACKINFO         Obtains the default tracking information.
  7125.  
  7126.    WM_SHOW                   Returns WinDefWindowProc.
  7127.  
  7128.    WM_SIZE                   Sends a WM_FORMATFRAME message to itself.
  7129.  
  7130.    WM_SYSCOMMAND             If the mouse is captured, ignores the system
  7131.                              command. Otherwise, uses one of the following
  7132.                              commands: SC_RESTORE, SC_SIZE, SC_MOVE,
  7133.                              SC_CLOSE, SC_TASKMANAGER, SC_NEXT, SC_NEXTFRAME,
  7134.                              SC_SYSMENU, SC_APPMENU.
  7135.  
  7136.    WM_UPDATEFRAME            Calls WinFormatFrame to format the frame
  7137.                              controls.
  7138.    ──────────────────────────────────────────────────────────────────────────
  7139.  
  7140.  
  7141.  
  7142.  9.3  Using Frame Windows
  7143.  
  7144.    The following sections detail creating and using frame windows in your
  7145.    Presentation Manager applications.
  7146.  
  7147.  9.3.1  Creating a Main Window
  7148.  
  7149.    You can create a main window by using the WinCreateStdWindow function. The
  7150.    following code fragment creates a typical main window: a frame window that
  7151.    has a System menu, title bar, menu, vertical and horizontal scroll bars,
  7152.    minimize and maximize buttons, and a sizing border:
  7153.  
  7154.    /* Create a main window. */
  7155.  
  7156.    ULONG flFrameControlFlags =
  7157.        FCF_SYSMENU | FCF_TITLEBAR   | FCF_SIZEBORDER |
  7158.        FCF_MENU    | FCF_MINMAX     | FCF_HORZSCROLL |
  7159.        FCF_VERTSCROLL;
  7160.  
  7161.    hwndFrame = WinCreateStdWindow(
  7162.        HWND_DESKTOP,          /* frame-window parent      */
  7163.        0L,                    /* no window styles         */
  7164.        &flFrameControlFlags,  /* frame-control flags      */
  7165.        "MyClass",             /* client-window class      */
  7166.        "Main Window",         /* window title             */
  7167.        0L,                    /* no client-window styles  */
  7168.        NULL,                  /* app module has resources */
  7169.        1,                     /* resource ID              */
  7170.        &hwndClient);          /* client-window handle     */
  7171.  
  7172.    You can also create a "standard" main window for an application by
  7173.    creating a frame window with the FCF_STANDARD style. You create the frame
  7174.    window using the WinCreateStdWindow function. The following code fragment
  7175.    creates the window:
  7176.  
  7177.    /* Set the frame-control flags. */
  7178.  
  7179.    ULONG flFrameControlFlags = FCF_STANDARD;
  7180.  
  7181.    hwndFrame = WinCreateStdWindow (HWND_DESKTOP, ..., &hwndClient);
  7182.  
  7183.    Another way to create a main window and its frame controls is by calling
  7184.    the WinCreateWindow function to create the frame window and the frame
  7185.    controls and then calling WinCreateWindow to create the client window. One
  7186.    advantage of this approach is that you can specify an initial size and
  7187.    position of the frame window when you create it. The following code
  7188.    fragment illustrates this:
  7189.  
  7190.    FRAMECDATA fcdata;
  7191.  
  7192.    fcdata.cb = sizeof(fcdata);
  7193.    fcdata.flCreateFlags = FCF_STANDARD;
  7194.    fcdata.hmodResources = NULL;
  7195.    fcdata.idResources   = idFrame;
  7196.  
  7197.    hwndFrame = WinCreateWindow(
  7198.        HWND_DESKTOP,   /* frame-window parent            */
  7199.        WC_FRAME,       /* frame-window class             */
  7200.        "Main Window",  /* window title                   */
  7201.        0L,             /* initially invisible            */
  7202.        0, 0, 0, 0,     /* size and position = 0          */
  7203.        NULL,           /* no owner                       */
  7204.        HWND_TOP,       /* top Z-order position           */
  7205.        idFrame,        /* frame-window ID                */
  7206.        &fcdata,        /* pointer to class-specific data */
  7207.        NULL);          /* no presentation parameters     */
  7208.  
  7209.    hwndClient = WinCreateWindow(
  7210.        hwndFrame,      /* client-window parent           */
  7211.        "My Class",     /* client-window class            */
  7212.        NULL,           /* no title for client window     */
  7213.        0L,             /* initially invisible            */
  7214.        0, 0, 0, 0,     /* size and position = 0          */
  7215.        hwndFrame,      /* owner is frame window          */
  7216.        HWND_BOTTOM,    /* bottom Z-order position        */
  7217.        FID_CLIENT,     /* standard client-window ID      */
  7218.        NULL,           /* no class-specific data         */
  7219.        NULL);          /* no presentation parameters     */
  7220.  
  7221.    /* ... continue initialization ... */
  7222.  
  7223.    WinShowWindow(hwndFrame, TRUE);
  7224.  
  7225.  9.3.2  Retrieving Frame Handles
  7226.  
  7227.    You can easily retrieve a frame-control handle by using the
  7228.    WinWindowFromID function. The following code fragment retrieves the
  7229.    control handle of the title bar:
  7230.  
  7231.    hwndTitleBar = WinWindowFromID(hwndFrame, FID_TITLEBAR);
  7232.  
  7233.    Given a frame-control handle, you can retrieve its parent frame-window
  7234.    handle by using the WinQueryWindow function:
  7235.  
  7236.    hwndFrame = WinQueryWindow(hwndTitleBar, QW_PARENT, FALSE);
  7237.  
  7238.    By using identifiers to identify frame controls rather than window
  7239.    classes, you can create your own controls to replace the predefined
  7240.    controls.
  7241.  
  7242.  
  7243.  9.4  Summary
  7244.  
  7245.    The following sections list the messages and functions you can use to
  7246.    create and use frame windows.
  7247.  
  7248.  9.4.1  Functions
  7249.  
  7250.    The following functions are used to create and use frame windows:
  7251.  
  7252.    WinCreateStdWindow  Creates a standard frame window.
  7253.  
  7254.    WinCreateWindow  Creates a standard frame window.
  7255.  
  7256.    WinCreateFrameControls  Creates standard frame controls for a given
  7257.    window.
  7258.  
  7259.    WinFormatFrame  Calculates the size and position of frame controls within
  7260.    a frame window. This function is typically used by applications that
  7261.    require a nonstandard frame-window layout.
  7262.  
  7263.    WinCalcFrameRect  Determines the size of a frame window or its client
  7264.    window.
  7265.  
  7266.    WinGetMinPosition  Obtains a frame window's minimized position.
  7267.  
  7268.    WinGetMaxPosition  Obtains a frame window's maximized position.
  7269.  
  7270.    WinFlashWindow  Starts or stops frame-window flashing.
  7271.  
  7272.  9.4.2  Messages
  7273.  
  7274.    The following messages are used to create and use frame windows:
  7275.  
  7276.    WM_ERASEBACKGROUND  Sent to the client window when the background needs to
  7277.    be redrawn.
  7278.  
  7279.    WM_FLASHWINDOW  Sent to a frame window as a result of a call to the
  7280.    WinFlashWindow function.
  7281.  
  7282.    WM_FORMATFRAME  Sent to a frame window to calculate the sizes and
  7283.    positions of its component windows.
  7284.  
  7285.    WM_MINMAXFRAME  Sent to a frame window when it is about to be minimized,
  7286.    maximized, or restored.
  7287.  
  7288.    WM_NEXTMENU  Sent to the owner window (the frame window) to obtain the
  7289.    next or previous menu window.
  7290.  
  7291.    WM_QUERYACCELTABLE  Sent to a frame window to obtain the accelerator-table
  7292.    handle.
  7293.  
  7294.    WM_QUERYBORDERSIZE  Sent to the frame window to determine the size of the
  7295.    window border.
  7296.  
  7297.    WM_QUERYFRAMECTLCOUNT  Sent to the frame window to determine the maximum
  7298.    number of frame controls that can exist for a frame window.
  7299.  
  7300.    WM_QUERYFRAMEINFO  Sent to determine the following things about the frame
  7301.    window: whether the window is a frame window; whether the window can be
  7302.    activated; whether the window should move as a result of its owner being
  7303.    moved; whether the window should be hidden or shown as a result of its
  7304.    owner window being hidden, shown, minimized, or maximized.
  7305.  
  7306.    WM_QUERYICON  Sent to the frame window to obtain the icon handle.
  7307.  
  7308.    WM_QUERYTRACKINFO  Sent to the window procedure of the owner (the frame
  7309.    window) of a title-bar control at the start of track-move processing.
  7310.  
  7311.    WM_SETACCELTABLE  Sent to the frame window to set the accelerator-table
  7312.    handle.
  7313.  
  7314.    WM_SETICON  Sent to the frame window to set the icon the frame-window uses
  7315.    when it is minimized.
  7316.  
  7317.    WM_TRACKFRAME  Sent to the frame window to start the tracking operation
  7318.    for a frame window.
  7319.  
  7320.    WM_TRANSLATEACCEL  Sent to the focus window (the frame window) to allow
  7321.    for accelerator-translation of the WM_CHAR message.
  7322.  
  7323.    WM_UPDATEFRAME  Sent after frame controls have controls have been added or
  7324.    removed from the frame window to notify the frame window to update the
  7325.    appearance of the window.
  7326.  
  7327.  
  7328.  
  7329.  ────────────────────────────────────────────────────────────────────────────
  7330.  Chapter 10  Control Windows
  7331.  
  7332.         10.1    Introduction
  7333.         10.2    About Control Windows
  7334.             10.2.1    Control-Window Features
  7335.         10.3    Using Control Windows in an Application
  7336.         10.4    Creating a Custom Control Window
  7337.         10.5    Summary
  7338.             10.5.1    Predefined Control-Window Classes
  7339.             10.5.2    Messages Sent to a Control Window
  7340.             10.5.3    Messages from a Control Window to an Owner Window
  7341.  
  7342.  10.1  Introduction
  7343.  
  7344.    This chapter describes the functions that allow you to use control windows
  7345.    in your applications. You should also be familiar with the following
  7346.    topics:
  7347.  
  7348.    ■  Standard user-interface guidelines
  7349.  
  7350.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  7351.  
  7352.    ■  Window Frames and creating standard frame windows
  7353.  
  7354.    ■  Window messages and message queues
  7355.  
  7356.  
  7357.  10.2  About Control Windows
  7358.  
  7359.    Control windows are predefined window classes that applications use for
  7360.    input and output. Control windows are typically used as part of a dialog
  7361.    window and are defined in the dialog template. Applications can also
  7362.    create control windows by calling the WinCreateWindow function with the
  7363.    appropriate window-class specification. The following control-window
  7364.    classes are predefined in MS OS/2:
  7365.  
  7366. ╓┌─┌─────────────┌───────────────────────────────────────────────────────────╖
  7367.    Control       Description
  7368.    ──────────────────────────────────────────────────────────────────────────
  7369.    Button        Buttons or boxes that the user selects by clicking or using
  7370.                  the keyboard. Several button types are available, including
  7371.                  push buttons, radio buttons, and check boxes.
  7372.  
  7373.    Control       Description
  7374.    ──────────────────────────────────────────────────────────────────────────
  7375. 
  7376.    Entry field   A single line of text that the user can edit.
  7377.  
  7378.    Static        Text, icons, or bitmaps that do not respond to user input.
  7379.  
  7380.    List box      A window containing a list of items, usually text strings,
  7381.                  from which the user may scroll and make selections.
  7382.  
  7383.    Menu          A list of items, either text or bitmaps. The items in a menu
  7384.                  may be displayed horizontally across the top of a frame
  7385.                  window, as in a menu bar, or vertically, in a menu. Menus
  7386.                  typically provide the command interface for an application.
  7387.  
  7388.    Scroll bar    A bar that allows a user to scroll the contents of a window.
  7389.                  Scroll-bar controls contain directional arrows and an
  7390.                  absolute-position indicator called the slider.
  7391.  
  7392.    Title bar     A title or caption displayed across the top of a frame
  7393.                  window. They can be used by a user to move the window, by
  7394.    Control       Description
  7395.    ──────────────────────────────────────────────────────────────────────────
  7396.                 window. They can be used by a user to move the window, by
  7397.                  dragging the title-bar control.
  7398.    ──────────────────────────────────────────────────────────────────────────
  7399.  
  7400.  
  7401.  10.2.1  Control-Window Features
  7402.  
  7403.    Control windows are always owned by other windows, usually dialog windows
  7404.    or application frame windows. The ownership relationship is important
  7405.    because a control window sends notification messages to its owner whenever
  7406.    an action occurs in the control window. A control-window position is also
  7407.    expressed in the coordinate space of its owner.
  7408.  
  7409.    Control windows are like other predefined window classes in that they
  7410.    respond to standard window management messages and functions, such as the
  7411.    WinSetWindowText and WinShowWindow functions.
  7412.  
  7413.    Control windows are usually painted synchronously. This means that a
  7414.    control window is redrawn as soon as any part of it becomes invalid.
  7415.  
  7416.    All control windows have a window ID. This ID is set either in a dialog
  7417.    template or when the control is created by the WinCreateWindow function.
  7418.    The ID is used when the control window sends notification messages to its
  7419.    owner. Care must be taken to make sure that the control ID for a
  7420.    particular window is not duplicated. Note that the control-window ID
  7421.    should not be the same as the command ID associated with individual menu
  7422.    items.
  7423.  
  7424.    All control-window classes have a set of specific messages that they send
  7425.    and receive. The summary at the end of this chapter lists the messages
  7426.    that all control windows have in common.
  7427.  
  7428.  
  7429.  10.3  Using Control Windows in an Application
  7430.  
  7431.    Control windows can be used in dialog windows and standard-frame or client
  7432.    windows.
  7433.  
  7434.    To use a control window in a dialog window, an application defines the
  7435.    control. A dialog template typically includes several control windows as
  7436.    part of the dialog template in its resource file. Then, when the dialog
  7437.    resource is loaded and displayed, control windows are automatically
  7438.    displayed as part of the dialog window. The application can then send
  7439.    messages to the control window to change its state. The dialog-window
  7440.    procedure defined by an application receives notification messages from
  7441.    the control window. The nature of these messages depends on the specific
  7442.    type of control window.
  7443.  
  7444.    To use a control window in a non-dialog window, an application must call
  7445.    the WinCreateWindow function using the appropriate window-class
  7446.    specification. An application usually specifies one of its client windows
  7447.    as the owner of the control window. Therefore, the client-window procedure
  7448.    receives notification messages from the control window. In some cases
  7449.    where a control is owned by the frame window (such as a menu control), the
  7450.    notification messages to the frame are passed on to the client window.
  7451.  
  7452.  
  7453.  10.4  Creating a Custom Control Window
  7454.  
  7455.    MS OS/2 provides several predefined control-window classes. You can create
  7456.    custom-control windows to fit specific purposes in an application by doing
  7457.    the following:
  7458.  
  7459.    ■  Using the user-drawn buttons, list boxes, and menus
  7460.  
  7461.    ■  Subclassing an existing control-window class
  7462.  
  7463.    ■  Registering and implementing a window class from scratch
  7464.  
  7465.    Buttons, list boxes, and menus have an optional style designation that
  7466.    marks them as "user-drawn." This means that the owner window of the
  7467.    control with this style receives a message whenever the control must be
  7468.    drawn. (If the owner window is a frame window, it sends owner-drawn
  7469.    messages to its client windows, which should be handled by the
  7470.    client-window procedure.) This allows you to alter the appearance of a
  7471.    control window. For buttons, the owner-drawn style affects the drawing of
  7472.    the entire control. For menus and list boxes, the owner draws the
  7473.    individual items within the control, and the system draws the external
  7474.    outline of the control.
  7475.  
  7476.    Subclassing an existing control window is an easy way to make custom
  7477.    controls. When you subclass an existing control window, you only alter
  7478.    those behaviors you want to change, letting all other messages through to
  7479.    the original control-window procedure.
  7480.  
  7481.    The techniques for defining a custom control window are the same as those
  7482.    used in creating a client-window class. However, if you are creating your
  7483.    own custom-control window class, be sure it can send and receive the
  7484.    messages listed in Section 10.5.
  7485.  
  7486.    If you create a custom control-window class by subclassing a control class
  7487.    or by creating a window class from scratch, you can use its class name in
  7488.    the dialog template just like a predefined window-class constant. For
  7489.    example, if you define and register a window class called "MyControlClass"
  7490.    in an application, you can define a dialog window containing a control
  7491.    window using the following resource definition:
  7492.  
  7493.    DLGTEMPLATE IDD_CUSTOM_TEST
  7494.    BEGIN
  7495.        DIALOG "", IDD_CUSTOM_TEST, 1, 1, 126, 130, FS_DLGBORDER, 0
  7496.        BEGIN
  7497.            CONTROL "This is Text", IDD_TITLE,
  7498.                    37, 107, 56, 12,
  7499.                    WC_STATIC,
  7500.                    SS_TEXT | DT_CENTER | DT_TOP | DT_WORDBREAK
  7501.                    | WS_VISIBLE
  7502.            CONTROL "Custom Control", IDD_CUSTOM,
  7503.                    33, 68, 64, 13,
  7504.                    "MyControlClass",
  7505.                    WS_VISIBLE
  7506.            CONTROL "Okay", DID_OK,
  7507.                    57, 10, 24, 14,
  7508.                    WC_BUTTON,
  7509.                    BS_PUSHBUTTON | BS_DEFAULT | WS_TABSTOP | WS_VISIBLE
  7510.        END
  7511.    END
  7512.  
  7513.  
  7514.  10.5  Summary
  7515.  
  7516.    The following sections describe the predefined control-window classes and
  7517.    the messages common to all control windows.
  7518.  
  7519.  10.5.1  Predefined Control-Window Classes
  7520.  
  7521.    These the predefined control-window classes in MS OS/2:
  7522.  
  7523.    WC_BUTTON  A button control, including push buttons, radio buttons, and
  7524.    check boxes.
  7525.  
  7526.    WC_ENTRYFIELD  An entry-field control that allows single-line text
  7527.    editing.
  7528.  
  7529.    WC_STATIC  A static control that displays text, icons, or bitmap data.
  7530.  
  7531.    WC_LISTBOX  A list box that displays a list of items that can be scrolled.
  7532.  
  7533.    WC_MENU  A menu, including a menu bar and menus.
  7534.  
  7535.    WC_SCROLLBAR  A scroll bar that allows a user to scroll the contents of a
  7536.    window.
  7537.  
  7538.    WC_TITLEBAR  The title of a window at the top of the frame that allows a
  7539.    user to reposition a window on screen.
  7540.  
  7541.  10.5.2  Messages Sent to a Control Window
  7542.  
  7543.    All types of control windows receive the following messages:
  7544.  
  7545.    WM_ADJUSTWINDOWPOS  Sent to the control window by the WinSetWindowPos
  7546.    function to allow the control to modify its position. The message contains
  7547.    a pointer to an SWP structure that specifies the new control size and
  7548.    position. The control can modify the data in the SWP structure before the
  7549.    control is actually displayed or moved. For example, the dimensions of an
  7550.    entry-field control define the limits of the area that can be edited (not
  7551.    the border). The entry-field control modifies the fields of the SWP
  7552.    structure, specifying the size and position, including the border.
  7553.    List-box controls also modify their size and position, including any
  7554.    borders, and they can adjust their height to display all list items.
  7555.  
  7556.    WM_QUERYDLGCODE  Sent to the control window by the system to determine the
  7557.    kinds of messages the control processes. The control window returns a
  7558.    dialog code that is a combination of bit flags describing the messages the
  7559.    control responds to.
  7560.  
  7561.  10.5.3  Messages from a Control Window to an Owner Window
  7562.  
  7563.    The following are messages sent from a control window to an owner window:
  7564.  
  7565.    WM_COMMAND  Posted to the owner-message queue by menus and buttons. The
  7566.    owner window receives this message when the user selects a push button or
  7567.    chooses a menu item. This message also includes information about its
  7568.    source.
  7569.  
  7570.    WM_CONTROL  Sent (with the WinSendMsg function) to the owner of the
  7571.    control window. This message includes the control-window ID and other
  7572.    information specific to the type of control and nature of the message.
  7573.  
  7574.    WM_CONTROLHEAP  Sent by the control to its owner window when it needs a
  7575.    handle to a heap to allocate memory. For example, entry-field controls
  7576.    allocate memory to hold text associated with a control window. Generally,
  7577.    an application ignores this message, passing it on to the default window
  7578.    procedure that returns a handle to a heap.
  7579.  
  7580.    WM_CONTROLPOINTER  Sent to an owner window when the mouse pointer moves
  7581.    over the control window. The owner sets the mouse pointer to a different
  7582.    shape, if desired. The control passes an HPOINTER to a mouse pointer as
  7583.    part of this message. The owner can alter the default pointer shape by
  7584.    passing a different HPOINTER back. Applications that use the default
  7585.    should pass the same HPOINTER back as the result of this message or just
  7586.    pass the message on to the WinDefWindowProc function.
  7587.  
  7588.    WM_HELP  Posted by controls with the appropriate style. This message is
  7589.    like the WM_COMMAND message. The owner window receives this message and
  7590.    responds with help information, depending on the context information
  7591.    included in the message.
  7592.  
  7593.    WM_SYSCOMMAND  Posted by controls with the appropriate style. This message
  7594.    is like the WM_COMMAND message. It is not passed from a frame window to a
  7595.    client window. Generally, the only control sending this message is the
  7596.    system menu in a frame window.
  7597.  
  7598.  
  7599.  
  7600.  ────────────────────────────────────────────────────────────────────────────
  7601.  Chapter 11  Title-Bar Controls
  7602.  
  7603.         11.1    Introduction
  7604.         11.2    About Title Bars
  7605.         11.3    Using Title-Bar Controls in Applications
  7606.             11.3.1    Altering Dragging Action
  7607.         11.4    Default Title-Bar Behavior
  7608.         11.5    Summary
  7609.  
  7610.  11.1  Introduction
  7611.  
  7612.    This chapter describes creating and using title-bar control windows. The
  7613.    title-bar control window is part of a standard frame window. You should
  7614.    also be familiar with the following topics:
  7615.  
  7616.    ■  Standard user-interface guidelines
  7617.  
  7618.    ■  Standard frame windows
  7619.  
  7620.    ■  Window messages and message queues
  7621.  
  7622.  
  7623.  11.2  About Title Bars
  7624.  
  7625.    A standard frame window is made up of several overlapping control windows
  7626.    that give the window its distinctive look and behavior. This chapter
  7627.    discusses one of these control windows: the title bar. Menus and scroll
  7628.    bars, the other control-window types that can be part of a frame window,
  7629.    are discussed in other chapters in this manual. Figure 11.1 shows a
  7630.    standard frame window with its title bar:
  7631.  
  7632.    ┌────────────────────────────────────────────────────────────────────────┐
  7633.    │ Figure 11.1 can be found in Section 11.2 of the printed manual.        │
  7634.    └────────────────────────────────────────────────────────────────────────┘
  7635.  
  7636.    Figure 11.1  Frame Window with Title Bar
  7637.  
  7638.    The title bar in a standard frame window performs four functions. First,
  7639.    it displays the title of the window across the top of the frame. Second,
  7640.    it changes its highlight appearance to show whether the frame window is
  7641.    active or not. Normally, the topmost window in a screen display is the
  7642.    active window. Third, the title bar responds to the user──for example,
  7643.    when the user drags the frame window to a new location on the screen.
  7644.    Finally, the title bar flashes (as a result of the WinFlashWindow
  7645.    function).
  7646.  
  7647.    Title-bar control windows, like all control windows, must be owned by
  7648.    another window. Title-bar controls are owned by the frame window. A
  7649.    title-bar control sends messages to its owner when the control receives
  7650.    user input.
  7651.  
  7652.  
  7653.  11.3  Using Title-Bar Controls in Applications
  7654.  
  7655.    Typically, you need not be too concerned with the title-bar control. The
  7656.    default behavior of the title-bar control follows the standard
  7657.    user-interface guidelines. Most applications allow the title-bar control
  7658.    to operate according to these guidelines.
  7659.  
  7660.    To include a title-bar control in a standard frame window, the application
  7661.    must compare (by using the OR operator) constants representing each
  7662.    control type and pass the resulting value to the WinCreateStdWindow
  7663.    function. The following code fragment shows the creation of a standard
  7664.    frame window with a title bar, a minimum/maximum control, a size border, a
  7665.    System menu, and an application menu. (The System menu and application
  7666.    menu are considered frame controls. For more information about frame
  7667.    controls, see Chapter 9, "Frame Windows.")
  7668.  
  7669.    ULONG lControlStyle = FCF_TITLEBAR | FCF_SIZEBORDER |  FCF_MINMAX |
  7670.        FCF_SYSMENU | FCF_MENU;
  7671.  
  7672.    hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
  7673.        WS_VISIBLE | FS_ACCELTABLE,
  7674.        &lControlStyle,
  7675.        szClassName,
  7676.        szClassName,
  7677.        0L, NULL,
  7678.        ID_MENU_RESOURCE,
  7679.        &hwndClient);
  7680.  
  7681.    Once the frame controls are in place in the frame window, most
  7682.    applications can ignore them. The system handles the frame controls. In
  7683.    some cases, the application may take control of the title bar by sending
  7684.    messages to the title-bar control window.
  7685.  
  7686.    To get the window handle of a title-bar control in a frame window, the
  7687.    application calls the WinWindowFromID function with the frame-window
  7688.    handle and a constant identifying the title-bar control, as shown in the
  7689.    following code:
  7690.  
  7691.    hwndTitleBar = WinWindowFromID(hwndFrame, FID_TITLEBAR);
  7692.  
  7693.    To change the text of a title bar, the application sets the window text of
  7694.    the frame window by calling the WinSetWindowText function. The frame
  7695.    window passes the message to the title bar. This changes the title-bar
  7696.    text.
  7697.  
  7698.  11.3.1  Altering Dragging Action
  7699.  
  7700.    When the user clicks in the title-bar control, the title bar sends its
  7701.    owner (the frame window) a WM_TRACKFRAME message. The frame window also
  7702.    sends a WM_QUERYTRACKINFO message to itself to fill in a TRACKINFO
  7703.    structure that defines the tracking parameters and boundaries. To modify
  7704.    the default behavior, you must subclass the frame window and intercept the
  7705.    message WM_QUERYTRACKINFO and modify the TRACKINFO structure. If you
  7706.    return TRUE for the WM_QUERYTRACKINFO message, the tracking information
  7707.    proceeds according to the information in the TRACKINFO structure. If you
  7708.    return FALSE, no tracking occurs.
  7709.  
  7710.  
  7711.  11.4  Default Title-Bar Behavior
  7712.  
  7713.    This section describes all the messages specifically handled by the
  7714.    predefined title-bar control class.
  7715.  
  7716. ╓┌─┌──────────────────────────┌──────────────────────────────────────────────╖
  7717.    Message                    Description
  7718.    ──────────────────────────────────────────────────────────────────────────
  7719.    WM_CREATE                  Sets the window text for the control. Returns
  7720.                               FALSE if creation succeeds.
  7721.  
  7722.    WM_DESTROY                 Frees the window text for the control.
  7723.  
  7724.    WM_QUERYWINDOWPARAMS       Returns the requested window parameters.
  7725.  
  7726.    WM_SETWINDOWPARAMS         Sets the specified window parameters.
  7727.  
  7728.    WM_PAINT                   Draws the title bar.
  7729.  
  7730.    Message                    Description
  7731.    ──────────────────────────────────────────────────────────────────────────
  7732. 
  7733.    WM_HITTEST                 Always returns HT_NORMAL, so the title bar does
  7734.                               not beep when it is disabled (it is disabled
  7735.                               when the frame window is maximized).
  7736.  
  7737.    WM_BUTTON1DOWN             Sends the WM_TRACKFRAME message to the owner
  7738.                               (typically a frame window) to start tracking.
  7739.  
  7740.    WM_BUTTON1DBLCLK           Restores the window if the owner window is
  7741.                               minimized or maximized. If the window is
  7742.                               neither, maximizes the window.
  7743.  
  7744.    WM_ADJUSTWINDOWPOS         Returns FALSE. Process this message to prevent
  7745.                               the WinDefWindowProc function from sending the
  7746.                               size and show messages.
  7747.  
  7748.    WM_QUERYDLGCODE            Returns the predefined constant DLGC_STATIC. A
  7749.                               user cannot use the TAB key to move to this
  7750.                               window in a dialog box.
  7751.    Message                    Description
  7752.    ──────────────────────────────────────────────────────────────────────────
  7753.                              window in a dialog box.
  7754.  
  7755.    TBM_QUERYHILITE            Returns the highlight state of the title bar.
  7756.  
  7757.    TBM_SETHILITE              Sets the highlight state of the title bar,
  7758.                               repainting it if the state is changing.
  7759.    ──────────────────────────────────────────────────────────────────────────
  7760.  
  7761.  
  7762.  
  7763.  11.5  Summary
  7764.  
  7765.    The following messages are associated with frame-control windows:
  7766.  
  7767.    TBM_SETHILITE  Sets the highlight state of the title bar to TRUE or FALSE.
  7768.    The system usually sends this message to a title bar to show whether or
  7769.    not the frame window containing the title bar is active.
  7770.  
  7771.    TBM_QUERYHILITE  Returns the highlight state (TRUE or FALSE) for a
  7772.    title-bar control window.
  7773.  
  7774.  
  7775.  
  7776.  ────────────────────────────────────────────────────────────────────────────
  7777.  Chapter 12  Button Controls
  7778.  
  7779.         12.1    Introduction
  7780.         12.2    About Button Controls
  7781.         12.3    Using Button Controls in an Application
  7782.             12.3.1    Buttons in a Dialog Window
  7783.             12.3.2    Buttons in a Client Window
  7784.             12.3.3    Responding to a Button-Notification Message
  7785.             12.3.4    Changing the Button State
  7786.             12.3.5    Owner-Drawn Buttons
  7787.         12.4    Default Button Behavior
  7788.         12.5    Summary
  7789.             12.5.1    Button Styles
  7790.             12.5.2    Messages Sent to Button Controls
  7791.             12.5.3    Messages Sent from Buttons to Owner Windows
  7792.  
  7793.  12.1  Introduction
  7794.  
  7795.    This chapter describes how to use button-control windows in your
  7796.    applications. You should also be familiar with the following topics:
  7797.  
  7798.    ■  Standard user-interface guidelines
  7799.  
  7800.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  7801.  
  7802.    ■  Window messages and message queues
  7803.  
  7804.  
  7805.  12.2  About Button Controls
  7806.  
  7807.    A button control is a window that represents a button that a user can
  7808.    select using the mouse or keyboard. Buttons can appear by themselves or in
  7809.    groups, and can appear with or without label text. A user can select a
  7810.    button by clicking it with the mouse or pressing the ENTER key when the
  7811.    button window has the keyboard focus. Buttons typically change appearance
  7812.    when selected.
  7813.  
  7814.    There are four main types of buttons: push buttons, radio buttons, check
  7815.    boxes, and three-state check boxes. The appearance and behavior of button
  7816.    controls is determined by the style of the button. Figure 12.1 shows the
  7817.    different types of button controls.
  7818.  
  7819.    ┌────────────────────────────────────────────────────────────────────────┐
  7820.    │ Figure 12.1 can be found in Section 12.2 of the printed manual.        │
  7821.    └────────────────────────────────────────────────────────────────────────┘
  7822.  
  7823.    Figure 12.1  Button Types
  7824.  
  7825.    Radio buttons, check boxes, and three-state check boxes are used to
  7826.    control attributes of an operation. Push buttons are used to initiate
  7827.    operations. For example, a user might indicate paper size, print quality,
  7828.    and printer type in a print-command dialog window containing an array of
  7829.    radio buttons and check boxes. Once the user sets each option, a push
  7830.    button can be used to tell an application that printing should begin (or
  7831.    be canceled). The application queries the state of each radio button and
  7832.    check box to determine the printing parameters.
  7833.  
  7834.    Push buttons are rounded-corner rectangular windows containing text
  7835.    strings. Push buttons become highlighted when they are selected by a user.
  7836.    They return to an unhighlighted state when the user releases the mouse
  7837.    button or the SPACEBAR. Push buttons are typically used to start or stop
  7838.    operations. A push button posts a WM_COMMAND message to its owner window.
  7839.  
  7840.    Radio buttons are windows with text displayed to the right of a small,
  7841.    circular indicator. A radio button toggles between selected and
  7842.    unselected, each time the user selects it. The button retains the state
  7843.    until the next selection. Radio buttons usually appear in groups with only
  7844.    one button selected at a time. Radio buttons are appropriate where an
  7845.    exclusive choice is required from a group of related options. A radio
  7846.    button sends a WM_CONTROL message to its owner window.
  7847.  
  7848.    Check boxes are similar to radio buttons except that they are used by
  7849.    themselves instead of in groups. They also toggle on or off application
  7850.    features. A check box sends a WM_CONTROL message to its owner window.
  7851.  
  7852.    Three-state check boxes are similar to check boxes except that they can be
  7853.    displayed in halftone as well as selected or unselected. A three-state
  7854.    check box sends a WM_CONTROL message to its owner window.
  7855.  
  7856.    In addition to the four predefined button-control types, an application
  7857.    can create buttons that appear defined by the owner window. Buttons using
  7858.    this style send BN_PAINT messages to their owner windows when they must be
  7859.    drawn or highlighted.
  7860.  
  7861.    Button-control windows are always owned by other windows, typically by an
  7862.    application client window or a dialog window. A button control posts
  7863.    WM_COMMAND messages or sends WM_CONTROL notification messages to its owner
  7864.    when a user selects the button. Owner windows can also send messages to
  7865.    button controls to query or set states.
  7866.  
  7867.  
  7868.  12.3  Using Button Controls in an Application
  7869.  
  7870.    The most common way to use button controls is in a dialog window. An
  7871.    application defines one or more button controls in the dialog template in
  7872.    the resource file, and processes button messages in the dialog-window
  7873.    procedure.
  7874.  
  7875.    Buttons can be associated in groups in dialog windows. A user can move
  7876.    from one button in a group to another button in the same group by pressing
  7877.    the direction keys. The TAB key moves from one group to the next. Groups
  7878.    are established by setting the WS_GROUP style bit for the first member of
  7879.    each group in the dialog template.
  7880.  
  7881.    You can also use button controls in standard client windows. For these
  7882.    windows, create a button-control window by calling the WinCreateWindow
  7883.    function with a window class of WC_BUTTON. Specify the client window as
  7884.    the owner of the button window. The owner window receives messages from
  7885.    buttons and can send messages to the buttons to alter their control state.
  7886.    The control state includes highlighting control text, button position, and
  7887.    the enabled/disabled state.
  7888.  
  7889.    Applications can create custom buttons that appear to be controlled by the
  7890.    application. The BS_USERBUTTON style, used in conjunction with other
  7891.    button styles, creates a button that notifies the application whenever the
  7892.    button must be drawn, allowing the application to draw the button.
  7893.  
  7894.  12.3.1  Buttons in a Dialog Window
  7895.  
  7896.    Buttons are typically used in dialog windows. An application can define
  7897.    buttons as part of a dialog-template resource file, as shown in the
  7898.    following sample Resource Compiler source-code fragment:
  7899.  
  7900.    DLGTEMPLATE IDD_BUTTON
  7901.    BEGIN
  7902.      DIALOG  "", 2, 64, 9, 235, 130
  7903.      BEGIN
  7904.          AUTORADIOBUTTON "R~adio1", ID_RADIO1, 15, 20, 40, 12, WS_GROUP
  7905.          AUTORADIOBUTTON "Ra~dio2", ID_RADIO2, 15, 40, 40, 12
  7906.          AUTORADIOBUTTON "Rad~io3", ID_RADIO3, 15, 60, 40, 12
  7907.          AUTORADIOBUTTON "R~adio4", ID_RADIO4,15, 80, 40, 12
  7908.  
  7909.          PUSHBUTTON "Button 1", ID_PUSH1, 100, 50, 14, WS_GROUP
  7910.          PUSHBUTTON "Button 2", ID_PUSH2, 75, 100, 50, 14, WS_GROUP
  7911.          PUSHBUTTON "Button 3", ID_PUSH3, 130, 100, 60, 14, WS_GROUP
  7912.  
  7913.          CHECKBOX "Check Box 1", ID_CHECK1, 150, 20, 58, 12, WS_GROUP
  7914.          CHECKBOX "no toggle", ID_CHECK2, 150, 40, 58, 12
  7915.  
  7916.          AUTOCHECKBOX "Check Box 3", ID_CHECK3, 150, 60, 58, 12, WS_GROUP
  7917.          DEFPUSHBUTTON "OK", DID_OK, 75, 26, 46, 20, WS_GROUP
  7918.      END
  7919.    END
  7920.  
  7921.    Each button item in a dialog window has an ID (for example, ID_RADIO1)
  7922.    that allows an application to identify the source of the WM_COMMAND and
  7923.    WM_CONTROL messages. The ID is also used to retrieve the button-window
  7924.    handle using the WinWindowFromID function.
  7925.  
  7926.    The dialog template also specifies the text for each button, which is
  7927.    displayed in a rectangular box. If the button text is too long to fit in
  7928.    the button, it is clipped to the rectangle. For radio buttons and check
  7929.    boxes, text is displayed to the right of the button. A user selects the
  7930.    button by clicking either the button or the text itself.
  7931.  
  7932.    The WS_GROUP attribute identifies the beginning of each new group of
  7933.    buttons. In the example above, the first four auto-radio buttons are in
  7934.    the same group, the following push buttons are in their own group, and the
  7935.    following two check boxes are in their own group. The auto-radio buttons
  7936.    in the first group can only be selected one at a time. An application must
  7937.    see that only one check box in a group is selected at a time. The group
  7938.    can wrap around from the end of the item list to the beginning.
  7939.  
  7940.    Notice the DEFPUSHBUTTON style with the DID_OK identification number in
  7941.    the code fragment above. It is customary to include an OK button with this
  7942.    ID in most dialog windows to provide a uniform user interface. The
  7943.    DEFPUSHBUTTON style draws a thick border around a button and allows a user
  7944.    to select the button by pressing the ENTER key.
  7945.  
  7946.    The dialog-window procedure for a dialog window containing buttons must
  7947.    respond to WM_COMMAND and WM_CONTROL messages. A common strategy is to use
  7948.    auto-radio buttons and auto-check boxes to allow a user to set a list of
  7949.    attributes for a command, and execute it by choosing the OK button. In
  7950.    this case, the dialog-window procedure ignores all WM_CONTROL messages
  7951.    that come from auto-radio buttons and auto-check boxes. These controls
  7952.    select and deselect themselves. When the dialog-window procedure receives
  7953.    a WM_COMMAND message for the OK button, it should query the auto-radio
  7954.    buttons and auto-check boxes to determine which options have been selected
  7955.    before proceeding with the operation.
  7956.  
  7957.  12.3.2  Buttons in a Client Window
  7958.  
  7959.    Applications can also use buttons in non-dialog windows. An application
  7960.    can create a button window using an application client window as the
  7961.    owner, as shown in the following code fragment:
  7962.  
  7963.    /* Create a button window. */
  7964.  
  7965.    hwndButton = WinCreateWindow(hwndClient,  /* parent       */
  7966.        WC_BUTTON,                            /* class        */
  7967.        "Test Button",                        /* text         */
  7968.        WS_VISIBLE | BS_PUSHBUTTON,           /* style        */
  7969.        10, 10,                               /* x, y         */
  7970.        60, 70,                               /* cx, cy       */
  7971.        hwndClient,                           /* owner        */
  7972.        HWND_TOP,                             /* behind       */
  7973.        ID_PBWINDOW,                          /* ID           */
  7974.        NULL,                                 /* control data */
  7975.        NULL);                                /* parameters   */
  7976.  
  7977.    Once created in the client window, the button posts a WM_COMMAND message,
  7978.    or sends a WM_CONTROL message to the client-window procedure. The window
  7979.    procedure should examine the message ID to determine the button that sent
  7980.    the message.
  7981.  
  7982.    Applications that have client-window buttons may move and size the buttons
  7983.    when the window receives a WM_SIZE message. This message indicates that
  7984.    the window is changing size. Buttons can be moved and sized using the
  7985.    WinSetWindowPos function. You can obtain a window handle for a button by
  7986.    calling the WinWindowFromID function using the parent window and the
  7987.    window ID for each button.
  7988.  
  7989.  12.3.3  Responding to a Button-Notification Message
  7990.  
  7991.    A button control sends a message to its owner window when a user selects
  7992.    the button, by either using the mouse or the keyboard. Buttons created
  7993.    with the BS_PUSHBUTTON or BS_USERBUTTON styles generate a WM_COMMAND
  7994.    message each time they are selected (this can be altered by specifying the
  7995.    BS_HELP or BS_SYSCOMMAND style when the button is created). All other
  7996.    button styles generate WM_CONTROL messages when selected.
  7997.  
  7998.    A push button is automatically highlighted when a user selects it using
  7999.    the mouse. The button tracks the mouse until the user releases the mouse
  8000.    button. The highlight is turned off if the mouse moves outside the button
  8001.    boundaries. The push button does not generate any messages to its owner
  8002.    window until the user releases the mouse button, and then only if the
  8003.    mouse button is released inside the push-button boundary. When the owner
  8004.    window receives a WM_COMMAND message from a push button, the low word of
  8005.    the first parameter in the message contains the button window ID, as
  8006.    specified in the dialog template or when the button was created.
  8007.  
  8008.    You should avoid duplicating IDs in menu commands and buttons because they
  8009.    both send IDs to owner windows as WM_COMMAND messages. However,
  8010.    it is possible to tell whether a WM_COMMAND message came from a menu
  8011.    or a push button by looking for the value CMDSRC_PUSHBUTTON or CMDSRC_MENU
  8012.    in the low word of the second parameter of the message.
  8013.  
  8014.    Button types other than push buttons generate WM_CONTROL messages when
  8015.    selected. Applications can examine the low word of the first parameter in
  8016.    the message to find the button ID and the high word of the first parameter
  8017.    to determine the notification code for the control message. The
  8018.    notification code tells the application whether the control message
  8019.    originated from the user clicking or double clicking, or if the button
  8020.    needs to be drawn.
  8021.  
  8022.    When a check box or radio button is selected, it sends a WM_CONTROL
  8023.    message with a notification BN_CLICKED code to the owner window. The owner
  8024.    window responds by sending a message back to the button to toggle its
  8025.    state.
  8026.  
  8027.    In the case of auto-check boxes and auto-radio buttons, an application
  8028.    need not respond because these buttons toggle themselves in response to
  8029.    the mouse. The application still receives WM_CONTROL messages each time
  8030.    the button is selected. Most applications that use this default for radio
  8031.    buttons and check boxes should also use the automatic versions of these
  8032.    buttons and ignore any WM_COMMAND messages.
  8033.  
  8034.  12.3.4  Changing the Button State
  8035.  
  8036.    An application can query and set the highlight and checked state of its
  8037.    buttons by sending messages to button windows. The window handle for a
  8038.    button can be obtained by calling the fbWinWindowFromID function using the
  8039.    parent window and the window ID of the button. In the case of a dialog
  8040.    window, the parent would be the dialog window and the ID would be the
  8041.    button item ID from the dialog template.
  8042.  
  8043.    Button-window text is stored as window text, and is accessible by using
  8044.    the WinSetWindowText and WinQueryWindowText functions. The size, position,
  8045.    and visibility of a button are set using standard window functions.
  8046.  
  8047.  12.3.5  Owner-Drawn Buttons
  8048.  
  8049.    An application can create custom buttons by using the BS_USERBUTTON
  8050.    style in combination with other styles. For example, an application can
  8051.    create a custom auto-radio button that works like an auto-radio button but
  8052.    whose appearance is controlled by the application. The owner window
  8053.    receives WM_CONTROL messages for these buttons whenever they must be
  8054.    drawn, highlighted, or disabled.
  8055.  
  8056.    When a button must be drawn, the owner window receives a WM_CONTROL
  8057.    message with the low word of the first parameter equal to BN_PAINT. The
  8058.    second parameter is a pointer to a USERBUTTON structure that contains
  8059.    necessary information the application needs to draw the button. The
  8060.    USERBUTTON structure is shown below.
  8061.  
  8062.    typedef struct _USERBUTTON {
  8063.        HWND hwnd;
  8064.        HPS hps;
  8065.        USHORT fsState;
  8066.        USHORT fsStateOld;
  8067.    } USERBUTTON;
  8068.  
  8069.    An application uses the hwnd field in this structure to find the bounding
  8070.    rectangle for the button. The hps field is used as a presentation space
  8071.    for any drawing. The high byte of the fsState field contains flags that
  8072.    tell an application how to draw the button: highlighted, unhighlighted, or
  8073.    disabled. The high byte of the fsStateOld field contains flags describing
  8074.    the current highlighted, unhighlighted, or disabled state of the button.
  8075.  
  8076.  
  8077.  12.4  Default Button Behavior
  8078.  
  8079.    This section describes the messages specifically handled by the predefined
  8080.    button-control window class.
  8081.  
  8082. ╓┌─┌──────────────────────────┌──────────────────────────────────────────────╖
  8083.    Message                    Description
  8084.    ──────────────────────────────────────────────────────────────────────────
  8085.    WM_CREATE                  Validates the requested button style and sets
  8086.                               the window text.
  8087.    Message                    Description
  8088.    ──────────────────────────────────────────────────────────────────────────
  8089.                              the window text.
  8090.  
  8091.    WM_DESTROY                 Frees the memory containing the window text.
  8092.  
  8093.    WM_PAINT                   Draws the button according to its style and
  8094.                               current state.
  8095.  
  8096.    WM_SETFOCUS                Creates a cursor if receiving the focus,
  8097.                               destroys the cursor if losing the focus.
  8098.  
  8099.    WM_BUTTON1DOWN             Sets mouse capture for the button window.
  8100.  
  8101.    WM_MOUSEMOVE               Sets the default mouse pointer. If the button
  8102.                               has the mouse capture, the button highlight
  8103.                               state changes as the mouse pointer moves in and
  8104.                               out of button area.
  8105.  
  8106.    WM_BUTTON1UP               If the button has mouse capture, releases the
  8107.                               mouse capture and sends notification message to
  8108.    Message                    Description
  8109.    ──────────────────────────────────────────────────────────────────────────
  8110.                              mouse capture and sends notification message to
  8111.                               the owner window if the mouse pointer is inside
  8112.                               the button when the mouse button is released.
  8113.                               If the button is a BS_PUSHBUTTON, a WM_COMMAND
  8114.                               message is posted, otherwise a WM_CONTROL
  8115.                               message with the BN_CLICKED code is sent.
  8116.  
  8117.    WM_BUTTON1DBLCLK           Marks the button, sending a BN_DBLCLICKED
  8118.                               notification code when the button-up message
  8119.                               arrives.
  8120.  
  8121.    WM_CHAR                    Sets mouse capture when the SPACEBAR is
  8122.                               pressed, releases capture when the SPACEBAR is
  8123.                               released. Passes other key messages to the
  8124.                               default window procedure.
  8125.  
  8126.    WM_QUERYDLGCODE            Returns DLGC_BUTTON combined using the OR
  8127.                               operator with the appropriate bits to designate
  8128.                               the particular button type.
  8129.    Message                    Description
  8130.    ──────────────────────────────────────────────────────────────────────────
  8131.                              the particular button type.
  8132.  
  8133.    WM_QUERYWINDOWPARAMS       Returns the requested window parameters.
  8134.  
  8135.    WM_SETWINDOWPARAMS         Sets the requested window parameters and
  8136.                               redraws the button, including the cursor, if
  8137.                               the window has the focus.
  8138.  
  8139.    WM_ENABLE                  Draws the button.
  8140.  
  8141.    WM_MATCHMNEMONIC           Returns TRUE if mp1 matches a button mnemonic.
  8142.  
  8143.    BM_QUERYCHECKINDEX         Returns the zero-based index to the selected
  8144.                               item in the same group as the button. Returns
  8145.                               -1 if no button in the group is selected or if
  8146.                               the button receiving the message is not a radio
  8147.                               button or auto-radio button.
  8148.  
  8149.    BM_CLICK                   Sends a WM_BUTTON1DOWN and WM_BUTTON1UP message
  8150.    Message                    Description
  8151.    ──────────────────────────────────────────────────────────────────────────
  8152.   BM_CLICK                   Sends a WM_BUTTON1DOWN and WM_BUTTON1UP message
  8153.                               to itself to simulate a user-button selection.
  8154.  
  8155.    BM_QUERYCHECK              Returns the checked state of the button.
  8156.  
  8157.    BM_SETCHECK                Sets the checked state of the button, returns
  8158.                               the previous checked state.
  8159.  
  8160.    BM_QUERYHILITE             Returns the highlight state of the button.
  8161.  
  8162.    BM_SETHILITE               Sets the highlight state of the button, returns
  8163.                               the previous highlight state.
  8164.  
  8165.    BM_SETDEFAULT              Sets the default button state, redraws the
  8166.                               button.
  8167.    ──────────────────────────────────────────────────────────────────────────
  8168.  
  8169.  
  8170.  
  8171.  12.5  Summary
  8172.  
  8173.    The following section lists the available styles for buttons and the
  8174.    messages associated with button controls.
  8175.  
  8176.  12.5.1  Button Styles
  8177.  
  8178.    The following are available button styles:
  8179.  
  8180.    BS_3STATE  Similar to a check box, except that it toggles between
  8181.    selected, unselected, and halftone states. The owner window receives a
  8182.    WM_CONTOL message and changes the state of the three-state check box when
  8183.    it is selected.
  8184.  
  8185.    BS_AUTO3STATE  Similar to a three-state check box, except it changes its
  8186.    state when selected.
  8187.  
  8188.    BS_AUTOCHECKBOX  Similar to a check box, except that it automatically
  8189.    changes its state when selected. An auto-check box sends a WM_CONTROL
  8190.    message to its owner window.
  8191.  
  8192.    BS_AUTORADIOBUTTON  Similar to a radio button, except that it
  8193.    automatically responds to a selection by changing its state and the state
  8194.    of all other radio buttons in its group.
  8195.  
  8196.    BS_CHECKBOX  A check box is a small square window that is empty when it is
  8197.    unselected, and contains an "x" when selected. Check-box text is dis-
  8198.    played to the right of the check box. The owner window is notified with a
  8199.    WM_CONTROL message when the check box is selected and is responsible for
  8200.    changing the check-box state.
  8201.  
  8202.    BS_DEFAULT  A button with this style is outlined with a heavy black
  8203.    border. A user can select this button by pressing the ENTER key. This is
  8204.    useful for allowing a user to quickly select the most likely option, the
  8205.    default option, by pressing the ENTER key.
  8206.  
  8207.    BS_HELP  A button with this style posts a WM_HELP message when selected.
  8208.  
  8209.    BS_NOBORDER  A button with this style is drawn without a border.
  8210.  
  8211.    BS_NOPOINTERFOCUS  A button with this style does not receive the focus
  8212.    when selected.
  8213.  
  8214.    BS_PUSHBUTTON  A push button. The button posts a WM_COMMAND message to the
  8215.    owner window when selected.
  8216.  
  8217.    BS_RADIOBUTTON  Similar to a check box, except that it is used in
  8218.    groups of mutually exclusive choices. The owner window is notified with a
  8219.    WM_CONTROL message when a radio button is selected, and changes the
  8220.    state of the selected radio button and all other buttons in the group.
  8221.  
  8222.    BS_SYSCOMMAND  A button with this style posts a WM_SYSCOMMAND message when
  8223.    selected.
  8224.  
  8225.    BS_USERBUTTON  An application-defined button. This style, used in
  8226.    conjunction with other styles, allows the owner window to draw the button
  8227.    control in a highlighted, unhighlighted, enabled, or disabled state. The
  8228.    owner window receives a BN_PAINT message when the button must be drawn.
  8229.  
  8230.  12.5.2  Messages Sent to Button Controls
  8231.  
  8232.    The following messages are sent to button controls:
  8233.  
  8234.    BM_CLICK  The button responds as if it were selected using the mouse or
  8235.    the keyboard. This is useful when simulating a user selection for a
  8236.    particular button.
  8237.  
  8238.    BM_QUERYCHECK  Sent to a check box and radio button. Returns 0 if the
  8239.    button is unselected, 1 if the button state is selected, and 2 if the
  8240.    button state is indeterminate (for example, the grayed state for
  8241.    three-state buttons).
  8242.  
  8243.    BM_QUERYCHECKINDEX  The button responds to this message by setting the
  8244.    result to the zero-based index of the selected radio button in the same
  8245.    group as the sender. Returns -1 if no button in the group is selected or
  8246.    the receiver is not a radio button, or if the radio button has no parent
  8247.    window.
  8248.  
  8249.    BM_QUERYHILITE  For push buttons, returns TRUE if the button is currently
  8250.    highlighted, FALSE otherwise. Returns FALSE if the button receiving the
  8251.    message is not a push button.
  8252.  
  8253.    BM_SETCHECK  Sets the state to unselected, selected, or indeterminate (for
  8254.    three-state buttons) for check boxes and radio buttons. If the button
  8255.    receiving the message also has the style BS_USERBUTTON, a WM_CONTROL
  8256.    message is sent to the button owner telling it to select or unselect the
  8257.    button.
  8258.  
  8259.    BM_SETDEFAULT  Sets or removes the BS_DEFAULT style bit in the receiving
  8260.    button.
  8261.  
  8262.    BM_SETHILITE  Sent to a push button. Sets the state of the button to
  8263.    highlighted or unhighlighted, depending on the parameters supplied with
  8264.    the message. If the button receiving the message has the BS_USERBUTTON
  8265.    style, a WM_CONTROL message is sent to the button owner telling it to
  8266.    highlight or unhighlight the button.
  8267.  
  8268.  12.5.3  Messages Sent from Buttons to Owner Windows
  8269.  
  8270.    The following messages are sent from buttons to their owner windows:
  8271.  
  8272.    WM_COMMAND  Posted from a push button to its owner window when a user
  8273.    selects the button. Additional parameters in the message indicate whether
  8274.    the selection was done using the mouse or the keyboard, although
  8275.    applications generally do not track how the button was selected.
  8276.  
  8277.    WM_CONTROL  Sent from a button control to its owner to indicate that a
  8278.    user has selected the button or when the owner must draw the button.
  8279.    Included in the message is one of the following notification codes:
  8280.  
  8281.    Code              Description
  8282.    ──────────────────────────────────────────────────────────────────────────
  8283.    BN_CLICKED        A user selected the button.
  8284.  
  8285.    BN_DBLCLICKED     A user double-clicked the button.
  8286.  
  8287.    BN_PAINT          Sent from a BS_USERBUTTON button to the owner window
  8288.                      instructing it to draw the button control. The
  8289.                      WM_CONTROL message contains a pointer to a USERBUTTON
  8290.                      structure.
  8291.    ──────────────────────────────────────────────────────────────────────────
  8292.  
  8293.    WM_HELP  Posted instead of the WM_COMMAND message from a push button to
  8294.    its owner window when the button has the BS_HELP style.
  8295.  
  8296.    WM_SYSCOMMAND  Posted instead of the WM_COMMAND message from a push button
  8297.    to its owner window when the button has the style BS_SYSCOMMAND.
  8298.  
  8299.  
  8300.  
  8301.  ────────────────────────────────────────────────────────────────────────────
  8302.  Chapter 13  Entry-Field Controls
  8303.  
  8304.         13.1    Introduction
  8305.         13.2    About Entry-Field Controls
  8306.         13.3    Using Entry-Field Controls in an Application
  8307.             13.3.1    Entry-Field Controls in a Dialog Window
  8308.             13.3.2    Entry-Field Controls in a Client Window
  8309.             13.3.3    Responding to a Message from an Entry-Field Control
  8310.             13.3.4    Changing the State of an Entry-Field Control
  8311.             13.3.5    Communicating with the System Clipboard
  8312.         13.4    Default Entry-Field Behavior
  8313.         13.5    Summary
  8314.             13.5.1    Entry-Field Control Styles
  8315.             13.5.2    Messages Sent to Entry-Field Controls
  8316.             13.5.3    Messages Sent from an Entry-Field to an Owner Window
  8317.  
  8318.  13.1  Introduction
  8319.  
  8320.    This chapter describes the functions that allow you to use entry-field
  8321.    control windows in your applications. You should also be familiar with the
  8322.    following topics:
  8323.  
  8324.    ■  Standard user-interface guidelines
  8325.  
  8326.    ■  System clipboard
  8327.  
  8328.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  8329.  
  8330.    ■  Basic concepts of window messages and the message queue
  8331.  
  8332.  
  8333.  13.2  About Entry-Field Controls
  8334.  
  8335.    An entry-field control is a rectangular window that displays a single line
  8336.    of text a user can edit. When the entry-field control has the focus, it
  8337.    displays a flashing bar to mark the current insertion point. It also
  8338.    allows a user to select text by dragging the mouse or by using the
  8339.    keyboard. Entry-field controls allow applications to provide
  8340.    standard-interface text editing to users for short selections.
  8341.  
  8342.    Users can select a range of text in an entry-field control. Many
  8343.    text-editing operations on the contents of an entry-field control affect
  8344.    the current selection rather than the entire text.
  8345.  
  8346.    Entry-field controls are typically used in dialog windows, although they
  8347.    may be used in non-dialog windows as well. Entry-field control windows are
  8348.    always owned by other windows. The entry-field control window sends
  8349.    notification messages to its owner when it gains or loses the focus, or
  8350.    when its contents change or are scrolled.
  8351.  
  8352.    Entry-field control windows have style bits that determine whether the
  8353.    text is left, center, or right-justified in the window, and whether the
  8354.    text automatically scrolls horizontally, showing the current insertion
  8355.    point. Style bits also control whether entry-fields have borders. These
  8356.    styles are set when the control is created.
  8357.  
  8358.  
  8359.  13.3  Using Entry-Field Controls in an Application
  8360.  
  8361.    Entry-field controls can be used in dialog windows and regular client
  8362.    windows. As part of a dialog window, the entry-field control is defined as
  8363.    part of the dialog template in the application resource file. In a client
  8364.    window, the application creates a window with the window class
  8365.    WC_ENTRYFIELD.
  8366.  
  8367.    Once created, the contents, font, and selection range of the entry-field
  8368.    control can be changed by sending appropriate messages to the entry-field
  8369.    control window. Entry-field controls hold up to 32 characters by default,
  8370.    but applications can expand or reduce this limit, depending on memory
  8371.    limits, once the control is created. Applications can query the current
  8372.    contents or the current selection in an entry-field control.
  8373.  
  8374.    Applications can also transfer text and data between the entry-field
  8375.    control and the system clipboard by using cut, copy, clear, and paste
  8376.    operations. This facility is useful for moving text from an entry-field
  8377.    control to another window or process.
  8378.  
  8379.  13.3.1  Entry-Field Controls in a Dialog Window
  8380.  
  8381.    Entry-field controls are typically used in dialog windows. The dialog
  8382.    window serves as the parent and owner window for the entry-field control.
  8383.    The application dialog procedure receives notification messages from
  8384.    entry-field controls. Generally, a dialog window includes a button that
  8385.    signals that the user wants to carry out an operation. The application
  8386.    ignores most notification messages from an entry-field control, allowing
  8387.    default text editing to occur. When the user selects the button that
  8388.    indicates an operation should begin, the application queries the contents
  8389.    of the entry-field control and proceeds with the operation.
  8390.  
  8391.    To include an entry-field control in a dialog window, include a definition
  8392.    for an entry-field control item in the dialog-template definition in the
  8393.    resource file. The definition sets up the initial text, window ID, size,
  8394.    position, and style of the entry-field control. A sample dialog template
  8395.    containing an entry-field control is shown below.
  8396.  
  8397.    DLGTEMPLATE IDD_SAMPLE
  8398.    {
  8399.    DIALOG "Sample Dialog", 50, 7, 7, 253, 145, FS_DLGBORDER,0
  8400.        {
  8401.            DEFPUSHBUTTON "~Ok", DID_OK, 8, 151, 50, 23, WS_GROUP
  8402.            ENTRYFIELD "Here is some text", ID_ED1, 42, 46, 68, 15,
  8403.                ES_MARGIN | ES_AUTOSCROLL
  8404.        }
  8405.    }
  8406.  
  8407.    Once created as part of a dialog window, the entry-field control sends
  8408.    notification messages to the dialog window. An application handles these
  8409.    messages in its dialog-window procedure.
  8410.  
  8411.    An application communicates with an entry-field control in a dialog window
  8412.    by sending messages to the entry-field control window. The handle of the
  8413.    entry-field control window is obtained by calling the WinWindowFromID
  8414.    function (using the dialog window as the parent window and the window ID
  8415.    for the entry-field control as defined in the dialog template).
  8416.  
  8417.  13.3.2  Entry-Field Controls in a Client Window
  8418.  
  8419.    To have an entry-field control in a non-dialog window, an application
  8420.    calls the WinCreateWindow function with the window class WC_ENTRYFIELD. An
  8421.    application client window owns the entry-field control. The client-window
  8422.    procedure receives notification messages from the entry-field control. The
  8423.    following code fragment shows how to create an entry-field control window
  8424.    in a client window:
  8425.  
  8426.    hwndEntryField = WinCreateWindow(hwndClient,   /* parent    */
  8427.       WC_ENTRYFIELD,                              /* class     */
  8428.       "initial text contents",                    /* text      */
  8429.       WS_VISIBLE | ES_AUTOSCROLL | ES_MARGIN,     /* style     */
  8430.       xPos, yPos,                                 /* x, y      */
  8431.       xSize, ySize,                               /* cx, cy    */
  8432.       hwndClient,                                 /* owner     */
  8433.       HWND_TOP,                                   /* behind    */
  8434.       hwndEntryField,                             /* win ID    */
  8435.       (PVOID) NULL,                               /* ctl data  */
  8436.       (PVOID) NULL);                              /* reserved  */
  8437.  
  8438.    The entry-field control created in the preceding example has a
  8439.    32-character default limit. An application can change this limit by
  8440.    sending an EM_SETTEXTLIMIT message to the control window. The limit can be
  8441.    set to a non-default value at creation by supplying a pointer to an
  8442.    ENTRYFDATA structure as the ctldata parameter to the WinCreateWindow
  8443.    function.
  8444.  
  8445.    The other fields of the ENTRYFDATA structure can be set to specify the
  8446.    selection length and the first visible character at the left edge of the
  8447.    control window. Entry-field control attributes can also be changed by
  8448.    sending messages to the control after it is created. It is not necessary
  8449.    to provide this information in the ENTRYFDATA structure for creation to
  8450.    occur.
  8451.  
  8452.  13.3.3  Responding to a Message from an Entry-Field Control
  8453.  
  8454.    An entry-field control communicates with its owner by sending WM_CONTROL
  8455.    messages. These messages contain notification codes that specify the exact
  8456.    nature of the message. Typically, an application does not respond to
  8457.    notification messages from an entry-field control for default
  8458.    text-editing. For more specialized uses, an application uses notification
  8459.    messages to perform input filtering.
  8460.  
  8461.    For example, if an application has an entry-field control that is intended
  8462.    for entering a number, it can use the EN_CHANGED message to check the
  8463.    contents after each new character is entered. This tells a user that an
  8464.    inappropriate character has been entered.
  8465.  
  8466.    On a deeper level, an application can use the EN_SETFOCUS and EN_KILLFOCUS
  8467.    messages to toggle the input filtering that occurs before the character
  8468.    messages are sent to the entry-field control. An application can use
  8469.    conditional code in its main-event loop to filter incoming WM_CHAR
  8470.    messages whenever the entry-field control has the focus. By intercepting
  8471.    WM_CHAR messages before they are dispatched using the WinDispatchMsg
  8472.    function, an application can prevent inappropriate characters from
  8473.    reaching the entry-field control. You might also want to apply special
  8474.    interpretation to certain keystrokes, such as the ENTER key, as long as
  8475.    the entry-field control has the focus.
  8476.  
  8477.  13.3.4  Changing the State of an Entry-Field Control
  8478.  
  8479.    You can set or retrieve text in an entry-field control window by calling
  8480.    the WinSetWindowText or WinQueryWindowText function. To retrieve the text
  8481.    for the current selection, an application first calls the
  8482.    WinQueryWindowText function to retrieve the contents, and then sends an
  8483.    EM_QUERYSEL message to retrieve the offsets to the first and last
  8484.    character of the text selection. These offsets are used to retrieve
  8485.    selected text from the entire text.
  8486.  
  8487.    Edit fields containing numerical values can be set or queried by calling
  8488.    the WinSetDlgItemShort or WinQueryDlgItemShort function and passing the
  8489.    entry-field ID and the parent window. The WinSetDlgItemShort function
  8490.    converts a signed or unsigned integer into a text string and sets the
  8491.    field text with it. The WinQueryDlgItemShort function converts the
  8492.    entry-field text to a signed or unsigned integer and returns the value in
  8493.    a specified variable.
  8494.  
  8495.    An application can set or query the selection range, although the
  8496.    entry-field control automatically handles selection changes in response to
  8497.    user input in keeping with the standard user-interface guidelines.
  8498.    However, it can be useful to have an application select the entire text
  8499.    prior to cutting or pasting to the system clipboard.
  8500.  
  8501.  13.3.5  Communicating with the System Clipboard
  8502.  
  8503.    Entry-field controls respond to messages designed to simplify transferring
  8504.    data to and from the system clipboard. These messages support the standard
  8505.    cut, copy, clear, and paste operations defined by the standard
  8506.    user-interface guidelines. All clipboard messages for entry-field controls
  8507.    use the CF_TEXT clipboard-data format. See the summary section at the end
  8508.    of this chapter for a description of each message.
  8509.  
  8510.  
  8511.  13.4  Default Entry-Field Behavior
  8512.  
  8513.    This section describes all the messages specifically handled by the
  8514.    predefined entry-field control-window class.
  8515.  
  8516. ╓┌─┌──────────────────────────┌──────────────────────────────────────────────╖
  8517.    Message                    Description
  8518.    ──────────────────────────────────────────────────────────────────────────
  8519.    WM_CREATE                  Validate the requested style and set the window
  8520.                               text.
  8521.  
  8522.    WM_DESTROY                 Free the memory used for the window text.
  8523.  
  8524.    WM_BUTTON1DOWN             Set the mouse capture and keyboard focus to the
  8525.                               entry-field and prepare to track the mouse
  8526.                               during WM_MOUSEMOVE messages.
  8527.  
  8528.    Message                    Description
  8529.    ──────────────────────────────────────────────────────────────────────────
  8530. 
  8531.    WM_BUTTON1DBLCLK           Set the mouse capture and keyboard focus to the
  8532.                               entry-field and prepare to track the mouse
  8533.                               during WM_MOUSEMOVE messages.
  8534.  
  8535.    WM_BUTTON1UP               Release the mouse capture.
  8536.  
  8537.    WM_BUTTON2DOWN             Return TRUE to prevent this message from being
  8538.                               processed further.
  8539.  
  8540.    WM_BUTTON3DOWN             Return TRUE to prevent this message from being
  8541.                               processed further.
  8542.  
  8543.    WM_PAINT                   Draw the entry-field control and text.
  8544.  
  8545.    WM_CHAR                    Handle key events according to the standard
  8546.                               user-interface guidelines.
  8547.  
  8548.    WM_SETSELECTION            Invert the current selection range.
  8549.    Message                    Description
  8550.    ──────────────────────────────────────────────────────────────────────────
  8551.   WM_SETSELECTION            Invert the current selection range.
  8552.  
  8553.    WM_SETFOCUS                If gaining the focus, create a cursor and send
  8554.                               to the owner window a WM_CONTROL message with
  8555.                               the EN_SETFOCUS control code. If losing the
  8556.                               focus, destroy the current cursor and send to
  8557.                               the owner window a WM_CONTROL message with the
  8558.                               control code EN_KILLFOCUS.
  8559.  
  8560.    WM_QUERYDLGCODE            Return the predefined constant DLGC_ENTRYFIELD.
  8561.  
  8562.    WM_QUERYWINDOWPARAMS       Return the requested window parameters.
  8563.  
  8564.    WM_SETWINDOWPARAMS         Set the specified window parameters, redraw the
  8565.                               control, and send to the owner window a
  8566.                               WM_CONTROL message with the EN_CHANGED control
  8567.                               code.
  8568.  
  8569.    WM_MOUSEMOVE               If the mouse button is down, track the text
  8570.    Message                    Description
  8571.    ──────────────────────────────────────────────────────────────────────────
  8572.   WM_MOUSEMOVE               If the mouse button is down, track the text
  8573.                               selection. If the mouse button is up, set the
  8574.                               mouse pointer to the default arrow shape.
  8575.  
  8576.    WM_ENABLE                  Invalidate the entire entry-field control
  8577.                               window, causing a WM_PAINT message to be sent
  8578.                               to the control.
  8579.  
  8580.    WM_TIMER                   Blink the insertion point if the control has
  8581.                               the focus. Scroll the text, if necessary, while
  8582.                               extending a selection to text not visible in
  8583.                               the window.
  8584.  
  8585.    WM_ADJUSTWINDOWPOS         Change the rectangle for the control size to
  8586.                               adjust for the margin if the control has the
  8587.                               ES_MARGIN style.
  8588.  
  8589.    EM_QUERYFIRSTCHAR          Return the offset to the first character
  8590.                               visible at the left edge of the control window.
  8591.    Message                    Description
  8592.    ──────────────────────────────────────────────────────────────────────────
  8593.                              visible at the left edge of the control window.
  8594.  
  8595.    EM_SETFIRSTCHAR            Scrolls the text so that the character at the
  8596.                               specified offset is the first character visible
  8597.                               at the left edge of the control window. Returns
  8598.                               TRUE if successful, or FALSE if it is not.
  8599.  
  8600.    EM_QUERYCHANGED            Returns TRUE if the text has changed since the
  8601.                               last EM_QUERYCHANGED message.
  8602.  
  8603.    EM_QUERYSEL                Returns a long word that contains the offsets
  8604.                               for the first and last characters of the
  8605.                               current selection in the control window.
  8606.  
  8607.    EM_SETSEL                  Sets the current selection to the specified
  8608.                               character offsets.
  8609.  
  8610.    EM_SETTEXTLIMIT            Allocates memory from the control heap for the
  8611.                               specified maximum number of characters,
  8612.    Message                    Description
  8613.    ──────────────────────────────────────────────────────────────────────────
  8614.                              specified maximum number of characters,
  8615.                               returning TRUE if it is successful, FALSE if it
  8616.                               is not. Failure causes a WM_CONTROL message
  8617.                               with the EM_MEMERROR control code to be sent to
  8618.                               the owner window.
  8619.  
  8620.    EM_CUT                     Copies the current text selection to the system
  8621.                               clipboard in CF_TEXT format and deletes the
  8622.                               selection from the control window.
  8623.  
  8624.    EM_COPY                    Copies the current text selection to the system
  8625.                               clipboard in CF_TEXT format.
  8626.  
  8627.    EM_CLEAR                   Deletes the current text selection from the
  8628.                               control window.
  8629.  
  8630.    EM_PASTE                   Copies the current contents of the system
  8631.                               clipboard that have CF_TEXT format, replacing
  8632.                               the current text selection in the control.
  8633.    Message                    Description
  8634.    ──────────────────────────────────────────────────────────────────────────
  8635.                              the current text selection in the control.
  8636.    ──────────────────────────────────────────────────────────────────────────
  8637.  
  8638.  
  8639.  
  8640.  13.5  Summary
  8641.  
  8642.    The following sections describe the styles and messages associated with
  8643.    entry-field controls.
  8644.  
  8645.  13.5.1  Entry-Field Control Styles
  8646.  
  8647.    The following style constants, specified when the entry-field control is
  8648.    created, determine its behavior and appearance:
  8649.  
  8650.    ES_AUTOSCROLL  Scrolls text horizontally to show the current insertion
  8651.    point.
  8652.  
  8653.    ES_CENTER  Displays text centered within the control window.
  8654.  
  8655.    ES_LEFT  Displays text on the left within the control window.
  8656.  
  8657.    ES_MARGIN  Paints a wide border around the control window. The border is
  8658.    one-half characters wide and one-fourth characters high. Without this
  8659.    style, no border is drawn around the control window. The entry-field
  8660.    window rectangle is inflated (outset) on all sides by this margin. After
  8661.    an ES_MARGIN style entry-field is created, the WinQueryWindowRect function
  8662.    returns a larger rectangle, with a different origin than the one specified
  8663.    at creation because it now includes this margin. Note this when moving or
  8664.    sizing an entry-field control or it will become larger after each move or
  8665.    size operation.
  8666.  
  8667.    ES_RIGHT  Displays text on the right within the control window.
  8668.  
  8669.  13.5.2  Messages Sent to Entry-Field Controls
  8670.  
  8671.    This section describes the messages that are specific to entry-field
  8672.    controls:
  8673.  
  8674.    EM_CLEAR  Deletes the current selection in the entry-field control.
  8675.  
  8676.    EM_COPY  Sends the current selection to the system clipboard in CF_TEXT
  8677.    format.
  8678.  
  8679.    EM_CUT  Sends the current selection to the system clipboard in CF_TEXT
  8680.    format and then deletes the selection from the entry-field control.
  8681.  
  8682.    EM_PASTE  Replaces the current selection (or inserts text if the current
  8683.    selection is an insertion point) with text from the system clipboard. No
  8684.    replacement occurs if the clipboard does not contain any CF_TEXT data.
  8685.  
  8686.    EM_QUERYCHANGED  Returns TRUE if the contents of the entry-field control
  8687.    have changed since last receiving a WM_QUERYWINDOWPARAMS or EM_GETCHANGED
  8688.    message; it returns FALSE if the contents have not changed.
  8689.  
  8690.    EM_QUERYFIRSTCHAR  Returns the zero-based byte offset of the first
  8691.    character visible at the left edge of the control window.
  8692.  
  8693.    EM_QUERYSEL  Returns the offsets for the first and last characters of the
  8694.    current selection as the low and high word of the function return value.
  8695.  
  8696.    EM_SETFIRSTCHAR  Displays a character, specified by its zero-based byte
  8697.    offset, as the first character visible at the left edge of the control
  8698.    window, scrolling the text if necessary.
  8699.  
  8700.    EM_SETSEL  Sets the selection range between the supplied first and last
  8701.    character positions. If the first-character position is zero and the
  8702.    last-character position is greater than the number of characters in the
  8703.    control window, the entire text is selected.
  8704.  
  8705.    EM_SETTEXTLIMIT  Sets the maximum number of characters that the
  8706.    entry-field control can hold. It returns TRUE if the operation is
  8707.    successful, or FALSE if there was not enough memory.
  8708.  
  8709.  13.5.3  Messages Sent from an Entry-Field to an Owner Window
  8710.  
  8711.    The following section describes messages that an entry-field control sends
  8712.    to its owner window:
  8713.  
  8714.    WM_CONTROL  Notifies the owner window of a significant change in the
  8715.    control. The low word of the first parameter contains the window ID of the
  8716.    entry-field control window. The high word of the first parameter contains
  8717.    one of the following notification codes:
  8718.  
  8719.    Control code        Description
  8720.    ──────────────────────────────────────────────────────────────────────────
  8721.    EN_CHANGE           Contents of the entry-field control have changed and
  8722.                        the change is displayed on screen.
  8723.  
  8724.    EN_KILLFOCUS        Entry-field control loses the keyboard focus.
  8725.  
  8726.    EN_MEMERROR         Entry-field control cannot allocate enough memory to
  8727.                        perform the requested operation, such as extending the
  8728.                        text limit.
  8729.  
  8730.    EN_SCROLL           Entry-field control is about to scroll horizontally.
  8731.                        This happens when a user enters text beyond the edge
  8732.                        of the entry-field control boundary, requiring the
  8733.                        text to scroll to continue displaying the insertion
  8734.                        point.
  8735.  
  8736.    EN_SETFOCUS         Entry-field control receives the keyboard focus.
  8737.    ──────────────────────────────────────────────────────────────────────────
  8738.  
  8739.  
  8740.  
  8741.  ────────────────────────────────────────────────────────────────────────────
  8742.  Chapter 14  List-Box Controls
  8743.  
  8744.         14.1    Introduction
  8745.         14.2    About List Boxes
  8746.         14.3    Using a List Box in an Application
  8747.             14.3.1    Creating a List-Box Window
  8748.             14.3.2    List Boxes in Dialog Windows
  8749.             14.3.3    Adding and Deleting an Item in a List Box
  8750.             14.3.4    Responding to a User Selection in a List Box
  8751.             14.3.5    Handling Multiple Selections
  8752.             14.3.6    Owner-Drawn List Items
  8753.         14.4    Default List-Box Behavior
  8754.         14.5    Summary
  8755.             14.5.1    List-Box Styles
  8756.             14.5.2    Messages Sent from a List Box to an Owner Window
  8757.             14.5.3    Messages Sent to a List Box
  8758.  
  8759.  14.1  Introduction
  8760.  
  8761.    This chapter describes creating and using list-box control windows in your
  8762.    applications. You should also be familiar with the following topics:
  8763.  
  8764.    ■  Standard user-interface guidelines
  8765.  
  8766.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  8767.  
  8768.    ■  Window messages and message queues
  8769.  
  8770.  
  8771.  14.2  About List Boxes
  8772.  
  8773.    A list box is a control window containing a list of items. Each item
  8774.    contains a text string and a handle. The text string is usually displayed
  8775.    in the list-box window. The handle is available to the application to
  8776.    reference other data associated with the list item.
  8777.  
  8778.    A list-box window must be owned by another window. This ownership
  8779.    relationship is important because the owner window receives messages from
  8780.    the list box when events occur──for example, when a user selects an item
  8781.    from the list box. Typically, the owner window is a client window of an
  8782.    application frame window or a dialog window. The client-window procedure
  8783.    or the dialog-window procedure defined by an application responds to
  8784.    messages sent from the list box.
  8785.  
  8786.    A list box always contains a scroll bar. If the list box contains more
  8787.    items than can be displayed in the list-box window, the scroll bar is
  8788.    enabled. Otherwise, the scroll bar is disabled. The list box responds to
  8789.    clicks in the scroll bar by scrolling the list.
  8790.  
  8791.    The maximum number of items in a list box is 32,767. This limit on
  8792.    list-box items is controlled by the 64K heap-size limit used in storing
  8793.    the list-box items.
  8794.  
  8795.    Figure 14.1 shows a typical list-box control.
  8796.  
  8797.    ┌────────────────────────────────────────────────────────────────────────┐
  8798.    │ Figure 14.1 can be found in Section 14.2 of the printed manual.        │
  8799.    └────────────────────────────────────────────────────────────────────────┘
  8800.  
  8801.    Figure 14.1  Typical List-Box Control
  8802.  
  8803.  
  8804.  14.3  Using a List Box in an Application
  8805.  
  8806.    An application uses a list-box control to display a list in a window. List
  8807.    boxes can be displayed in standard application windows, although they are
  8808.    more commonly used in dialog windows. Either way, notification messages
  8809.    are sent from the list box to the owner window, allowing the application
  8810.    to respond to user actions in the list. In practice, if a list box is
  8811.    owned by a dialog window, messages are handled in dialog-window
  8812.    procedures. If the list box is owned by a client window, notification
  8813.    messages are handled in the client-window procedure.
  8814.  
  8815.    Once a list box is created, the application controls inserting and
  8816.    deleting list items. Items can be inserted at the end of the list,
  8817.    automatically sorted into the list, or inserted at a specified index
  8818.    position. Applications can turn list drawing on and off to speed up the
  8819.    process of inserting numerous items into a list.
  8820.  
  8821.    The window procedure of the owner window of the list box receives messages
  8822.    when a user manipulates the list-box data. Most default list actions (for
  8823.    example, highlighting selections and scrolling) are handled automatically
  8824.    by the list box itself. The application controls the responses when the
  8825.    user chooses an item in the list, either by double-clicking the item or
  8826.    pressing ENTER after an item is highlighted. The application is also
  8827.    notified whenever the selection changes or when the list is scrolled.
  8828.  
  8829.    Normally, list items are text strings drawn by a list box. An application
  8830.    can also draw and highlight the items in a list. This allows customized
  8831.    lists containing graphics or special fonts to be created. When an
  8832.    application creates a list box with the LS_OWNERDRAW style, the owner of
  8833.    the list box receives a WM_DRAWITEM message for each item that should be
  8834.    drawn or highlighted. This is similar to the owner-drawn style for menus,
  8835.    but unlike menus, the owner-drawn style applies to the entire list rather
  8836.    than to individual items.
  8837.  
  8838.  14.3.1  Creating a List-Box Window
  8839.  
  8840.    List boxes are WC_LISTBOX class windows and are predefined by the system.
  8841.    Applications can create list boxes by calling the WinCreateWindow
  8842.    function, using WC_LISTBOX as the window-class parameter.
  8843.  
  8844.    A list box passes notification messages to its owner window, so an
  8845.    application uses its client window, rather than the frame window, as the
  8846.    owner of the list. The client-window procedure receives the messages sent
  8847.    from the list box.
  8848.  
  8849.    For example, to create a list box that completely fills the client area of
  8850.    a frame window, an application would make the client window the owner and
  8851.    parent of the list-box window and make the list-box window the same size
  8852.    as the client window. This is shown in the following code fragment:
  8853.  
  8854.    /* How big is the client window? */
  8855.  
  8856.    WinQueryWindowRect(hwndClient, &rect);
  8857.  
  8858.    /* Make a list-box window. */
  8859.  
  8860.    hwndList = WinCreateWindow(hwndClient,    /* parent       */
  8861.        WC_LISTBOX,                           /* class        */
  8862.        "",                                   /* name         */
  8863.        WS_VISIBLE | LS_NOADJUSTPOS,          /* style        */
  8864.        0, 0,                                 /* x, y         */
  8865.        rect.xRight, rect.yTop,               /* cx, cy       */
  8866.        hwndClient,                           /* owner        */
  8867.        HWND_TOP,                             /* behind       */
  8868.        ID_LISTWINDOW,                        /* ID           */
  8869.        NULL,                                 /* control data */
  8870.        NULL);                                /* parameters   */
  8871.  
  8872.    Because the list box draws its own border and a frame-window border
  8873.    already surrounds the client area of a frame window (because of the
  8874.    adjacent frame controls), the effect is a double-thick border around the
  8875.    list box. To change this, call the WinInflateRect function to overlap the
  8876.    list-box border with the surrounding frame-window border. This results in
  8877.    one list-box border.
  8878.  
  8879.    Notice that the code specifies the list-box window style LS_NOADJUSTPOS.
  8880.    This ensures that the list box is created in exactly the size specified.
  8881.    If the LS_NOADJUSTPOS style is not specified, the list-box height is
  8882.    rounded down, if necessary, to make it a multiple of the item height.
  8883.    Allowing a list box to automatically adjust its height is useful for
  8884.    preventing partial items from being displayed at the bottom of a list box.
  8885.  
  8886.  14.3.2  List Boxes in Dialog Windows
  8887.  
  8888.    List boxes are most commonly used in dialog windows. A list box in a
  8889.    dialog box is a control window, like a push button or an entry field.
  8890.    Typically, the application defines a list box as one item in a dialog
  8891.    template in the resource-definition file, as shown in the following
  8892.    Resource Compiler source-code fragment:
  8893.  
  8894.    DLGTEMPLATE IDD_OPEN
  8895.    BEGIN
  8896.       DIALOG "Open...", IDD_OPEN, 35, 35, 150, 135,
  8897.                FS_DLGBORDER, FCF_TITLEBAR
  8898.          BEGIN
  8899.              LISTBOX        IDD_FILELIST, 15, 15, 90, 90
  8900.              PUSHBUTTON     "Drive", IDD_DRIVEBUTTON, 115, 70, 30, 14
  8901.              DEFPUSHBUTTON  "Open", IDD_OPENBUTTON, 115, 40, 30, 14
  8902.              PUSHBUTTON     "Cancel", IDD_CANCELBUTTON, 115, 15, 30, 14
  8903.          END
  8904.    END
  8905.  
  8906.    Once the dialog resource is defined, the application loads and displays
  8907.    the dialog box as it normally would. The application should insert items
  8908.    into the list when processing the WM_INITDLG message. The dialog-window
  8909.    procedure gets the window handle for the list box by calling the
  8910.    WinWindowFromID function using the list-box ID given in the dialog
  8911.    template. The following code fragment from a dialog-window procedure
  8912.    illustrates this:
  8913.  
  8914.    case WM_INITDLG:
  8915.        hwndList = WinWindowFromID(hwndDialog, IDD_FILELIST);
  8916.            .
  8917.            . /* Now use hwndList to send LM_INSERTITEM messages. */
  8918.            .
  8919.        return 0L;
  8920.  
  8921.    It is very common for a dialog window with a list box to have an OK
  8922.    button. The user may select items in the list and then indicate a final
  8923.    selection by double-clicking, pressing ENTER, or clicking the OK button.
  8924.    When the dialog-window procedure receives a message that the user has
  8925.    clicked the OK button, it should query the list box to determine the
  8926.    current selection (or selections if the list allows multiple selections)
  8927.    and then respond as if it received a WM_CONTROL message with the LN_ENTER
  8928.    notification code.
  8929.  
  8930.  14.3.3  Adding and Deleting an Item in a List Box
  8931.  
  8932.    Applications can add or delete items in a list box by sending
  8933.    LM_INSERTITEM and LM_DELETEITEM messages to the list-box window. Items in
  8934.    a list are specified with a zero-based index (beginning at the top of the
  8935.    list). A new list is always created empty. The application must initialize
  8936.    the list by inserting items.
  8937.  
  8938.    The application specifies the text and position for each new item. It can
  8939.    specify an absolute-position index or one of the following predefined
  8940.    index values:
  8941.  
  8942.    Value                              Meaning
  8943.    ──────────────────────────────────────────────────────────────────────────
  8944.    LIT_END                            Insert item at end of list.
  8945.  
  8946.    LIT_SORTASCENDING                  Insert item alphabetically ascending
  8947.                                       into list.
  8948.  
  8949.    LIT_SORTDESCENDING                 Insert item alphabetically descending
  8950.                                       into list.
  8951.    ──────────────────────────────────────────────────────────────────────────
  8952.  
  8953.    The application must send an LM_DELETEITEM message and supply the absolute
  8954.    index position of the item when deleting items from a list. The
  8955.    LM_DELETEALL message deletes all items in a list.
  8956.  
  8957.    One way an application can speed up the process of inserting list items is
  8958.    to suspend drawing in the list while inserting items. The list is redrawn
  8959.    after the insertion process is finished. This is a particularly valuable
  8960.    approach when using a sorted insertion process, when inserting one item
  8961.    can cause rearrangement of the entire list. List drawing is turned off by
  8962.    calling the WinEnableWindowUpdate function with FALSE for the enable
  8963.    parameter, and then calling the WinShowWindow function. This forces a
  8964.    complete update when insertion is complete. The following code fragment
  8965.    illustrates this concept:
  8966.  
  8967.    /* Disable updates while filling the list. */
  8968.  
  8969.    WinEnableWindowUpdate(hwndFileList, FALSE);
  8970.        .
  8971.        . /* Send LM_INSERTITEM messages to insert all new items. */
  8972.        .
  8973.  
  8974.    /* Now cause the window to update and show the new information. */
  8975.  
  8976.    WinShowWindow(hwndFileList, TRUE);
  8977.  
  8978.    Note that this optimization is not necessary if adding list items when
  8979.    processing a WM_INITDLG message because the list box is not visible and
  8980.    the list-box routines are internally optimized.
  8981.  
  8982.  14.3.4  Responding to a User Selection in a List Box
  8983.  
  8984.    The primary notification an application receives when a user chooses an
  8985.    item in a list is a WM_CONTROL message with the LN_ENTER control code sent
  8986.    to the owner window of the list. The owner window is an application client
  8987.    window or a dialog window. Within the window procedure for the owner
  8988.    window, the application responds to the LN_ENTER control code by querying
  8989.    the list box for the current selection (or selections, in the case of an
  8990.    LS_MULTIPLESEL list box).
  8991.  
  8992.    The LN_ENTER control code notifies the application that the user has
  8993.    selected a list item. A WM_CONTROL message with an LN_SELECT control code
  8994.    is sent to the list-box owner whenever a selection in a list changes, such
  8995.    as when a user moves the mouse pointer up and down a list while pressing
  8996.    the mouse button. In this case, items are selected but not yet chosen. An
  8997.    application may ignore LN_SELECT control codes when the selection changes,
  8998.    responding only when the item is actually chosen. An application might use
  8999.    the LN_SELECT control code to display context-dependent information that
  9000.    changes rapidly with each selection made by the user.
  9001.  
  9002.  14.3.5  Handling Multiple Selections
  9003.  
  9004.    When a list box has the style LS_MULTIPLESEL, more than one item may be
  9005.    selected at a time. An application must use different strategies when
  9006.    working with this type of list. For example, when responding to an
  9007.    LN_ENTER control code, it is not sufficient to send a single
  9008.    LM_QUERYSELECTION message because that message will find only the first
  9009.    selection. To find all current selections, an application should continue
  9010.    sending LM_QUERYSELECTION messages, using the return index of the previous
  9011.    message as the starting index of the next message, until no items are
  9012.    returned.
  9013.  
  9014.  14.3.6  Owner-Drawn List Items
  9015.  
  9016.    To draw its own list items, an application must create a list that has the
  9017.    style LS_OWNERDRAW. The owner window of the list box must respond to the
  9018.    WM_MEASUREITEM and WM_DRAWITEM messages.
  9019.  
  9020.    When the owner window receives a WM_MEASUREITEM message, it must return
  9021.    the height of the list item. All items in a list must have the same height
  9022.    (greater than or equal to 1). The WM_MEASUREITEM message is sent only
  9023.    once, when the list box is created. You can change the item height by
  9024.    sending an LM_SETITEMHEIGHT message to the list-box window.
  9025.  
  9026.    The owner window receives a WM_DRAWITEM message whenever an item in an
  9027.    owner-drawn list should be drawn or highlighted. The owner window returns
  9028.    FALSE if the list box must draw the text of the item. The owner window
  9029.    returns TRUE if it actually draws the item. This tells the list box not to
  9030.    draw the item. This is useful if the owner window alters the appearance of
  9031.    certain items, allowing other items to be drawn by the list box.
  9032.  
  9033.    Although it is quite common for an owner-drawn list to draw items, it is
  9034.    less common to override the system-default method of highlighting. (The
  9035.    system-default highlighting method inverts the rectangle that contains the
  9036.    item.) Do not create your own highlighting unless the system-default
  9037.    method is unacceptable to you.
  9038.  
  9039.    The WM_DRAWITEM message contains a pointer to an OWNERITEM data structure.
  9040.    The OWNERITEM data structure contains the window ID for the list box, a
  9041.    presentation-space handle, a bounding rectangle for the item, the position
  9042.    index for the item, and the application-defined item handle. This
  9043.    structure also contains two fields that determine if a message draws,
  9044.    highlights, or removes the highlighting from an item. The OWNERITEM data
  9045.    structure has the following form:
  9046.  
  9047.    typedef struct _OWNERITEM {
  9048.        HWND    hwnd;
  9049.        HPS     hps;
  9050.        USHORT  fsState;
  9051.        USHORT  fsAttribute;
  9052.        USHORT  fsStateOld;
  9053.        USHORT  fsAttributeOld;
  9054.        RECTL   rclItem;
  9055.        SHORT   idItem;
  9056.        ULONG   hItem;
  9057.    } OWNERITEM;
  9058.  
  9059.    When the item must be drawn, the owner window receives a WM_DRAWITEM
  9060.    message with the fsState field set differently than the fsStateOld field.
  9061.    If the owner window draws the item in response to this message, it returns
  9062.    TRUE, telling the system not to draw the item. If the owner window returns
  9063.    FALSE, the system draws the item using the default list-item drawing
  9064.    method.
  9065.  
  9066.    You can get the text of a list item by sending an LM_QUERYITEMTEXT message
  9067.    to the list-box window. You should draw the item using the hps and rclItem
  9068.    arguments provided in the OWNERITEM structure.
  9069.  
  9070.    If the item being drawn is currently selected, then the fsState and
  9071.    fsStateOld fields will both be TRUE; they will both be FALSE if the item
  9072.    is not currently selected. The window receiving a WM_DRAWITEM message can
  9073.    use this information to highlight the selected item at the same time it
  9074.    draws the item. If the owner window highlights the item, it should leave
  9075.    the fsState and fsStateOld fields equal to each other. If the system
  9076.    provides default highlighting for the item (by inverting the item
  9077.    rectangle), the owner window should set the fsState field to 1 and the
  9078.    fsStateOld field to 0 before returning from the WM_DRAWITEM message.
  9079.  
  9080.    The owner window also receives a WM_DRAWITEM message when the highlight
  9081.    state of a list item changes. For example, when a user clicks an item, the
  9082.    highlighting must be removed from the currently selected item and the new
  9083.    selection must be highlighted. If these items are owner-drawn, then the
  9084.    owner window receives one WM_DRAWITEM message for each unhighlighted item
  9085.    and one message for the newly highlighted item. To highlight an item, the
  9086.    fsState field must equal TRUE and the fsStateOld field must equal FALSE.
  9087.    In this case, the application should highlight the item and return the
  9088.    fsState and fsStateOld fields equal to FALSE. This tells the system not to
  9089.    highlight the item. The application can also return the fsState and
  9090.    fsStateOld fields with two different values (not equal) and the list box
  9091.    will highlight the item (the default).
  9092.  
  9093.    To remove highlighting from an item, the fsState field must equal FALSE
  9094.    and the fsStateOld field must equal TRUE. An application can remove the
  9095.    highlighting and return both the fsState and fsStateOld fields as FALSE,
  9096.    or it can return the fsState field with a value that is not equal to the
  9097.    fsStateOld field and the system will remove the highlighting (the
  9098.    default).
  9099.  
  9100.    The following code fragment shows these selection processes:
  9101.  
  9102.    case WM_DRAWITEM:
  9103.  
  9104.        /* Test to see if this is drawing or highlighting/unhighlighting. */
  9105.  
  9106.        if (((POWNERITEM) mp2)->fsState !=
  9107.                ((POWNERITEM) mp2)->fsStateOld) {
  9108.  
  9109.            /* This is either highlighting or unhighlighting. */
  9110.  
  9111.            if (((POWNERITEM) mp2)->fsState) {
  9112.                .
  9113.                . /* Highlight the item. */
  9114.                .
  9115.            } else {
  9116.                .
  9117.                . /* Remove the highlighting.*/
  9118.                .
  9119.            }
  9120.            /* Set fsState = fsStateOld to tell system you did it. */
  9121.  
  9122.            ((POWNERITEM) mp2)->fsState =
  9123.                ((POWNERITEM) mp2)->fsStateOld = 0;
  9124.  
  9125.            return (TRUE); /* Tells list box you did the highlighting. */
  9126.  
  9127.        } else {
  9128.            .
  9129.            . /* Draw the item. */
  9130.            .
  9131.  
  9132.            /* Check to see if item is selected. */
  9133.  
  9134.            if (((POWNERITEM) mp2)->fsState) {
  9135.                .
  9136.                . /* Highlight the item. */
  9137.                .
  9138.  
  9139.                /* Set fsState = fsStateOld to tell system you did it. */
  9140.  
  9141.                ((POWNERITEM) mp2)->fsState =
  9142.                    ((POWNERITEM) mp2) ->fsStateOld = 0;
  9143.           }
  9144.           return (TRUE); /* Tells list box you did the drawing. */
  9145.        }
  9146.  
  9147.  
  9148.  14.4  Default List-Box Behavior
  9149.  
  9150.    This section lists all the messages handled by the predefined list-box
  9151.    window-class procedure.
  9152.  
  9153. ╓┌─┌──────────────────────────┌──────────────────────────────────────────────╖
  9154.    Message                    Description
  9155.    ──────────────────────────────────────────────────────────────────────────
  9156.    WM_CREATE                  Creates an empty list box with a scroll bar.
  9157.  
  9158.    Message                    Description
  9159.    ──────────────────────────────────────────────────────────────────────────
  9160. 
  9161.    WM_DESTROY                 Destroys the list and deallocates any memory
  9162.                               allocated during its existence.
  9163.  
  9164.    WM_PAINT                   Draws the list box and its items.
  9165.  
  9166.    WM_CHAR                    Processes virtual keys for line and page
  9167.                               scrolling. Sends an LN_ENTER notification code
  9168.                               for the ENTER key. Returns TRUE if the key is
  9169.                               processed; otherwise, passes the message to the
  9170.                               WinDefWindowProc function.
  9171.  
  9172.    WM_SETFOCUS                If gaining the focus, creates a cursor and
  9173.                               sends an LN_SETFOCUS notication code to the
  9174.                               owner window. If losing the focus, destroys the
  9175.                               cursor and sends an LN_KILLFOCUS notification
  9176.                               code to the owner window.
  9177.  
  9178.    WM_ADJUSTWINDOWPOS         If the list box has the style LS_NOADJUSTPOS,
  9179.    Message                    Description
  9180.    ──────────────────────────────────────────────────────────────────────────
  9181.   WM_ADJUSTWINDOWPOS         If the list box has the style LS_NOADJUSTPOS,
  9182.                               makes no changes to the SWP structure and
  9183.                               returns FALSE. Otherwise, adjusts the height of
  9184.                               the list box so that a partial item is not
  9185.                               shown at the bottom of the list. Returns TRUE
  9186.                               if the SWP structure is changed.
  9187.  
  9188.    WM_ENABLE                  Enables the scroll bar if there are more items
  9189.                               than can be displayed in a list window.
  9190.  
  9191.    WM_TIMER                   Uses timers to control automatic scrolling that
  9192.                               occurs when a user drags the mouse pointer
  9193.                               outside the window.
  9194.  
  9195.    WM_BUTTON2DOWN             Returns TRUE; the message is ignored.
  9196.  
  9197.    WM_BUTTON3DOWN             Returns TRUE; the message is ignored.
  9198.  
  9199.    WM_MOUSEMOVE               Sets the mouse pointer to the arrow shape and
  9200.    Message                    Description
  9201.    ──────────────────────────────────────────────────────────────────────────
  9202.   WM_MOUSEMOVE               Sets the mouse pointer to the arrow shape and
  9203.                               returns TRUE to show that the message was
  9204.                               processed.
  9205.  
  9206.    WM_VSCROLL                 Handles scrolling indicated by the list-box
  9207.                               scroll bar.
  9208.  
  9209.    LM_QUERYITEMCOUNT          Returns the number of items in the list.
  9210.  
  9211.    LM_INSERTITEM              Inserts a new item in the list according to the
  9212.                               position information passed with the message.
  9213.  
  9214.    LM_SETTOPINDEX             Shows the specified item as the top item in the
  9215.                               list window, scrolling the list as necessary.
  9216.  
  9217.    LM_QUERYTOPINDEX           Returns the zero-based index to the item
  9218.                               currently visible at the top of the list.
  9219.  
  9220.    LM_DELETEITEM              Removes the specified item from the list,
  9221.    Message                    Description
  9222.    ──────────────────────────────────────────────────────────────────────────
  9223.   LM_DELETEITEM              Removes the specified item from the list,
  9224.                               redrawing the list as necessary. Returns the
  9225.                               number of items remaining in the list.
  9226.  
  9227.    LM_SELECTITEM              Selects the specified item. If the list is a
  9228.                               single-selection list, deselects the previous
  9229.                               selection. Sends a WM_CONTROL message (with the
  9230.                               LN_SELECT code) to the owner window.
  9231.  
  9232.    LM_QUERYSELECTION          For a single-selection list box, returns the
  9233.                               zero-based index of the currently selected
  9234.                               item. For multiple-selection list boxes,
  9235.                               returns the next selected item or LIT_NONE if
  9236.                               no more items are selected.
  9237.  
  9238.    LM_SETITEMTEXT             Sets the text for the specified item.
  9239.  
  9240.    LM_QUERYITEMTEXTLENGTH     Returns the length of the specified item text.
  9241.  
  9242.    Message                    Description
  9243.    ──────────────────────────────────────────────────────────────────────────
  9244. 
  9245.    LM_QUERYITEMTEXT           Copies the specified item's text to a buffer
  9246.                               supplied by the message sender.
  9247.  
  9248.    LM_SETITEMHANDLE           Sets the specified item handle.
  9249.  
  9250.    LM_QUERYITEMHANDLE         Returns the specified item handle.
  9251.  
  9252.    LM_SEARCHSTRING            Searches the list for a match to the specified
  9253.                               string.
  9254.  
  9255.    LM_SETITEMHEIGHT           Sets the item height for the list. All items in
  9256.                               the list have the same height.
  9257.  
  9258.    LM_DELETEALL               Deletes all items in the list.
  9259.    ──────────────────────────────────────────────────────────────────────────
  9260.  
  9261.  
  9262.  
  9263.  14.5  Summary
  9264.  
  9265.    List boxes are control windows that have style bits and that can send and
  9266.    receive messages. These styles and messages are listed in the following
  9267.    sections.
  9268.  
  9269.  14.5.1  List-Box Styles
  9270.  
  9271.    The style of a list box determines how it displays its items and how it
  9272.    responds to user input. The following styles are used by list boxes:
  9273.  
  9274.    LS_MULTIPLESEL  Allows more than one list item to be selected at a time.
  9275.  
  9276.    LS_NOADJUSTPOS  Automatically adjusts the list-box height (by default) so
  9277.    that it is a multiple of the item height. This is done so that a list box
  9278.    will not display a partial item at the bottom of the list. The size of the
  9279.    list box can be different than the size specified by the application that
  9280.    created it. The style LS_NOADJUSTPOS tells the list box not to adjust the
  9281.    height of window in response to a WM_SIZE message. Applications that need
  9282.    absolute control over list-box size should use the LS_NOADJUSTPOS style
  9283.    (for example, when a list box needs to completely fill a client area).
  9284.    This style may cause items at the bottom of the box to be displayed
  9285.    partially.
  9286.  
  9287.    LS_OWNERDRAW  Causes the owner window to receive a WM_DRAWITEM message
  9288.    each time an item must be drawn or highlighted.
  9289.  
  9290.  14.5.2  Messages Sent from a List Box to an Owner Window
  9291.  
  9292.    Messages sent from a list box to an owner window notify the owner of
  9293.    events in the list box, such as when a user selects an item. The following
  9294.    messages are sent from list boxes to owner windows:
  9295.  
  9296.    WM_CONTROL  Sent to the owner window of the list box when a user event
  9297.    occurs in the list box. This message contains a control code that notifies
  9298.    the owner that an event occurred and indicates the type of event. The
  9299.    following are possible control codes:
  9300.  
  9301.    Code          Description
  9302.    ──────────────────────────────────────────────────────────────────────────
  9303.    LN_ENTER      Sent to the owner window when the user presses ENTER or
  9304.                  double-clicks an item while the list box has the focus. This
  9305.                  code indicates that the user has chosen an item. The owner
  9306.                  window may then query the current selection and respond
  9307.                  accordingly.
  9308.  
  9309.    LN_KILLFOCUS  Sent to the owner window when the list box loses the focus.
  9310.  
  9311.    LN_SCROLL     Sent to the owner window when the list box scrolls.
  9312.  
  9313.    LN_SELECT     Sent to the owner window when a different item in the list
  9314.                  is selected. The owner window can use this code to query the
  9315.                  current selection and respond accordingly.
  9316.  
  9317.    LN_SETFOCUS   Sent to the owner window when the list box receives the
  9318.                  focus.
  9319.    ──────────────────────────────────────────────────────────────────────────
  9320.  
  9321.    WM_DRAWITEM  Sent to the owner window of a list box with the style
  9322.    LS_OWNERDRAW each time an item must be drawn. The owner window should
  9323.    return TRUE if it actually draws the item; otherwise, it should return
  9324.    FALSE. If the item contains text, the owner window can return FALSE and
  9325.    the list box will draw the item. This message allows the owner window to
  9326.    draw the item or allows default text drawing by the list box. This message
  9327.    contains a structure with a presentation space and a bounding rectangle in
  9328.    which to draw the item. It is also sent when an item must be highlighted.
  9329.    The owner window can handle the highlighting or indicate that the list box
  9330.    should handle this process.
  9331.  
  9332.    WM_MEASUREITEM  This message is sent to the owner window of a list box
  9333.    that has the style LS_OWNERDRAW. The owner window returns a value that is
  9334.    the height of an item in the list. Note that all items in a list must have
  9335.    the same height and that this must be greater than or equal to 1. It is
  9336.    not necessary to specify the width of an item since the item is clipped to
  9337.    the width of the list box when drawn.
  9338.  
  9339.  14.5.3  Messages Sent to a List Box
  9340.  
  9341.    Messages sent to a list box set or query the list data. The following
  9342.    messages are sent to list-box controls:
  9343.  
  9344.    LM_DELETEALL  Deletes all items in the list.
  9345.  
  9346.    LM_DELETEITEM  Deletes a specified item from the list.
  9347.  
  9348.    LM_INSERTITEM  Inserts an item in the list box. Items can be inserted at a
  9349.    specified index, at the beginning or the end, or sorted in ascending or
  9350.    descending order.
  9351.  
  9352.    LM_QUERYITEMCOUNT  Returns the number of items in the list box.
  9353.  
  9354.    LM_QUERYITEMHANDLE  Returns the item handle for the specified item.
  9355.  
  9356.    LM_QUERYITEMTEXT  Copies the text for a specified item into a buffer
  9357.    provided by the caller. The size of the required buffer can be determined
  9358.    by sending an LM_QUERYITEMTEXTLENGTH message for the item.
  9359.  
  9360.    LM_QUERYITEMTEXTLENGTH  Returns the length of the text for a specified
  9361.    item in the list.
  9362.  
  9363.    LM_QUERYSELECTION  Returns the index of the selected item in the list or
  9364.    LIT_NONE if no item is selected. In a multiple selection list, this
  9365.    message returns the first selected item, starting at a specified index.
  9366.  
  9367.    LM_QUERYTOPINDEX  Returns the index of the item currently displayed at the
  9368.    top of the list-box window or LIT_NONE if the list is empty.
  9369.  
  9370.    LM_SEARCHSTRING  Searches the list for a match with the specified string,
  9371.    returning the first matching item. Match criteria can be set using flags
  9372.    for case sensitivity and substring matching. Another parameter allows the
  9373.    search to start at a specified index, allowing iterative searches to start
  9374.    from the previous matching item.
  9375.  
  9376.    LM_SELECTITEM  Sets the selection state of a specified item. If the list
  9377.    box allows only a single selection, the previous selection is deselected.
  9378.    An index of LIT_NONE deselects all items in the list. Sending an
  9379.    LM_SELECTITEM message with LIT_NONE set to a multiple-selection list box
  9380.    does not deselect anything. However, it does remove the cursor.
  9381.  
  9382.    LM_SETITEMHANDLE  Sets the item handle for the specified item.
  9383.  
  9384.    LM_SETITEMHEIGHT  Sets the height of all items in the list, redrawing the
  9385.    list box and all visible items.
  9386.  
  9387.    LM_SETITEMTEXT  Sets the text of a specified item in the list.
  9388.  
  9389.    LM_SETTOPINDEX  Displays a specified item at the top of the list box,
  9390.    scrolling the list as necessary.
  9391.  
  9392.  
  9393.  
  9394.  ────────────────────────────────────────────────────────────────────────────
  9395.  Chapter 15  Static Controls
  9396.  
  9397.         15.1    Introduction
  9398.         15.2    About Static Controls
  9399.         15.3    Using Static Controls in an Application
  9400.             15.3.1    Static Controls in a Dialog Window
  9401.             15.3.2    Static Controls in Client Windows
  9402.             15.3.3    Changing the Static-Control Handle
  9403.         15.4    Default Static-Control Behavior
  9404.         15.5    Summary
  9405.             15.5.1    Static-Control Styles
  9406.             15.5.2    Messages Sent to Static Controls
  9407.  
  9408.  15.1  Introduction
  9409.  
  9410.    This chapter describes how to use static control windows in your
  9411.    applications. You should already be familiar with the following topics:
  9412.  
  9413.    ■  Standard user-interface guidelines
  9414.  
  9415.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  9416.  
  9417.    ■  Window messages and message queues
  9418.  
  9419.  
  9420.  15.2  About Static Controls
  9421.  
  9422.    Static controls are simple text fields, bitmaps, or icons that can be used
  9423.    to label, enclose, or separate other control windows. Static controls do
  9424.    not accept user input and they do not send notification messages to their
  9425.    owners.
  9426.  
  9427.    Static controls have style bits that determine whether the control
  9428.    displays text, draws a simple box containing text, displays an icon or a
  9429.    bitmap, or shows framed or unframed colored boxes. The various styles for
  9430.    static controls are discussed individually in Section 15.5.
  9431.  
  9432.    Static text controls are most commonly used in dialog windows as labels.
  9433.    Iconic and bitmap static controls can be used to provide graphic objects
  9434.    in dialog windows. One advantage of static controls is that, once created,
  9435.    they provide labels and graphics and require little attention from an
  9436.    application.
  9437.  
  9438.    Static controls never accept the keyboard focus. When a static control
  9439.    receives a WM_SETFOCUS message, or when a user clicks a static control,
  9440.    that control advances the focus to the next sibling window that is not a
  9441.    static control. If there are no sibling windows to the static control, the
  9442.    focus is given to the owner of the static control.
  9443.  
  9444.  
  9445.  15.3  Using Static Controls in an Application
  9446.  
  9447.    Static controls can be used in dialog windows and client windows. There is
  9448.    usually very little interaction between an application and the static
  9449.    control once the control is created. However, an application can change
  9450.    the state of the static control.
  9451.  
  9452.    Static controls also are associated with a long-word handle which may be
  9453.    set and queried by an application. By default, icon and bitmap static
  9454.    controls use this handle to contain a handle to their display object.
  9455.    Applications can modify this handle by using the SM_SETHANDLE and
  9456.    SM_QUERYHANDLE messages to change static-control appearance.
  9457.  
  9458.  15.3.1  Static Controls in a Dialog Window
  9459.  
  9460.    Static controls are most commonly used as labels and separators in dialog
  9461.    windows. As such, they are defined as part of a dialog template in the
  9462.    application resource file. Once the dialog window is displayed, the static
  9463.    controls do not interact with the application unless the application
  9464.    changes their state. Typically, an application might change the text or
  9465.    position of a static control. These operations are achieved by using the
  9466.    WinSetWindowText and WinSetWindowPos functions.
  9467.  
  9468.    When defining icon or bitmap static controls in a dialog template, the
  9469.    text for the control is interpreted as the resource ID of the bitmap or
  9470.    the icon. There are two ways that the text can be interpreted. If the
  9471.    first byte is '#', the rest of the text is assumed to be an ASCII decimal
  9472.    representation of the icon-or bitmap-resource ID. If the first byte of the
  9473.    text is 0xFF, the second byte is the low byte of the resource ID, and the
  9474.    third byte is the high byte of the resource ID. The following are two
  9475.    sample Resource Compiler definitions:
  9476.  
  9477.    CONTROL "#256",ID_ICON1, 140, 20, 0, 0, WC_STATIC,
  9478.        SS_ICON | WS_VISIBLE
  9479.  
  9480.    CONTROL 0xFF000100, ID_ICON2, 140, 20, 0, 0, WC_STATIC,
  9481.        SS_ICON | WS_VISIBLE
  9482.  
  9483.    Each definition specifies an SS_ICON static control that uses an icon with
  9484.    resource ID 256 (0x0100). The icon is assumed to be in the current
  9485.    application resource file.
  9486.  
  9487.    The window handle for a static-control window can be obtained by calling
  9488.    the WinWindowFromID function using the dialog-window handle and the window
  9489.    ID of the static control as defined in the dialog template.
  9490.  
  9491.  15.3.2  Static Controls in Client Windows
  9492.  
  9493.    Applications can create static-control windows in non-dialog windows by
  9494.    calling the WinCreateWindow function with a WC_STATIC window class. The
  9495.    appearance of the control is defined by the style parameter to the
  9496.    WinCreateWindow function.
  9497.  
  9498.    If the application creates a control with SS_ICON or SS_BITMAP style, it
  9499.    must ensure that the resource ID specified by the window text corresponds
  9500.    to an actual resource in the application resource file or the static
  9501.    control will not be created.
  9502.  
  9503.    Once created, the static-control window can be moved and sized just like
  9504.    any other child window. An application can obtain the window handle of the
  9505.    static control by calling the WinWindowFromID function, supplying the
  9506.    parent window and the window ID of the static control.
  9507.  
  9508.  15.3.3  Changing the Static-Control Handle
  9509.  
  9510.    The static-window handle contains a handle to an icon or bitmap. Applica-
  9511.    tions can query and set this handle by using the SM_QUERYHANDLE and
  9512.    SM_SETHANDLE messages. Setting the handle causes the static item to be
  9513.    redrawn, so the handle must be a valid icon or bitmap handle.
  9514.  
  9515.    For non-icon and non-bitmap static-control items, the handle is available
  9516.    for use by the application and has no effect on the appearance of the
  9517.    control.
  9518.  
  9519.  
  9520.  15.4  Default Static-Control Behavior
  9521.  
  9522.    This section describes all the messages specifically handled by the
  9523.    predefined static-control class.
  9524.  
  9525. ╓┌─┌───────────────────────────┌─────────────────────────────────────────────╖
  9526.    Message                     Description
  9527.    ──────────────────────────────────────────────────────────────────────────
  9528.    WM_PAINT                    Draws the static control based on its style
  9529.                                attributes.
  9530.  
  9531.    WM_CREATE                   Sets the window text for static-text controls.
  9532.                                Loads the bitmap or icon resource for the
  9533.                                bitmap or icon static controls. Returns TRUE
  9534.                                if the resource cannot be loaded.
  9535.  
  9536.    Message                     Description
  9537.    ──────────────────────────────────────────────────────────────────────────
  9538. 
  9539.    WM_DESTROY                  Frees the text for static-text controls.
  9540.                                Destroys the bitmap or icon for the bitmap and
  9541.                                icon static controls. The icon for a sysicon
  9542.                                static control is not destroyed, because it
  9543.                                belongs to the system.
  9544.  
  9545.    WM_ADJUSTWINDOWPOS          Adjusts the SWP structure so that the new
  9546.                                window size matches the bitmap, icon, or
  9547.                                sysicon dimensions associated with the
  9548.                                control.
  9549.  
  9550.    WM_QUERYWINDOWPARAMS        Returns the requested window parameters.
  9551.  
  9552.    WM_SETWINDOWPARAMS          Allows the window text to be set for
  9553.                                static-text controls only.
  9554.  
  9555.    WM_ENABLE                   Invalidates the entire control window, forcing
  9556.                                it to be redrawn.
  9557.    Message                     Description
  9558.    ──────────────────────────────────────────────────────────────────────────
  9559.                               it to be redrawn.
  9560.  
  9561.    WM_QUERYDLGCODE             Returns the predefined constant DLGC_STATIC.
  9562.  
  9563.    WM_MOUSEMOVE                Sets the mouse pointer to the arrow pointer
  9564.                                and returns TRUE.
  9565.  
  9566.    WM_SETFOCUS                 Sets the focus to the next sibling window that
  9567.                                can accept the focus, or if no such sibling
  9568.                                exists, it sets the focus to the parent
  9569.                                window.
  9570.  
  9571.    SM_SETHANDLE                Sets the handle associated with the static
  9572.                                control and invalidates the control window,
  9573.                                forcing it to be redrawn.
  9574.  
  9575.    SM_QUERYHANDLE              Returns the handle associated with the
  9576.                                static-control window.
  9577.  
  9578.    Message                     Description
  9579.    ──────────────────────────────────────────────────────────────────────────
  9580. 
  9581.    WM_MATCHMNEMONIC            Returns TRUE if the mnemonic passed in the mp1
  9582.                                parameter matches the mnemonic in the
  9583.                                control-window text.
  9584.  
  9585.    WM_HITTEST                  Returns HT_TRANSPARENT for the following
  9586.                                static control styles: SS_GROUPBOX,
  9587.                                SS_FGNDRECT, SS_HALFTONERECT, SS_BKGNDRECT,
  9588.                                SS_FGNDFRAME, SS_HALFTONEFRAME, SS_BKGNDFRAME.
  9589.                                For other styles, returns the WinDefWindowProc
  9590.                                function.
  9591.    ──────────────────────────────────────────────────────────────────────────
  9592.  
  9593.  
  9594.  
  9595.  15.5  Summary
  9596.  
  9597.    The following sections describe the styles and messages associated with
  9598.    static-control windows.
  9599.  
  9600.  15.5.1  Static-Control Styles
  9601.  
  9602.    The following styles are associated with static-control windows:
  9603.  
  9604.    SS_BITMAP  Draws a bitmap. The resource ID for the bitmap resource is
  9605.    determined in the same way as for SS_ICON controls. The bitmap resource is
  9606.    assumed to be in the current application resource file.
  9607.  
  9608.    SS_BKGNDFRAME  Draws a rectangular frame with the current background
  9609.    color.
  9610.  
  9611.    SS_BKGNDRECT  Draws a filled rectangle with the current background color.
  9612.  
  9613.    SS_FGNDFRAME  Draws a rectangular frame with the current foreground color.
  9614.  
  9615.    SS_FGNDRECT  Draws a filled rectangle with the current foreground color.
  9616.  
  9617.    SS_GROUPBOX  Draws a box with control text in the upper-right corner of
  9618.    the box. This style is useful for enclosing groups of radio buttons or
  9619.    check boxes in a box.
  9620.  
  9621.    SS_HALFTONEFRAME  Draws a rectangular frame with a halftone pattern in the
  9622.    current foreground color.
  9623.  
  9624.    SS_HALFTONERECT  Draws a filled rectangle with a halftone pattern in the
  9625.    current foreground color.
  9626.  
  9627.    SS_ICON  Draws an icon. The text of the control is interpreted as the
  9628.    resource ID of the icon. The bytes that make up the text can be
  9629.    interpreted as numeric values or as ASCII representations of numbers,
  9630.    depending on the value of the first byte. If the first byte is '#', the
  9631.    remaining text is assumed to be an ASCII decimal representation of the
  9632.    icon resource ID. If the first byte of the text is 0xFF, the second byte
  9633.    is the low byte of the resource ID and the third byte is the high byte of
  9634.    the resource ID.
  9635.  
  9636.    SS_SYSICON  Displays a system pointer icon. The ID of the icon is
  9637.    extracted from the control text, as in the SS_ICON style. To display this
  9638.    icon, the system calls the WinQuerySysPointer function with the specified
  9639.    ID.
  9640.  
  9641.    SS_TEXT  Allows various formatting options to be combined with the SS_TEXT
  9642.    style to produce formatted text in the boundaries of the control. The
  9643.    formatting option flags are the same as those used for the WinDrawText
  9644.    function.
  9645.  
  9646.  15.5.2  Messages Sent to Static Controls
  9647.  
  9648.    The following messages are associated with static-control windows:
  9649.  
  9650.    SM_QUERYHANDLE──Returns the private handle for the static control. For
  9651.    controls with SS_ICON, SS_BITMAP, or SS_SYSICON style, the handle of the
  9652.    icon or bitmap is returned. For all other types of static controls, the
  9653.    handle is available for application-defined purposes.
  9654.  
  9655.    SM_SETHANDLE──Sets the private handle for the static control. Static
  9656.    controls with SS_ICON, SS_BITMAP, or SS_SYSICON style automatically use
  9657.    this handle to store the icon or bitmap when the control is created. An
  9658.    application can change the appearance of these controls by setting the
  9659.    handle. For all other types of static controls, the handle is available
  9660.    for application-defined purposes.
  9661.  
  9662.  
  9663.  
  9664.  ────────────────────────────────────────────────────────────────────────────
  9665.  Chapter 16  Scroll-Bar Controls
  9666.  
  9667.         16.1    Introduction
  9668.         16.2    About Scroll Bars
  9669.             16.2.1    Scroll-Bar Creation
  9670.             16.2.2    Scroll-Bar Range and Position
  9671.             16.2.3    Scroll-Bar Notification Messages
  9672.             16.2.4    Scroll Bars and the Keyboard
  9673.         16.3    Using Scroll Bars
  9674.             16.3.1    Creating Scroll Bars
  9675.             16.3.2    Retrieving a Scroll-Bar Handle
  9676.             16.3.3    Using the Scroll-Bar Range and Position
  9677.         16.4    Summary
  9678.             16.4.1    Messages
  9679.             16.4.2    System Values
  9680.  
  9681.  16.1  Introduction
  9682.  
  9683.    This chapter describes creating and using scroll bars in Presentation
  9684.    Manager applications. You should also be familiar with the following
  9685.    topics:
  9686.  
  9687.    ■  Standard user-interface guidelines
  9688.  
  9689.    ■  Windows
  9690.  
  9691.    ■  Frame windows
  9692.  
  9693.    ■  Messages and message queues
  9694.  
  9695.    ■  Control windows
  9696.  
  9697.  
  9698.  16.2  About Scroll Bars
  9699.  
  9700.    Scroll bars are control windows that convert mouse and keyboard input into
  9701.    integer values. Applications typically use scroll bars to control
  9702.    scrolling the contents in a client window.
  9703.  
  9704.    A scroll bar has several parts: the bar, arrows, and the slider. These are
  9705.    found on vertical and on horizontal scroll bars. Arrows are located at
  9706.    each end of a scroll bar. The left scroll arrow, on the left side of a
  9707.    horizontal scroll bar, lets the user scroll toward the left in a document.
  9708.    The right scroll arrow lets the user scroll toward the right. The upper
  9709.    scroll arrow lets the user scroll upward in the document. The lower scroll
  9710.    arrow lets the user scroll downward.
  9711.  
  9712.    The slider, a hollow box, lies between the two scroll arrows. The slider
  9713.    position in the scroll bar the reflects current value of the scroll bar.
  9714.    When the slider is against the left or top scroll arrow, the scroll-bar
  9715.    value is at a minimum; when the slider is against the right or bottom
  9716.    arrow, the scroll-bar value is at a maximum. The area between the scroll
  9717.    arrows is called the slider background.
  9718.  
  9719.    Scroll bars monitor the slider position and send notification messages to
  9720.    the owner window when the slider position changes through mouse or
  9721.    keyboard input.
  9722.  
  9723.    Scroll bars are often used in frame windows. A frame window automatically
  9724.    places scroll bars at the right and bottom sides of a window, depending on
  9725.    the scroll-bar style. The frame window automatically passes scroll-bar
  9726.    messages on to its client window. The client window handles these messages
  9727.    by adjusting the display. The client window can also send messages
  9728.    directly to the scroll bar, directing the scroll bar to adjust its range
  9729.    so that it will map to the data scrolling in the client window.
  9730.  
  9731.    An application can use scroll bars as stand-alone controls in any size or
  9732.    shape, at any position, in any sort of window. Scroll bars can be used as
  9733.    parts of other controls──for example, list-box controls use a scroll bar
  9734.    to let the user view items when the list box is too small to display all
  9735.    the items.
  9736.  
  9737.  16.2.1  Scroll-Bar Creation
  9738.  
  9739.    An application creates a scroll bar by using the preregistered window
  9740.    class WC_SCROLLBAR. The application can create a scroll bar by using the
  9741.    WinCreateWindow function. There are two scroll-bar styles: SBS_HORZ and
  9742.    SBS_VERT. The style SBS_HORZ creates a horizontal scroll bar; SBS_VERT
  9743.    creates a vertical scroll bar. Although most applications specify an owner
  9744.    when creating a scroll bar, an owner is not required. If no owner is
  9745.    specified, the scroll bar does not send notification messages. An
  9746.    application can retrieve the scroll bar's current slider position by
  9747.    sending the SBM_QUERYPOS message to the scroll bar.
  9748.  
  9749.    An application can specify class-specific data when creating a scroll bar.
  9750.    The SBCDATA structure specifies the initial range and slider position for
  9751.    the scroll bar.
  9752.  
  9753.    If a scroll bar is a descendant of a frame window, its position relative
  9754.    to the parent window may change when the frame window's position changes.
  9755.    Frame windows draw scroll bars relative to the upper-left corner of the
  9756.    frame window (rather than the lower-left corner). The frame window may
  9757.    adjust the y-coordinate of the scroll-bar position. This is desirable when
  9758.    the scroll bar is an immediate child window of the frame window, but may
  9759.    be undesirable if the scroll bar is not an immediate child window.
  9760.  
  9761.  16.2.2  Scroll-Bar Range and Position
  9762.  
  9763.    Every scroll bar has a range and a slider position. The range specifies
  9764.    the maximum and minimum values for the slider position. As the user moves
  9765.    the slider in the scroll bar, its position is reported as an integer value
  9766.    in the range. If the slider position is the minimum value, the slider is
  9767.    at the top of a vertical scroll bar or at the left end of a horizontal
  9768.    scroll bar. If the slider position is the maximum value, the slider is at
  9769.    the bottom or right end of the vertical or horizontal scroll bar,
  9770.    respectively.
  9771.  
  9772.    An application can adjust the range to convenient integer values by using
  9773.    the SBM_SETSCROLLBAR message (or initially, by using the SBCDATA
  9774.    structure). This makes it easy to translate the slider position to a value
  9775.    that corresponds to the data being scrolled. For example, an application
  9776.    that has 260 lines of text to display in a window that can show only 16
  9777.    lines at a time can set the vertical scroll-bar range to 1 through 244.
  9778.    When the slider is at position 1, the first line is at the top of the
  9779.    window. When the slider is at position 244, the last line is at the bottom
  9780.    of the window.
  9781.  
  9782.    To keep the scroll-bar range in useful relationship with the data, an
  9783.    application must adjust the range whenever the data or the size of the
  9784.    window changes. This means an application should adjust the range as part
  9785.    of processing WM_SIZE messages.
  9786.  
  9787.    An application must move the slider in the scroll bar. Although the user
  9788.    makes a request for scrolling in the scroll bar, the scroll bar does not
  9789.    update the slider position. Instead, it passes the request to the owner
  9790.    window. The owner window must scroll the data and update the slider
  9791.    position by using the SBM_SETPOS message. Because the application controls
  9792.    the slider movement, it can move the slider in increments that work best
  9793.    for the data being scrolled.
  9794.  
  9795.  16.2.3  Scroll-Bar Notification Messages
  9796.  
  9797.    The scroll bar sends notification messages to the scroll-bar owner
  9798.    whenever the user clicks the scroll bar. The WM_VSCROLL and WM_HSCROLL
  9799.    messages are the notification messages for vertical and horizontal scroll
  9800.    bars, respectively. If the scroll bar is a frame-control window, the
  9801.    message is passed by the frame window to the client window.
  9802.  
  9803.    Each notification message includes the scroll-bar identifier, the specific
  9804.    scroll-bar command code that corresponds to the user's action, and, in
  9805.    some cases, the current position of the slider. If a scroll bar is created
  9806.    as part of a frame-control window, the scroll-bar identifier is one of the
  9807.    predefined constants FID_VERTSCROLL or FID_HORZSCROLL. Otherwise, it is
  9808.    the identifier given in the WinCreateWindow function.
  9809.  
  9810.    The scroll-bar command codes specify the action the user has taken. The
  9811.    code specifies where the user has clicked the mouse. MS OS/2
  9812.    user-interface guidelines recommend certain responses for each action. The
  9813.    following is a list of the command codes and the recommended responses. In
  9814.    each case, a "unit" is defined by the application and should be
  9815.    appropriate for the given data. For example, when scrolling text
  9816.    vertically, the unit is typically a line.
  9817.  
  9818. ╓┌─┌───────────────────┌─────────────────────────────────────────────────────╖
  9819.    Command code        Description
  9820.    ──────────────────────────────────────────────────────────────────────────
  9821.    SB_LINEUP           User clicked the top scroll arrow. Decrement the
  9822.                        slider position by one and scroll toward the top of
  9823.                        the data by one unit.
  9824.  
  9825.    SB_LINEDOWN         User clicked the bottom scroll arrow. Increment the
  9826.                        slider position by one and scroll toward the bottom of
  9827.                        the data by one unit.
  9828.  
  9829.    SB_LINELEFT         User clicked the left scroll arrow. Decrement the
  9830.    Command code        Description
  9831.    ──────────────────────────────────────────────────────────────────────────
  9832.   SB_LINELEFT         User clicked the left scroll arrow. Decrement the
  9833.                        slider position by one and scroll toward the left end
  9834.                        of the data by one unit.
  9835.  
  9836.    SB_LINERIGHT        User clicked the right scroll arrow. Increment the
  9837.                        slider position by one and scroll toward the right end
  9838.                        of the data one unit.
  9839.  
  9840.    SB_PAGEUP           User clicked the scroll-bar background above the
  9841.                        slider. Decrement the slider position by the number of
  9842.                        data units in the window and scroll toward the top of
  9843.                        the data by the same number of units.
  9844.  
  9845.    SB_PAGEDOWN         User clicked the scroll-bar background below the
  9846.                        slider. Increment the slider position by the number of
  9847.                        data units in the window and scroll toward the bottom
  9848.                        of the data by the same number of units.
  9849.  
  9850.    SB_PAGELEFT         User clicked the scroll-bar background to the left of
  9851.    Command code        Description
  9852.    ──────────────────────────────────────────────────────────────────────────
  9853.   SB_PAGELEFT         User clicked the scroll-bar background to the left of
  9854.                        the slider. Decrement the slider position by the
  9855.                        number of data units in the window and scroll toward
  9856.                        the left end of the data by the same number of units.
  9857.  
  9858.    SB_PAGERIGHT        User clicked the scroll-bar background to the right of
  9859.                        the slider. Increment the slider position by the
  9860.                        number of data units in the window and scroll toward
  9861.                        the right end of the data by the same number of units.
  9862.  
  9863.    SB_SLIDERTRACK      User is dragging the slider. Applications that draw
  9864.                        data quickly can set the slider to the position given
  9865.                        in the message and scroll the data by the same number
  9866.                        of units the slider has moved. Applications that can-
  9867.                        not draw data quickly should wait for the
  9868.                        SB_SLIDERPOSITION code before moving the slider and
  9869.                        scrolling the data.
  9870.  
  9871.    SB_SLIDERPOSITION   User released the slider after dragging it. Set the
  9872.    Command code        Description
  9873.    ──────────────────────────────────────────────────────────────────────────
  9874.   SB_SLIDERPOSITION   User released the slider after dragging it. Set the
  9875.                        slider to the position given in the message and scroll
  9876.                        the data by the same number of units the slider has
  9877.                        moved.
  9878.  
  9879.    SB_ENDSCROLL        User released the mouse after holding it on an arrow
  9880.                        or in the scroll-bar background. No action is
  9881.                        necessary.
  9882.    ──────────────────────────────────────────────────────────────────────────
  9883.  
  9884.  
  9885.    If the scroll-bar command code is either SB_SLIDERPOSITION or
  9886.    SB_SLIDERTRACK, indicating that the user is moving the scroll-bar slider,
  9887.    the notification message also contains the current position of the slider.
  9888.  
  9889.    The owner window can send a message to the scroll bar to read its current
  9890.    value and range or to reset its current value. The owner window can adjust
  9891.    data controlled by the scroll bar to reflect any changes in the state of
  9892.    the scroll bar.
  9893.  
  9894.    An application can disable a scroll bar by using the WinEnableWindow
  9895.    function. A disabled scroll-bar window ignores the user's actions, sending
  9896.    out no notification messages when the user tries to manipulate it. If an
  9897.    application has no data to scroll or all data fits in the client window,
  9898.    it should disable the scroll bar.
  9899.  
  9900.    Scroll bars have their own system color, SYSLR_SCROLLBAR. This color is
  9901.    used to paint the scroll-bar background. Other system colors are used in
  9902.    other parts of the scroll bar.
  9903.  
  9904.  16.2.4  Scroll Bars and the Keyboard
  9905.  
  9906.    When a scroll bar has the keyboard focus, it generates notification
  9907.    messages for the following keys:
  9908.  
  9909.    Key                 Command code
  9910.    ──────────────────────────────────────────────────────────────────────────
  9911.    UP                  SB_LINEUP or SB_LINELEFT
  9912.  
  9913.    LEFT                SB_LINEUP or SB_LINELEFT
  9914.  
  9915.    DOWN                SB_LINEDOWN or SB_LINERIGHT
  9916.  
  9917.    RIGHT               SB_LINEDOWN or SB_LINERIGHT
  9918.  
  9919.    PAGE UP             SB_PAGEUP or SB_PAGELEFT
  9920.  
  9921.    PAGE DOWN           SB_PAGEDOWN or SB_PAGERIGHT
  9922.    ──────────────────────────────────────────────────────────────────────────
  9923.  
  9924.    If an application uses scroll bars to scroll data but does not give the
  9925.    scroll bar the input focus, the window with the focus should process
  9926.    keyboard input itself. The window can generate scroll-bar notification
  9927.    messages or carry out the indicated scrolling. The following list gives
  9928.    the keys a window should process and what action to take for each:
  9929.  
  9930. ╓┌─┌───────────────────────┌─────────────────────────────────────────────────╖
  9931.    Key                     Command
  9932.    ──────────────────────────────────────────────────────────────────────────
  9933.    UP                      SB_LINEUP
  9934.  
  9935.    Key                     Command
  9936.    ──────────────────────────────────────────────────────────────────────────
  9937. 
  9938.    DOWN                    SB_LINEDOWN
  9939.  
  9940.    PAGE UP                 SB_PAGEUP
  9941.  
  9942.    PAGE DOWN               SB_PAGEDOWN
  9943.  
  9944.    CONTROL+HOME            SB_SLIDERTRACK with slider set to minimum position
  9945.  
  9946.    CONTROL+END             SB_SLIDERTRACK with slider set to maximum position
  9947.  
  9948.    LEFT                    SB_LINELEFT
  9949.  
  9950.    RIGHT                   SB_LINERIGHT
  9951.  
  9952.    CONTROL+PAGE UP         SB_PAGELEFT
  9953.  
  9954.    CONTROL+PAGE DOWN       SB_PAGERIGHT
  9955.  
  9956.    Key                     Command
  9957.    ──────────────────────────────────────────────────────────────────────────
  9958. 
  9959.    HOME                    SB_SLIDERTRACK with slider set to minimum position
  9960.  
  9961.    END                     SB_SLIDERTRACK with slider set to maximum position
  9962.    ──────────────────────────────────────────────────────────────────────────
  9963.  
  9964.  
  9965.    Vertical scroll bars that are part of list boxes have the following
  9966.    keyboard interface:
  9967.  
  9968.    Key                     Command
  9969.    ──────────────────────────────────────────────────────────────────────────
  9970.    CONTROL+UP              SB_SLIDERTRACK with slider set to minimum position
  9971.  
  9972.    CONTROL+DOWN            SB_SLIDERTRACK with slider set to maximum position
  9973.  
  9974.    F7                      SB_PAGEUP
  9975.  
  9976.    F8                      SB_PAGEDOWN
  9977.    ──────────────────────────────────────────────────────────────────────────
  9978.  
  9979.    The application must implement the suggested scroll-bar/keyboard
  9980.    interface. This can be accomplished by appropriate handling of WM_CHAR
  9981.    messages.
  9982.  
  9983.  
  9984.  16.3  Using Scroll Bars
  9985.  
  9986.    This section explains how to create and use scroll bars in an application.
  9987.    Scroll bars are most often used in frame windows to let the user scroll
  9988.    data in the corresponding client window.
  9989.  
  9990.  16.3.1  Creating Scroll Bars
  9991.  
  9992.    You can add scroll bars to a frame window by using the FCF_HORZSCROLL
  9993.    flag, the FCF_VERTSCROLL flag, or both flags when creating the frame
  9994.    window with the WinCreateStdWindow function. This adds a horizontal and/or
  9995.    a vertical scroll bar to the frame window. Because the frame window owns
  9996.    the scroll bars, it passes notification messages from these controls to
  9997.    the client window.
  9998.  
  9999.    The following code fragment adds scroll bars to a frame window:
  10000.  
  10001.    /* Set flags for a main window with scroll bars. */
  10002.  
  10003.    ULONG ulFrameControlFlags =
  10004.        FCF_STANDARD | FCF_HORZSCROLL | FCF_VERTSCROLL;
  10005.  
  10006.    /* Create the window. */
  10007.  
  10008.    hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE,
  10009.        &ulFrameControlFlags, szClientClass, szFrameTitle,
  10010.        0L, NULL, 0L, &hwndClient);
  10011.  
  10012.    Scroll bars created this way have the window identifier FID_HORZSCROLL or
  10013.    FID_VERTSCROLL. The frame window determines the size and position of the
  10014.    scroll bars. A frame window uses the standard size specified by the system
  10015.    values SV_CXVSCROLL and SV_CYHSCROLL. The position is always the right and
  10016.    bottom edges of the frame window.
  10017.  
  10018.    Another way to create scroll bars is by using the WinCreateWindow
  10019.    function. This is most common for stand-alone scroll bars. Creating scroll
  10020.    bars in this way lets you set the size and position of the scroll bars.
  10021.    You can also specify the window to receive notification messages.
  10022.  
  10023.    The following code fragment creates a stand-alone scroll bar:
  10024.  
  10025.    HWND hwndScroll;             /* scroll-bar handle              */
  10026.  
  10027.    hwndScroll = WinCreateWindow(
  10028.        hwndClient               /* scroll-bar parent              */
  10029.        WC_SCROLLBAR,           /* preregistered scroll-bar class */
  10030.        NULL,                    /* no window title                */
  10031.        SBS_VERT | WS_VISIBLE,   /* vertical style and visible     */
  10032.        10, 10,                  /* position                       */
  10033.        20, 100,                 /* size                           */
  10034.        hwndClient,              /* owner                          */
  10035.        HWND_TOP,                /* Z-order position               */
  10036.        1,                       /* scroll-bar ID                  */
  10037.        NULL,                    /* no class-specific data         */
  10038.        NULL);                   /* no presentation parameters     */
  10039.  
  10040.  16.3.2  Retrieving a Scroll-Bar Handle
  10041.  
  10042.    If you create a scroll bar as a child window of the frame window by using
  10043.    the WinCreateStdWindow function, you need a way to retrieve the scroll-bar
  10044.    handle. One way is to use the WinWindowFromID function, the frame-window
  10045.    handle, and a predefined identifier (such as FID_HORZSCROLL or
  10046.    FID_VERTSCROLL) to retrieve the scroll-bar handle:
  10047.  
  10048.    hwndHorzScroll = WinWindowFromID(hwndFrame, FID_HORZSCROLL);
  10049.    hwndVertScroll = WinWindowFromID(hwndFrame, FID_VERTSCROLL);
  10050.  
  10051.    If the standard frame window includes a client window, you can use that
  10052.    handle to access the scroll bars. The idea is to retrieve the frame-window
  10053.    handle first, then the scroll-bar handle. This is illustrated by the
  10054.    following code fragment:
  10055.  
  10056.    /* Get a handle to the horizontal scroll bar. */
  10057.  
  10058.    hwndScroll = WinWindowFromID(
  10059.        WinQueryWindow(hwndClient, QW_PARENT, FALSE),
  10060.        FID_HORZSCROLL);
  10061.  
  10062.  16.3.3  Using the Scroll-Bar Range and Position
  10063.  
  10064.    You can initialize a scroll bar's current value and range to nondefault
  10065.    values by sending the SBCDATA structure with class-specific data for a
  10066.    call to the WinCreateWindow function:
  10067.  
  10068.    SBCDATA sbcd;
  10069.  
  10070.    /* Set up scroll-bar control data. */
  10071.  
  10072.    sbcd.posFirst = 200;
  10073.    sbcd.posLast = 400;
  10074.    sbcd.posThumb = 300;
  10075.  
  10076.    /* Create the scroll bar. */
  10077.  
  10078.    hwndScroll = WinCreateWindow(hwndClient, WC_SCROLLBAR, NULL,
  10079.        SBS_VERT | WS_VISIBLE,
  10080.        10, 10, 20, 100,
  10081.        hwndClient, HWND_TOP, 1,
  10082.        &sbcd,       /* class-specific data */
  10083.        NULL);
  10084.  
  10085.    You can adjust a scroll-bar value and range by sending it an
  10086.    SBM_SETSCROLLBAR message:
  10087.  
  10088.    /* Set the scroll-bar value and range. */
  10089.  
  10090.    WinSendMsg(hwndScroll, SBM_SETSCROLLBAR,
  10091.        MPFROM2SHORT(300, 0),
  10092.        MPFROM2SHORT(200, 400));
  10093.  
  10094.    You can read a scroll-bar value by sending it an SBM_QUERYPOS message:
  10095.  
  10096.    USHORT usSliderPos;
  10097.  
  10098.    /* Read the scroll-bar value. */
  10099.  
  10100.    usSliderPos = (USHORT) WinSendMsg(hwndScroll,
  10101.        SBM_QUERYPOS, NULL, NULL);
  10102.  
  10103.    Similarly, you can set a scroll-bar value by sending an SBM_SETPOS
  10104.    message:
  10105.  
  10106.    /* Set the vertical scroll-bar value. */
  10107.  
  10108.    WinSendMsg(hwndScroll, SBM_QUERYPOS, MPFROM2SHORT(300, 0), NULL);
  10109.  
  10110.    You can read a scroll-bar range by sending it an SBM_QUERYRANGE message:
  10111.  
  10112.    MRESULT mr;
  10113.    USHORT iMinimum, iMaximum;
  10114.  
  10115.    /* Read the vertical scroll-bar range. */
  10116.  
  10117.    mr = WinSendMsg(hwndScroll, SBM_QUERYRANGE, NULL, NULL);
  10118.  
  10119.    iMinimum = SHORT1FROMMR(mr);  /* minimum in the low word  */
  10120.    iMaximum = SHORT2FROMMR(mr);  /* maximum in the high word */
  10121.  
  10122.  
  10123.  16.4  Summary
  10124.  
  10125.    This section lists the messages and system values that applications use to
  10126.    create and control scroll-bar control windows.
  10127.  
  10128.  16.4.1  Messages
  10129.  
  10130.    Applications use the following messages to create and control scroll bars:
  10131.  
  10132.    SBM_QUERYHILITE  Sent to a scroll bar to obtain its highlight state.
  10133.  
  10134.    SBM_QUERYPOS  Sent to a scroll bar to obtain the current value of the
  10135.    scroll bar.
  10136.  
  10137.    SBM_QUERYRANGE  Sent to a scroll bar to obtain the scroll-bar range.
  10138.  
  10139.    SBM_SETHILITE  Sent to a scroll bar to set the highlight state.
  10140.  
  10141.    SBM_SETPOS  Sent to a scroll bar to set the current value of the scroll
  10142.    bar.
  10143.  
  10144.    SBM_SETSCROLLBAR  Sent to a scroll bar to set the current value and range.
  10145.  
  10146.    WM_HSCROLL  Sent by a horizontal scroll bar to its owner window when the
  10147.    user changes the state of the scroll bar. The high word of the second
  10148.    parameter (mp2) contains a scroll-bar command code.
  10149.  
  10150.    WM_VSCROLL  Sent by a vertical scroll bar to its owner window when the
  10151.    user changes the state of the scroll bar. The high word of the second
  10152.    parameter (mp2) contains a scroll-bar command code.
  10153.  
  10154.  16.4.2  System Values
  10155.  
  10156.    Applications use the following system values to create and control scroll
  10157.    bars:
  10158.  
  10159.    SV_CXHSCROLLARROW  Width (in pels) of the scroll-arrow area in a
  10160.    horizontal scroll bar.
  10161.  
  10162.    SV_CXVSCROLL  Width (in pels) of a standard vertical scroll bar.
  10163.  
  10164.    SV_CYHSCROLL  Height (in pels) of a standard horizontal scroll bar.
  10165.  
  10166.    SV_CYVSCROLLARROW  Height (in pels) of the scroll-arrow area in a vertical
  10167.    scroll bar.
  10168.  
  10169.    SV_FIRSTSCROLLRATE  Initial rate at which a scroll bar sends notification
  10170.    messages when the user clicks the scroll arrows or scroll-bar background.
  10171.  
  10172.    SV_SCROLLRATE  Similar to SV_FIRSTSCROLLRATE, this is the rate at which
  10173.    the scroll bar sends messages.
  10174.  
  10175.    SYSCLR_SCROLLBAR  Color for drawing scroll-bar backgrounds.
  10176.  
  10177.    TID_SCROLL  Timer ID for a reserved scrolling timer. This timer is used
  10178.    for sending notification messages when a scroll arrow or scroll-bar
  10179.    background is clicked.
  10180.  
  10181.  
  10182.  
  10183.  ────────────────────────────────────────────────────────────────────────────
  10184.  Chapter 17  Menus
  10185.  
  10186.         17.1    Introduction
  10187.         17.2    About Menus
  10188.             17.2.1    Menu-Bar and Pull-Down Menus
  10189.             17.2.2    System Menu
  10190.             17.2.3    Menu-Item Styles
  10191.             17.2.4    Menu-Item Attributes
  10192.         17.3    Defining Menu Items in a Resource File
  10193.         17.4    Menu Data Structures
  10194.             17.4.1    Menu Template
  10195.         17.5    Using Menus in your Applications
  10196.             17.5.1    Including a Menu in a Standard Window
  10197.             17.5.2    Adding Menus to a Dialog Window
  10198.             17.5.3    Accessing the System Menu
  10199.             17.5.4    Responding to a User's Menu Choice
  10200.             17.5.5    Using Menus with the Keyboard
  10201.             17.5.6    Using Keyboard Accelerators
  10202.             17.5.7    Help Item in the Menu Bar
  10203.             17.5.8    Setting and Querying Menu-Item Attributes
  10204.             17.5.9    Setting and Querying Menu-Item Contents
  10205.             17.5.10   Adding and Deleting Menu Items
  10206.             17.5.11   Owner-Drawn Menu Items
  10207.         17.6    Summary
  10208.             17.6.1    Menu-Item Styles
  10209.             17.6.2    Menu-Item Attributes
  10210.             17.6.3    Menu Functions
  10211.             17.6.4    Messages Sent from a Menu to an Owner Window
  10212.             17.6.5    Messages Sent to a Menu
  10213.  
  10214.  17.1  Introduction
  10215.  
  10216.    This chapter describes how to use menus in your applications. You should
  10217.    also be familiar with the following topics:
  10218.  
  10219.    ■  Standard user-interface guidelines
  10220.  
  10221.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  10222.  
  10223.    ■  Accelerator tables
  10224.  
  10225.    ■  Creating standard frame windows
  10226.  
  10227.    ■  Window messages and message queues
  10228.  
  10229.  
  10230.  17.2  About Menus
  10231.  
  10232.    Menus are windows that contain a list of items. These items can be text
  10233.    strings, bitmaps, or images drawn by the application. Menus allow the user
  10234.    to use the mouse or keyboard to choose from a predetermined list of
  10235.    choices. When a user makes a choice from a menu, the menu posts a message
  10236.    containing the item's unique menu-item identifier to the menu's owner
  10237.    window.
  10238.  
  10239.    Typically, an application defines its menus by using Resource Compiler and
  10240.    associates the menus with an frame window when the window is created.
  10241.    Applications can also create menus by filling in menu-template data
  10242.    structures and then creating windows with the WC_MENU class. Either way,
  10243.    applications can dynamically add, delete, or change menu items by sending
  10244.    messages to menu windows.
  10245.  
  10246.    Menu windows are always owned by another window; this is important because
  10247.    a menu sends messages to its owner whenever a menu item is highlighted or
  10248.    chosen by the user. Owner windows send messages to menus to add, delete,
  10249.    or change menu items.
  10250.  
  10251.  17.2.1  Menu-Bar and Pull-Down Menus
  10252.  
  10253.    Typically, an application uses a menu-bar menu and several pull-down
  10254.    submenus. The menu bar is a child window in the parent window frame. The
  10255.    submenus are normally hidden and become visible when the user makes
  10256.    selections in the menu bar. Figure 17.1 shows a typical menu-bar and
  10257.    submenu layout in a standard frame window:
  10258.  
  10259.    ┌────────────────────────────────────────────────────────────────────────┐
  10260.    │ Figure 17.1 can be found in Section 17.2.1 of the printed manual.      │
  10261.    └────────────────────────────────────────────────────────────────────────┘
  10262.  
  10263.    Figure 17.1  Menu-Bar and Pull-Down Menus
  10264.  
  10265.    There are two main types of menu items: command items and submenu items.
  10266.    When the user chooses a command item, a command message is immediately
  10267.    posted to the parent window. When the user selects a submenu item, a
  10268.    pull-down menu is displayed from which the user may choose another command
  10269.    item. Since a pull-down menu window can also contain a submenu item,
  10270.    pull-down menus can originate from other pull-down menus. An item in the
  10271.    menu bar may be a command item or a submenu item.
  10272.  
  10273.    When a command item is selected, either from the menu bar or from a
  10274.    pull-down menu, the menu system posts a WM_COMMAND, WM_HELP, or
  10275.    WM_SYSCOMMAND message to the owner window, depending on the menu item's
  10276.    style bits.
  10277.  
  10278.    The menu bar is a child window of the frame window; the menu-bar window
  10279.    handle is the key to communicating with menus. The handle of the menu-bar
  10280.    window can be obtained by calling the WinWindowFromID function with the
  10281.    handle of the parent window and the FID_MENU frame-control identifier.
  10282.    Most messages for menus and submenus can be sent to the menu-bar window.
  10283.    Flags in the messages tell the window whether to search submenus for
  10284.    requested menu items.
  10285.  
  10286.  17.2.2  System Menu
  10287.  
  10288.    The System menu in the upper-left corner of a standard frame window is
  10289.    different from the menu-bar and pull-down menus defined by the
  10290.    application. The System menu is controlled and defined almost exclusively
  10291.    by the system. Your only decision about the System menu is whether or not
  10292.    to include it when creating a frame window. (It is unusual for a frame
  10293.    window not to include a System menu.) The System menu generates
  10294.    WM_SYSCOMMAND messages instead of WM_COMMAND messages. Most applications
  10295.    simply allow the default behavior for WM_SYSCOMMAND messages. If
  10296.    necessary, you can obtain the handle of the System menu by calling the
  10297.    WinWindowFromID function with the handle of the parent (frame) window and
  10298.    the FID_SYSMENU frame-control identifier. The application can add, delete,
  10299.    and change System-menu entries.
  10300.  
  10301.  17.2.3  Menu-Item Styles
  10302.  
  10303.    All menu items have a combination of style bits that determine what kind
  10304.    of data the item contains and what kind of message it generates when it is
  10305.    chosen by the user. For instance, a menu item can have the MIS_TEXT,
  10306.    MIS_BITMAP, or other styles, specifying what kind of display object
  10307.    visually represents the menu item on the screen. Other styles determine
  10308.    what kinds of messages the item sends to its owner window and whether the
  10309.    owner window draws the item. Menu-item styles typically do not change
  10310.    during program execution, but they can be queried and set by sending
  10311.    MM_SETITEM and MM_QUERYITEM messages to the menu with the identifier of
  10312.    the item. The possible menu-item styles are described in Section 17.6.1.
  10313.  
  10314.  17.2.4  Menu-Item Attributes
  10315.  
  10316.    Menu items have attributes that determine how they are displayed and
  10317.    whether or not the user can choose them. Menu-item attributes can be set
  10318.    and queried by sending MM_SETITEMATTR and MM_QUERYITEMATTR messages with
  10319.    the identifier of the item to the menu-bar menu window. If the specified
  10320.    item is in a submenu, you must set a flag in the message so that submenus
  10321.    are searched for the item. The possible attributes of a menu item are
  10322.    listed in Section 17.6.2.
  10323.  
  10324.  
  10325.  17.3  Defining Menu Items in a Resource File
  10326.  
  10327.    A menu resource consists of command items and submenu items. One menu
  10328.    resource typically represents the menu bar and all its submenus. An
  10329.    application can specify the identifier of the menu resource when creating
  10330.    a standard window, or it can load the menu resource directly by using the
  10331.    WinLoadMenu function. A menu-item definition is organized as follows:
  10332.  
  10333.      MENUITEM item text, item identifier, item style, item attributes
  10334.  
  10335.    The menu resource-definition file specifies the text of each item in the
  10336.    menu, unique identifier, its style and its attributes, and whether it is a
  10337.    command item or a submenu item. Following is sample source code that
  10338.    defines a menu resource for Resource Compiler. The code defines a menu
  10339.    with three submenu items in the menu bar (File, Edit, and Fonts) and a
  10340.    command item (Help). Each submenu has several command items, and the Fonts
  10341.    submenu has two other submenus within it.
  10342.  
  10343.    MENU ID_MENU_RESOURCE
  10344.    BEGIN
  10345.        SUBMENU "~File", IDM_FILE
  10346.            BEGIN
  10347.                MENUITEM "~Open...",       IDM_FI_OPEN
  10348.                MENUITEM "~Close\tF3",     IDM_FI_CLOSE, MIS_DISABLED
  10349.                MENUITEM "~Quit",          IDM_FI_QUIT
  10350.                MENUITEM "",               IDM_FI_SEP1, MIS_SEPARATOR
  10351.                MENUITEM "~About Sample",  IDM_FI_ABOUT
  10352.            END
  10353.        SUBMENU "~Edit", IDM_EDIT
  10354.            BEGIN
  10355.                MENUITEM "~Undo",          IDM_ED_UNDO, 0, MIA_DISABLED
  10356.                MENUITEM "",               IDM_ED_SEP1, MIS_SEPARATOR
  10357.                MENUITEM "~Cut",           IDM_ED_CUT
  10358.                MENUITEM "C~opy",          IDM_ED_COPY
  10359.                MENUITEM "~Paste",         IDM_ED_PASTE
  10360.                MENUITEM "C~lear",         IDM_ED_CLEAR
  10361.            END
  10362.        SUBMENU "Font", IDM_FONT
  10363.            BEGIN
  10364.                SUBMENU "Style",           IDM_FONT_STYLE
  10365.                    BEGIN
  10366.                        MENUITEM "Plain",  IDM_FONT_STYLE_PLAIN
  10367.                        MENUITEM "Bold",   IDM_FONT_STYLE_BOLD
  10368.                        MENUITEM "Italic", IDM_FONT_STYLE_ITALIC
  10369.                    END
  10370.                SUBMENU "Size",            IDM_FONT_SIZE
  10371.                    BEGIN
  10372.                        MENUITEM "10",     IDM_FONT_SIZE_10
  10373.                        MENUITEM "12",     IDM_FONT_SIZE_12
  10374.                        MENUITEM "14",     IDM_FONT_SIZE_14
  10375.                    END
  10376.            END
  10377.        MENUITEM "F1=Help", 0x00, MIS_TEXT | MIS_BUTTONSEPARATOR | MIS_HELP
  10378.    END
  10379.  
  10380.    Figure 17.2 shows how the submenus within a Delete submenu are displayed.
  10381.  
  10382.    ┌────────────────────────────────────────────────────────────────────────┐
  10383.    │ Figure 17.2 can be found in Section 17.3 of the printed manual.        │
  10384.    └────────────────────────────────────────────────────────────────────────┘
  10385.  
  10386.    Figure 17.2  Submenus
  10387.  
  10388.    You can indicate a mnemonic keystroke for the menu item by preceding that
  10389.    character in the item text with a tilde, as in "~File". The user can
  10390.    choose that item by pressing the mnemonic key when the menu is active.
  10391.    (The menu bar is active when the user presses and releases the ALT key,
  10392.    and the first item in the menu bar is highlighted. A pull-down menu is
  10393.    active when it is open.)
  10394.  
  10395.    In addition to mnemonics, a menu item can have an associated keyboard
  10396.    accelerator. Accelerators are different from mnemonics, in that the menu
  10397.    does not have to be active for the accelerator key to work. If a menu item
  10398.    has a keyboard accelerator associated with it, the corresponding menu item
  10399.    should display the accelerator to the right of the menu item. This is done
  10400.    by placing a tab character (\t) in the menu text before the characters
  10401.    that should be displayed on the right. For example, if the Close item had
  10402.    the F3 function key as its keyboard accelerator, the text for the item
  10403.    would be "Close\tF3". For more information on accelerators, see Section
  10404.    17.5.6.
  10405.  
  10406.    Each entry that defines a menu item specifies the text for the item, its
  10407.    identifier, and the style and attributes of the item. A menu item that has
  10408.    no specification for style or attributes has the default style of MIS_TEXT
  10409.    and all attribute bits off, indicating that the item is enabled. The
  10410.    MIS_SEPARATOR style identifies nonselectable lines between menu items.
  10411.  
  10412.    To define a menu item with the MIS_BITMAP style, an application should use
  10413.    a tool such as Icon Editor to create a bitmap, include the bitmap in the
  10414.    application's resource-definition file, and define a menu in the file (as
  10415.    shown in the following code fragment). The text for the bitmap menu items
  10416.    is an ASCII representation of the resource identifier of the bitmap
  10417.    resource to be displayed for that item.
  10418.  
  10419.    /* Bring externally created bitmaps into the resource file. */
  10420.  
  10421.    BITMAP 101 button.bmp
  10422.    BITMAP 102 hirest.bmp
  10423.    BITMAP 103 hizoom.bmp
  10424.    BITMAP 104 hired.bmp
  10425.  
  10426.    /* Connect a menu item with a bitmap. */
  10427.  
  10428.    SUBMENU "~Bitmaps", IDM_BITMAP
  10429.        BEGIN
  10430.            MENUITEM "#101", IDM_BM_01, MIS_BITMAP
  10431.            MENUITEM "#102", IDM_BM_02, MIS_BITMAP
  10432.            MENUITEM "#103", IDM_BM_03, MIS_BITMAP
  10433.            MENUITEM "#104", IDM_BM_04, MIS_BITMAP
  10434.        END
  10435.  
  10436.  
  10437.  
  10438.  17.4  Menu Data Structures
  10439.  
  10440.    There are two main data structures that define the contents of a menu: the
  10441.    menu-item structure and the menu-template structure. The menu-item
  10442.    structure defines a single menu item, and the menu-template structure
  10443.    contains all the menu items that make up a menu resource, including the
  10444.    menu bar and all its pull-down menus.
  10445.  
  10446.    A single menu item is defined by the MENUITEM data structure. This data
  10447.    structure is used with the MM_INSERTITEM message to insert items into a
  10448.    menu, or to query and set item characteristics with the MM_QUERYITEM and
  10449.    MM_SETITEM messages. The MENUITEM data structure has the following form:
  10450.  
  10451.    typedef struct _MENUITEM {
  10452.        SHORT  iPosition;
  10453.        USHORT afStyle;
  10454.        USHORT afAttribute;
  10455.        USHORT id;
  10456.        HWND   hwndSubMenu;
  10457.        ULONG  hItem;
  10458.    } MENUITEM;
  10459.  
  10460.    The values of most of the fields in the data structure can be derived
  10461.    directly from the resource-definition file shown in Section 17.3. The
  10462.    last field in the structure, hItem, depends on the style of the menu item.
  10463.  
  10464.    The iPosition field specifies the ordinal position of the item within its
  10465.    menu window. If the item is part of the menu bar, iPosition gives its
  10466.    relative left-to-right position, with zero being the leftmost item. If the
  10467.    item is part of a submenu, iPosition gives its relative top-to-bottom and
  10468.    left-to-right position, with zero being the upper-left item. An item with
  10469.    the MIS_BREAKSEPARATOR style in a pull-down menu will cause a new column
  10470.    to begin.
  10471.  
  10472.    The afStyle field contains the style bits of the item. The afAttribute
  10473.    field contains the attribute bits.
  10474.  
  10475.    The id field contains the identifier for the menu item. The identifier
  10476.    should be unique but does not have to be. When multiple items have the
  10477.    same identifier, they post the same command number in the WM_COMMAND,
  10478.    WM_HELP, and WM_SYSCOMMAND messages. Also, any message that specifies a
  10479.    menu item with a nonunique identifier will find the first item that has
  10480.    that identifier.
  10481.  
  10482.    The hwndSubMenu field contains the window handle of a pull-down menu
  10483.    window (if the item is a submenu item). The hwndSubMenu field is NULL for
  10484.    command items.
  10485.  
  10486.    The hItem field contains a handle to the display object for the item,
  10487.    unless the item has the MIS_TEXT style, in which case hItem is NULL. For
  10488.    example, a menu item with the MIS_BITMAP style has an hItem field that is
  10489.    equal to its bitmap handle.
  10490.  
  10491.  17.4.1  Menu Template
  10492.  
  10493.    A menu template is a variable-length data structure that represents the
  10494.    entire menu, including all items and submenus. A menu template is made up
  10495.    of a series of variable-length records. Each record represents a single
  10496.    menu item. If the item is a submenu, the template that describes the
  10497.    submenu is nested after the submenu item record.
  10498.  
  10499.    The menu template is a representation of the menu as it is defined in the
  10500.    resource-definition file. Typically, applications require information
  10501.    about the internal structure of a menu template only when creating a menu
  10502.    template without using a resource-definition file.
  10503.  
  10504.    A template is defined as shown in the following code fragment:
  10505.  
  10506.    typedef struct _MT {
  10507.        USHORT cb;          /* length of template in bytes              */
  10508.        USHORT version;     /* version; set to zero                     */
  10509.        USHORT codepage;    /* code page                                */
  10510.        USHORT iInputsize;  /* length of input field for host terminals */
  10511.        USHORT cMti;        /* count of items                           */
  10512.        MTI    rgMti(cMti);
  10513.    } MT;
  10514.  
  10515.    MS OS/2 version 1.1 sets the version, code-page, and input-size fields to
  10516.    zero, and ignores the contents of these fields if set by an application.
  10517.    The cMti field specifies the number of menu-template items that follow.
  10518.    Each menu-template item describes one item in the menu. Since each menu
  10519.    item can require a different amount of storage, the following variable
  10520.    definition of a menu-template item is used:
  10521.  
  10522.    typedef struct _MTI {
  10523.        USHORT afStyle;
  10524.        USHORT afAttribute;
  10525.        USHORT idItem;
  10526.        if (afStyle AND MIS_BITMAP)
  10527.          CHAR szItemString ? ;
  10528.        if (afStyle AND MIS_OWNERDRAW)
  10529.          VOID;
  10530.        if (afStyle AND MIS_TEXT)
  10531.          CHAR szItemString ? ;
  10532.        if (aStyle AND MIS_SEPARATOR)
  10533.          VOID;
  10534.        if (afStyle AND MIS_SUBMENU)
  10535.          MT MenuTemplate;
  10536.    } MTI;
  10537.  
  10538.    The first three fields of a structure for a menu-template item specify the
  10539.    style, attributes, and identifier of the item. The data that follows these
  10540.    fields is determined by the style of the item. The cases can be summarized
  10541.    as follows:
  10542.  
  10543.    If the afStyle field is MIS_TEXT, the data that follows the idItem field
  10544.    is a null-terminated string representing the menu-item text.
  10545.  
  10546.    If the afStyle field is MIS_BITMAP, the data that follows idItem is a
  10547.    null-terminated string that can represent one of three things:
  10548.  
  10549.    ■  If the first byte is NULL, then no bitmap resource is defined; the
  10550.       application provides a bitmap handle for the item.
  10551.  
  10552.    ■  If the first byte is "#", subsequent characters make up the decimal
  10553.       representation of the bitmap resource-identifier.
  10554.  
  10555.    ■  If neither of the previous cases apply, the handle is set to NULL, and
  10556.       the application must set it manually.
  10557.  
  10558.    If the afStyle field is MIS_OWNERDRAW or MIS_SEPARATOR, there is no data
  10559.    following the idItem field.
  10560.  
  10561.    If the afStyle field is MIS_SUBMENU, a complete menu-template structure
  10562.    for the submenu follows the idItem field.
  10563.  
  10564.  
  10565.  17.5  Using Menus in your Applications
  10566.  
  10567.    Typically, an application that uses menus defines them in a
  10568.    resource-definition file and includes them in a standard frame window.
  10569.    During program execution, the application's window procedure receives
  10570.    messages generated by the menu windows in response to user input, either
  10571.    from the mouse or the keyboard. The application responds to these messages
  10572.    by using the identifier of the menu item that is contained in each menu
  10573.    message. The application can also load menu resources at run time and
  10574.    associate them with a particular owner window. This is useful for putting
  10575.    menus in windows other than the standard frame window.
  10576.  
  10577.    The user-interface guidelines specify that a user should not be required
  10578.    to have a mouse to operate an MS OS/2 application. Applications can define
  10579.    keyboard equivalents to menu items to aid users without mice.
  10580.  
  10581.    It is also suggested that all applications have a Help item in their menu
  10582.    bar. This presents a standard interface for the novice user across all
  10583.    applications. The Help item is defined with a particular style,
  10584.    attributes, and position in the menu, as shown in the resource-definition
  10585.    file in Section 17.3. The Help command item generates a WM_HELP message
  10586.    when chosen by the user, allowing the application to respond
  10587.    appropriately. For more information on the help system, see Chapter 29,
  10588.    "Help."
  10589.  
  10590.    Applications can change the attributes, style, and contents of menu items,
  10591.    and insert and delete items at run time, to reflect changes in the command
  10592.    environment. An application can also add or delete items from the menu bar
  10593.    or submenus. For example, an application might maintain a menu of the
  10594.    currently available fonts in the system. This application would use Gpi
  10595.    calls to determine which fonts were available, and then insert a menu item
  10596.    for each font into a submenu. Furthermore, the application might set the
  10597.    "checked" attribute of the menu item for the currently chosen font. When
  10598.    the user chooses a new font, the application would remove the check-mark
  10599.    attribute from the previous choice and add it to the new choice.
  10600.  
  10601.    An application can also draw a menu item itself by setting the attribute
  10602.    MIS_OWNERDRAW for the menu item. Typically, this is done by specifying the
  10603.    MIS_OWNERDRAW attribute for the menu item in the resource-definition file,
  10604.    but it can also be done at run time. When the application draws a menu
  10605.    item, it must respond to messages from the menu each time the item needs
  10606.    to be drawn.
  10607.  
  10608.  17.5.1  Including a Menu in a Standard Window
  10609.  
  10610.    If you have defined a menu resource in a resource-definition file, you can
  10611.    include the menu in a standard window. You include the menu by using the
  10612.    FCF_MENU attribute flag and specifying the menu resource identifier in a
  10613.    call to the WinCreateStdWindow function, as shown in the following code
  10614.    fragment:
  10615.  
  10616.    ULONG lControlStyle = FCF_MENU | FCF_SIZEBORDER |
  10617.        FCF_TITLEBAR | FCF_ACCELTABLE;
  10618.  
  10619.    hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
  10620.        WS_VISIBLE,
  10621.        &lControlStyle,
  10622.        szClassName,
  10623.        szClassName,
  10624.        0L, NULL,
  10625.        ID_MENU_RESOURCE,
  10626.        &hwndClient);
  10627.  
  10628.    After you make this call, MS OS/2 automatically includes the menu in the
  10629.    window, drawing the menu bar across the top of the window. When the user
  10630.    chooses an item from the menu, the menu posts the message to the frame
  10631.    window. The frame window passes any WM_COMMAND messages to the client
  10632.    window. (The frame window does not pass WM_SYSCOMMAND messages to the
  10633.    client window.) WM_HELP messages are posted to the focus window. The
  10634.    WinDefWindowProc function passes WM_HELP messages to the parent window. If
  10635.    a WM_HELP message is passed to a frame window, the frame window calls the
  10636.    HK_HELP hook. Your client window procedure should process these messages
  10637.    to respond to the user's actions. The details of responding to menu
  10638.    selections are shown in Section 17.5.4.
  10639.  
  10640.  17.5.2  Adding Menus to a Dialog Window
  10641.  
  10642.    You may want to use menus in windows that were not created by using the
  10643.    WinCreateStdWindow function. For these windows, you can load a menu
  10644.    resource by using the WinLoadMenu function and specify the parent window
  10645.    for the menu. WinLoadMenu assigns the specified menu resource to the
  10646.    parent window. To see the menu in the window, you must send a
  10647.    WM_UPDATEFRAME message to the parent window after loading the menu
  10648.    resource. This strategy is especially useful for adding menus to a window
  10649.    created as a dialog window, but it can be used no matter what type of
  10650.    window is specified as the parent window.
  10651.  
  10652.  17.5.3  Accessing the System Menu
  10653.  
  10654.    Although most applications do not alter the System menu, you can obtain
  10655.    the handle of the System menu by calling the WinWindowFromID function with
  10656.    a frame-window handle (or dialog-window handle) and the FID_SYSMENU
  10657.    identifier. Once you have the handle of the System menu, you can access
  10658.    the individual menu items by using predefined constants. For example, the
  10659.    following code fragment shows how to disable the Close menu item in the
  10660.    System menu of a window:
  10661.  
  10662.    HWND hwndSysMenu;
  10663.  
  10664.    hwndSysMenu = WinWindowFromID(hwndFrame, FID_SYSMENU);
  10665.  
  10666.    WinSendMsg(hwndSysMenu, MM_SETITEMATTR,
  10667.        MPFROM2SHORT(SC_CLOSE, TRUE),
  10668.        MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
  10669.  
  10670.  17.5.4  Responding to a User's Menu Choice
  10671.  
  10672.    When a user chooses a menu, item your client window procedure receives a
  10673.    WM_COMMAND message with the low word of the mp1 parameter equal to
  10674.    the menu identifier of the selected item. Your application should use the
  10675.    menu identifier to guide its response to the selection. Typically, the
  10676.    code in the client window procedure resembles the following code fragment:
  10677.  
  10678.    case WM_COMMAND:
  10679.        DoMenuCommand(hwnd, LOUSHORT(mp1));
  10680.        return 0;
  10681.  
  10682.    The function that translates the menu identifier into an action typically
  10683.    resembles the following code fragment:
  10684.  
  10685.    VOID DoMenuCommand(hwnd, usItemID)
  10686.    HWND hwnd;
  10687.    USHORT usItemID;
  10688.    {
  10689.  
  10690.        /* Test the menu item. */
  10691.  
  10692.        switch (usItemID) {
  10693.            case IDM_FI_NEW:
  10694.                DoNew(hwnd);
  10695.                break;
  10696.            .
  10697.            .
  10698.            .
  10699.        }
  10700.    }
  10701.  
  10702.    The menu system sends a WM_MENUSELECT message every time the menu
  10703.    selection changes. The low word of the mp1 parameter contains the
  10704.    identifier of the item that is changing state and the high word is a 6-bit
  10705.    Boolean value that describes whether or not the item is chosen; the mp2
  10706.    parameter contains the handle of the menu.
  10707.  
  10708.    If the Boolean value is FALSE, the item is selected but not chosen──for
  10709.    example, the user may have moved the cursor or mouse pointer over the item
  10710.    while the button was down. An application can use this message to display
  10711.    help information at the bottom of the application window. The return value
  10712.    is ignored.
  10713.  
  10714.    If the Boolean value is TRUE, the item is chosen──that is, the user
  10715.    pressed ENTER or released the mouse button when an item was selected. If
  10716.    the application returns FALSE, the menu does not generate a WM_COMMAND,
  10717.    WM_SYSCOMMAND, or WM_HELP message, and the menu is not dismissed.
  10718.  
  10719.  17.5.5  Using Menus with the Keyboard
  10720.  
  10721.    MS OS/2 is designed to work with or without a mouse or other pointing
  10722.    device. The system provides default behavior to allow a user to interact
  10723.    with menus without using a mouse. The following are the keystrokes that
  10724.    produce this default behavior:
  10725.  
  10726. ╓┌─┌─────────────────┌───────────────────────────────────────────────────────╖
  10727.    Keystroke         Action
  10728.    ──────────────────────────────────────────────────────────────────────────
  10729.    ALT               Toggles into and out of menu mode.
  10730.  
  10731.    ALT, SPACEBAR     Shows the System menu.
  10732.  
  10733.    Keystroke         Action
  10734.    ──────────────────────────────────────────────────────────────────────────
  10735. 
  10736.    ESC               Backs up one level. If a pull-down menu is displayed, it
  10737.                      is canceled. If no pull-down menu is displayed, this
  10738.                      keystroke exits from menu mode.
  10739.  
  10740.    RIGHT             Cycles to the next menu-bar item. If the selected item
  10741.                      is at the far-left side of the menu bar, the menu code
  10742.                      sends a WM_NEXTMENU message to the frame. The default
  10743.                      processing by the frame is to cycle between the
  10744.                      application and System menus. (An application can modify
  10745.                      this behavior by subclassing the frame window.) If the
  10746.                      selected item is in a pull-down menu, the next column in
  10747.                      the pull-down menu is selected or the next menu-bar item
  10748.                      is selected; this key may also send or process a
  10749.                      WM_NEXTMENU message.
  10750.  
  10751.    LEFT              Works like the RIGHT key, except in the opposite
  10752.                      direction. In pull-down menus, this keystroke backs up
  10753.                      one column, except when the currently selected item is
  10754.    Keystroke         Action
  10755.    ──────────────────────────────────────────────────────────────────────────
  10756.                     one column, except when the currently selected item is
  10757.                      in the far-left column, in which case the previous
  10758.                      pull-down menu is selected.
  10759.  
  10760.    UP or DOWN        Activates a pull-down menu when in the menu bar. This
  10761.                      keystroke selects the next or previous item when in a
  10762.                      pull-down menu.
  10763.  
  10764.    ENTER             Activates a pull-down menu and highlights the first item
  10765.                      if an item has a pull-down menu associated with it;
  10766.                      otherwise, this keystroke chooses the item as if the
  10767.                      user released the mouse button while the item was
  10768.                      selected.
  10769.  
  10770.    Alphabetic        Selects the first menu item with the specified character
  10771.    characters        as its mnemonic key. A mnemonic is defined for a menu
  10772.                      item by placing a tilde (~) before the character in the
  10773.                      menu text. If the selected item has a pull-down menu or
  10774.                      secondary menu associated with it, the menu is displayed
  10775.    Keystroke         Action
  10776.    ──────────────────────────────────────────────────────────────────────────
  10777.                     secondary menu associated with it, the menu is displayed
  10778.                      and the first item is highlighted; otherwise, the item
  10779.                      is chosen.
  10780.    ──────────────────────────────────────────────────────────────────────────
  10781.  
  10782.  
  10783.    An application does not need to support this default behavior with any
  10784.    unusual code. The application receives a message when a menu item is
  10785.    chosen by using the keyboard just as if it had been chosen by using a
  10786.    mouse.
  10787.  
  10788.  17.5.6  Using Keyboard Accelerators
  10789.  
  10790.    Applications can define accelerator tables to make user interaction with
  10791.    menus more efficient. Accelerator tables are resources that associate
  10792.    keystrokes with menu command items. For example, an application can define
  10793.    an accelerator table resource that makes the F8 key generate a WM_COMMAND
  10794.    message that is identical to the message generated when the user chooses
  10795.    the Quit item from the File menu. Accelerator tables provide a shortcut
  10796.    for proficient users that allows them to work more quickly with the
  10797.    application. A sample resource-definition file for an accelerator table is
  10798.    shown in the following code fragment:
  10799.  
  10800.    ACCELTABLE ID_ACCEL_RESOURCE
  10801.    BEGIN
  10802.        VK_F8, IDM_FILE_QUIT, VIRTUALKEY
  10803.        VK_F3, IDM_SEARCH_FIND, VIRTUALKEY
  10804.        VK_F1, NULL, VIRTUALKEY, HELP
  10805.    END
  10806.  
  10807.    The resource-definition file associates keystrokes with menu-item command
  10808.    identifiers. Notice that the definition uses virtual-keystroke definitions
  10809.    that are independent of the particular scan codes generated by different
  10810.    keyboard hardware.
  10811.  
  10812.    In order to use an accelerator table with a window, the window should be
  10813.    created with the FS_ACCELTABLE style, and the resource identifier of the
  10814.    accelerator table must be the same as the identifier of the window's menu.
  10815.    Alternatively, you can associate an accelerator table with a frame window
  10816.    after the window is created, by calling the WinSetAccelTable function.
  10817.  
  10818.    For more information on keyboard accelerators, see Chapter 18,
  10819.    "Accelerator Tables."
  10820.  
  10821.  17.5.7  Help Item in the Menu Bar
  10822.  
  10823.    The user-interface guidelines suggest that all applications have a Help
  10824.    menu item at the far-right end of the menu bar. The item should read
  10825.    "F1=Help", have an identifier of zero, and have the MIS_BUTTONSEPARATOR or
  10826.    MIS_HELP item style. The Help menu item should be the last item in the
  10827.    menu template, so that it is displayed at the far-right end of the menu
  10828.    bar.
  10829.  
  10830.    The user can use either a mouse or the F1 key to select the Help menu
  10831.    item, if the application uses the system default accelerator table. (For
  10832.    more information on the system default accelerator table, see Section
  10833.    17.5.6.) The Help item generates a WM_HELP message instead of a
  10834.    WM_COMMAND message.
  10835.  
  10836.  17.5.8  Setting and Querying Menu-Item Attributes
  10837.  
  10838.    Menu-item attributes are represented in the afAttribute field of the
  10839.    MENUITEM data structure. Typically, attributes are set in the
  10840.    resource-definition file of the menu and changed at run time as required.
  10841.    Applications can use the MM_SETITEMATTR and MM_QUERYITEMATTR messages to
  10842.    set and query attributes for a particular menu item. One of the most
  10843.    common uses of these messages is to check and uncheck menu items to let
  10844.    the user know what option is currently selected. For example, if you have
  10845.    a menu item that should toggle between checked and unchecked each time it
  10846.    is chosen, you could use the following code to change the checked
  10847.    attribute. You first send an MM_QUERYITEMATTR message to the menu item to
  10848.    obtain its current checked attribute, then use the exclusive OR operator
  10849.    to toggle the state, and then you send the new attribute-state back to the
  10850.    item by using an MM_SETITEMATTR message.
  10851.  
  10852.    usAttrib = (SHORT) WinSendMsg(hwndMenu,   /* submenu window        */
  10853.        MM_QUERYITEMATTR,                     /* message               */
  10854.        MPFROMSHORT(itemID),                  /* identifier of item    */
  10855.        MPFROMSHORT(MIA_CHECKED));            /* attribute mask        */
  10856.  
  10857.    usAttrib ^= MIA_CHECKED;     /* XOR to toggle checked attribute    */
  10858.  
  10859.    WinSendMsg(hwndMenu,                      /* submenu window        */
  10860.        MM_SETITEMATTR,                       /* message               */
  10861.        MPFROMSHORT(itemID),                  /* identifier of item    */
  10862.        MPFROM2SHORT(MIA_CHECKED, usAttrib)); /* attribute mask, value */
  10863.  
  10864.    There are two methods for manipulating individual menu items in submenus.
  10865.    The first is to send MM_SETITEMATTR and MM_QUERYITEMATTR messages to the
  10866.    menu-bar menu, specifying the identifier of the item and setting a flag so
  10867.    that the message searches all submenus for the item. The handle of the
  10868.    menu-bar window can be obtained by calling the WinWindowFromID function
  10869.    with the handle of the frame window and the FID_MENU frame-control
  10870.    identifier.
  10871.  
  10872.    The second method, which is more efficient if you want to work with more
  10873.    than one item in a submenu or set the same item several times, involves
  10874.    two steps:
  10875.  
  10876.    1.  Sending an MM_QUERYITEM message to the menu-bar window with the
  10877.        identifier of the submenu. The updated MENUITEM structure contains the
  10878.        window handle of the submenu.
  10879.  
  10880.    2.  Send an MM_QUERYITEMATTR (or MM_SETITEMATTR) message to the submenu
  10881.        window, specifying the identifier of the item in the submenu.
  10882.  
  10883.  17.5.9  Setting and Querying Menu-Item Contents
  10884.  
  10885.    Applications can change the contents of a menu item dynamically by sending
  10886.    messages to the menu. For MIS_TEXT items, an MM_SETITEMTEXT message sets
  10887.    the text. The MM_QUERYITEMTEXT message queries the item's text.
  10888.  
  10889.    For nontext menu items, the hItem field of the MENUITEM data structure
  10890.    typically contains a handle of a display object, such as a bitmap handle
  10891.    for MIS_BITMAP menu items. You can change the Item field for a menu item
  10892.    by sending an MM_QUERYITEM message to the menu to fill in the MENUITEM
  10893.    structure, changing the relevant fields, and then sending the structure
  10894.    back to the menu with an MM_SETITEM message.
  10895.  
  10896.  17.5.10  Adding and Deleting Menu Items
  10897.  
  10898.    An application can add and delete items from its menus dynamically by
  10899.    sending MM_INSERTITEM and MM_DELETEITEM messages to the menu window. Any
  10900.    item, including those in submenus, can be deleted by sending a message to
  10901.    the menu-bar window. Messages to insert items in submenus must be sent to
  10902.    the submenu's pull-down menu window (rather than to the menu-bar window).
  10903.    The handle of the pull-down menu window can be obtained by sending an
  10904.    MM_QUERYITEM message to the menu-bar window and specifying the identifier
  10905.    of the submenu item for the submenu, as shown in the following code
  10906.    fragment:
  10907.  
  10908.    /* IDM_MYMENUID is the ID of the submenu containing the item. */
  10909.  
  10910.    MENUITEM mi;
  10911.  
  10912.    hwndActionBar = WinWindowFromID(hwndFrame, FID_MENU);
  10913.    WinSendMsg(hwndActionBar,                   /* handle of menu bar  */
  10914.        MM_QUERYITEM,                           /* message             */
  10915.        MPFROM2SHORT(IDM_MYMENUID, TRUE),       /* submenu identifier  */
  10916.        (MPARAM) &mi);                          /* pointer to MENUITEM */
  10917.  
  10918.    hwndpulldown = mi.hwndSubMenu;              /* handle to submenu   */
  10919.  
  10920.  
  10921.    Once the application has the handle of the pull-down menu window, it can
  10922.    insert an item by filling in a MENUITEM structure and sending an
  10923.    MM_INSERTITEM message to the pull-down menu. For text-menu items, the
  10924.    application must send a pointer to the text string as well as to the
  10925.    MENUITEM structure.
  10926.  
  10927.    mi.iPosition = MIT_END;
  10928.    mi.afStyle = MIS_TEXT;
  10929.    mi.afAttribute = 0;
  10930.    mi.id = IDM_MYMENU_FIRST;
  10931.    mi.hwndSubMenu = NULL;
  10932.    mi.hItem = NULL;
  10933.  
  10934.    WinSendMsg(hwndpulldown, MM_INSERTITEM, (PMENUITEM) &mi,
  10935.        (MPARAM) szNewItemString);
  10936.  
  10937.    To delete an item, the application sends an MM_DELETEITEM message to the
  10938.    menu-bar window, specifying the identifier of the item to delete. For
  10939.    example, to clear all the items following IDM_MYMENU_FIRST in a submenu in
  10940.    which the items are numbered sequentially, you would use the following
  10941.    code fragment:
  10942.  
  10943.    /* Clear all the items in MYMENU. */
  10944.  
  10945.    hwndActionBar = WinWindowFromID(hwndFrame, FID_MENU);
  10946.    usItemNum = IDM_MYMENU_FIRST;
  10947.    while (WinSendMsg(hwndActionBar, MM_DELETEITEM,
  10948.        MPFROM2SHORT(usItemNum++, TRUE), (MPARAM) 0L));
  10949.  
  10950.    Adding a complete submenu to the menu bar is a more complicated procedure
  10951.    than shown in the previous examples. There are two strategies. The
  10952.    recommended technique is to define all possible submenus in your
  10953.    resource-definition file and then selectively remove and insert the
  10954.    submenus as needed as your program runs.
  10955.  
  10956.    For example, assume that your program has a submenu that you want to be
  10957.    displayed only when a particular application tool is in use. You define
  10958.    the submenu as part of the main menu resource in your resource-definition
  10959.    file, so that the system reads in the resource menu template and creates
  10960.    the submenu window along with the rest of the menu. You can then remove
  10961.    the submenu from the menu bar, saving the title of the submenu and the
  10962.    MENUITEM data structure that defines the submenu, as shown in the
  10963.    following code fragment:
  10964.  
  10965.    HWND hwndActionBar;
  10966.    MENUITEM mi;
  10967.    CHAR szMenuTitle[MAX_STRINGSIZE];
  10968.  
  10969.    /* Remove a submenu so that you can replace it later. */
  10970.  
  10971.    /* Obtain the handle of a menu menu. */
  10972.  
  10973.    hwndActionBar = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE),
  10974.        FID_MENU);
  10975.  
  10976.    /* Obtain information on the item to remove. */
  10977.  
  10978.    WinSendMsg(hwndActionBar, MM_QUERYITEM,
  10979.        MPFROM2SHORT(IDM_MENUID, TRUE), /* TRUE to search submenus */
  10980.        &mi);
  10981.  
  10982.    /* Save the text for the submenu item. */
  10983.  
  10984.    WinSendMsg(hwndActionBar, MM_QUERYITEMTEXT,
  10985.        MPFROM2SHORT(IDM_FONT, MAX_STRINGSIZE),
  10986.        szMenuTitle);
  10987.  
  10988.    /* Remove the item, but retain mi and szMenuTitle. */
  10989.  
  10990.    WinSendMsg(hwndMenu, MM_REMOVEITEM,
  10991.        MPFROM2SHORT(IDM_FONT, TRUE), NULL);
  10992.  
  10993.    It is important to use the MM_REMOVEITEM message to remove the item,
  10994.    rather than the MM_DELETEITEM message; deleting the item destroys the
  10995.    submenu window but removing it does not destroy the submenu. The submenu
  10996.    should remain intact so that you can insert it later.
  10997.  
  10998.    To reinsert the submenu, send an MM_INSERTITEM message to the menu bar,
  10999.    passing the MENUITEM structure and menu title that you saved when you
  11000.    removed the item. The following code fragment shows how to insert a
  11001.    submenu that was removed by using the previous code example:
  11002.  
  11003.    /* Put the submenu back in and obtain the handle of the menu bar. */
  11004.  
  11005.    hwndMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE),
  11006.                               FID_MENU);
  11007.  
  11008.    /* Use the information that you saved when you removed the menu. */
  11009.  
  11010.    WinSendMsg(hwndMenu, MM_INSERTITEM, &mi, szMenuTitle);
  11011.  
  11012.    The other technique that you can use to insert a submenu in the menu bar
  11013.    is to build up a data structure as a menu template in memory and use that
  11014.    template and the WinCreateWindow function to create a submenu window. The
  11015.    resulting submenu window handle is then placed in the hwndSubMenu field of
  11016.    a nMENUITEM structure and the menu item is sent to the menu bar with an
  11017.    MM_INSERTITEM message.
  11018.  
  11019.    You also can create an empty submenu window by using the WinCreateWindow
  11020.    function. Pass NULL for the pCtlData and pPresParams parameters, instead
  11021.    of building the menu template in memory. Then insert a new menu item into
  11022.    the menu bar by using the MM_INSERTITEM message, setting the style
  11023.    MIS_SUBMENU, and putting the window handle of the created menu into the
  11024.    hwndSubMenu parameter. Then use the MM_INSERTITEM message to insert the
  11025.    items into the new pull-down menu.
  11026.  
  11027.  17.5.11  Owner-Drawn Menu Items
  11028.  
  11029.    Applications can customize the appearance of an individual menu item by
  11030.    setting the MIS_OWNERDRAW style bit for the item. MS OS/2 sends two
  11031.    different messages to an application that includes owner-drawn menu items:
  11032.    WM_MEASUREITEM and WM_DRAWITEM. Both messages include a pointer to an
  11033.    OWNERITEM data structure, as shown in the following code fragment:
  11034.  
  11035.    typedef struct _OWNERITEM {
  11036.        HWND    hwnd;           /* handle of menu window               */
  11037.        HPS     hps;            /* presentation space in which to draw */
  11038.        USHORT  fsState;        /* requested style                     */
  11039.        USHORT  fsAttribute;    /* requested attribute                 */
  11040.        USHORT  fsStateOld;     /* current style                       */
  11041.        USHORT  fsAttributeOld; /* current attribute                   */
  11042.        RECTL   rclItem;        /* bounding rectangle of item          */
  11043.        SHORT   idItem;         /* item identifier                     */
  11044.        ULONG   hItem;          /* handle of item-display object       */
  11045.    } OWNERITEM;
  11046.  
  11047.    The WM_MEASUREITEM message is sent only once for each owner-drawn item,
  11048.    when the menu is initialized. The message is sent to the menu's owner
  11049.    window (typically, a frame window), which forwards the message to its
  11050.    client window. Typically, the client window procedure processes the
  11051.    message WM_MEASUREITEM by filling in the yTop and xRight fields of the
  11052.    RECTL structure specified by the rclItem field of this OWNERITEM
  11053.    structure; this specifies the size of the rectangle needed to enclose the
  11054.    item when it is drawn. The code fragment shown below responds to a
  11055.    WM_MEASUREITEM message. If your owner-drawn menu contains text, you should
  11056.    compute the size of the items from the height of the system font or some
  11057.    other system characteristic.
  11058.  
  11059.    case WM_MEASUREITEM:
  11060.        (POWNERITEM) mp2->rclItem.xRight = 26;
  11061.        (POWNERITEM) mp2->rclItem.yTop = 10;
  11062.        return ((MRESULT) 0);
  11063.  
  11064.    If a menu item has the MIS_OWNERDRAW style, the owner window receives a
  11065.    WM_DRAWITEM message every time the menu item needs to be drawn. You should
  11066.    process this message by using the hps and rclItem fields of the OWNERITEM
  11067.    structure to draw the item. There are two situations in which the owner
  11068.    window receives a WM_DRAWITEM message:
  11069.  
  11070.    ■  The item needs to be completely redrawn.
  11071.  
  11072.    ■  The item needs to highlighted or unhighlighted.
  11073.  
  11074.    You can choose to handle one or both of these situations. Typically, you
  11075.    handle the drawing of the item. The system default behavior of inverting
  11076.    the item rectangle to show that the item is selected is often acceptable,
  11077.    however, so you may not want to do this yourself.
  11078.  
  11079.    The two situations in which a WM_DRAWITEM message is received are detected
  11080.    by comparing the values of the fsAttribute and fsAttributeOld fields of
  11081.    the OWNERITEM structure that is sent as part of the message. If the two
  11082.    fields are the same, you should draw the item. When drawing the item, you
  11083.    can also check the attributes of the item to see if the item has the
  11084.    MIA_CHECKED, MIA_FRAMED, or MIA_DISABLED attribute. You should draw the
  11085.    item according to the settings of the attribute bits. For example, when
  11086.    the checked attribute of a owner-drawn menu item changes, the system sends
  11087.    a WM_DRAWITEM message to the item so that it can redraw itself and either
  11088.    draw or remove the check mark. If you want the system default check mark,
  11089.    simply draw the item and leave the fsAttribute and fsAttributeOld fields
  11090.    unchanged; the system will draw the check mark, if necessary. If you draw
  11091.    the check mark yourself, clear the MIA_CHECKED bit in both fsAttribute and
  11092.    fsAttributeOld, so that the system does not attempt to draw a check mark.
  11093.  
  11094.    If the fsAttribute and fsAttributeOld fields of the OWNERITEM structure in
  11095.    a WM_DRAWITEM message are not equal, the highlight showing that an item
  11096.    is selected needs to change. The MIA_HILITED bit of the fsAttribute field
  11097.    is set if the item needs to be highlighted and is not set if the item
  11098.    needs to be unhighlighted. If you do not wish to provide your own, you
  11099.    should ignore any WM_DRAWITEM message in which fsAttribute and
  11100.    fsAttributeOld are not equal. If you do not alter these two fields, the
  11101.    system performs its default highlighting operation, which is to invert the
  11102.    bits within the item rectangle. If, however, you wish to provide your own
  11103.    visual cue that an item is selected, you should respond to a WM_DRAWITEM
  11104.    message in which fsAttribute and fsAttributeOld are not equal by providing
  11105.    the cue and then clearing the MIA_HILITED bit of both fsAttribute and
  11106.    fsAttributeOld before returning from the message.
  11107.  
  11108.    Likewise, the MIA_CHECKED and MIA_FRAMED bits of the fsAttribute and
  11109.    fsAttributeOld fields can either be used to perform the corresponding
  11110.    action or can be passed on unchanged so that the system performs the
  11111.    action.
  11112.  
  11113.    The following code fragment shows how to respond to a WM_DRAWITEM message
  11114.    when you want to draw the item and also be responsible for its
  11115.    highlighted/unhighlighted state:
  11116.  
  11117.    case WM_DRAWITEM:
  11118.        POWNERITEM poi;
  11119.        RECTL      rcl;
  11120.  
  11121.        poi = (POWNERITEM) mp2;
  11122.  
  11123.        /*
  11124.         * If the new attribute equals the old attribute,
  11125.         * redraw the entire item.
  11126.         */
  11127.  
  11128.        if (poi->fsAttribute == poi->fsAttributeOld) {
  11129.  
  11130.            /*
  11131.             * Draw the item in poi->hps and poi->rclItem,
  11132.             * and check the attributes for check marks. If you
  11133.             * produce your own check marks, use this line of code:
  11134.             * poi->fsAttributeOld = (poi->fsAttribute &= ~MIA_CHECKED;
  11135.             */
  11136.  
  11137.        /* Else the item should be highlighted or unhighlighted. */
  11138.  
  11139.        } else if ((poi->fsAttribute & MIA_HILITED) !=
  11140.                (poi->fsAttributeOld & MIA_HILITED)) {
  11141.  
  11142.            /*
  11143.             * Set bits the same so that the menu system does not make
  11144.             * the item highlighted or unhighlighted.
  11145.             */
  11146.  
  11147.            poi->fsAttributeOld = (poi->fsAttribute &= ~MIA_HILITED);
  11148.        }
  11149.        return TRUE; /* TRUE means item is drawn */
  11150.  
  11151.  
  11152.  17.6  Summary
  11153.  
  11154.    This section describes the styles, attributes, functions, and messages
  11155.    associated with menus.
  11156.  
  11157.  17.6.1  Menu-Item Styles
  11158.  
  11159.    Menu item styles determine what kind of data a menu contains (text,
  11160.    bitmap, etc.), how the menu is displayed (whether or not it is drawn by
  11161.    the owner), and what kind of message it generates when chosen (WM_COMMAND,
  11162.    WM_SYSCOMMAND, or WM_HELP). Menu-item styles are set when the menu item is
  11163.    created and are not typically changed at run time. Menu item attributes,
  11164.    described in the next section, are used for the aspects of a menu item
  11165.    that change frequently while a program is running.
  11166.  
  11167.    MIS_BITMAP  The menu-display object is a bitmap.
  11168.  
  11169.    MIS_BREAK  The item begins a new row or column.
  11170.  
  11171.    MIS_BREAKSEPARATOR  Same as MIS_BREAK, except that it draws a separator
  11172.    between rows or columns.
  11173.  
  11174.    MIS_BUTTONSEPARATOR  The item cannot be selected by using the cursor keys,
  11175.    but it can be selected by using the mouse or the appropriate accelerator
  11176.    key. A menu bar can have zero, one, or two button-separator items. They
  11177.    are always placed at the right side of the menu bar or at the bottom of a
  11178.    pull-down menu.
  11179.  
  11180.    MIS_HELP  A command item with this style notifies its owner window
  11181.    that it has been chosen by using a WM_HELP message rather than a
  11182.    WM_COMMAND message.
  11183.  
  11184.    MIS_OWNERDRAW  The item is drawn by the owner window. The menu sends
  11185.    WM_DRAWITEM and WM_MEASUREITEM messages to the owner window to draw the
  11186.    item and specify its size.
  11187.  
  11188.    MIS_SEPARATOR  This item is a horizontal dividing line in a pull-down
  11189.    menu. It cannot be checked, disabled, or selected.
  11190.  
  11191.    MIS_STATIC  The item is for information only. It cannot be selected by
  11192.    using the mouse or keyboard.
  11193.  
  11194.    MIS_SUBMENU  The item is a submenu item. When the user selects a submenu
  11195.    item, a pull-down menu window is displayed from which the user can choose
  11196.    a command item.
  11197.  
  11198.    MIS_SYSCOMMAND  A command item with this style notifies its owner window
  11199.    that it has been chosen by using a WM_SYSCOMMAND message, rather than a
  11200.    WM_COMMAND message. MIS_TEXT  The menu-display object is a text string.
  11201.    This is the default menu-item style.
  11202.  
  11203.    The following menu-item styles are mutually exclusive; they may not be
  11204.    specified in combination with each other:
  11205.  
  11206.         MIS_BITMAP
  11207.         MIS_OWNERITEM
  11208.         MIS_SEPARATOR
  11209.         MIS_TEXT
  11210.  
  11211.    Likewise, the following menu-item styles are mutually exclusive:
  11212.  
  11213.          MIS_HELP
  11214.          MIS_SYSCOMMAND
  11215.  
  11216.  17.6.2  Menu-Item Attributes
  11217.  
  11218.    Menu-item attributes specify changing display aspects of a menu item, such
  11219.    as its highlighted, and checked state. Attributes are set when the item is
  11220.    created and typically can change frequently as the program executes and
  11221.    the user interacts with the menus.
  11222.  
  11223.    MIA_CHECKED  Set to produce a check mark to the left of the item.
  11224.  
  11225.    MIA_ENABLED  Set when the item can be selected by the user. If not set,
  11226.    the item is drawn grayed and cannot be selected by the user. An
  11227.    application should disable a menu item when choosing it would be
  11228.    inappropriate──for example, a Save menu item should be disabled when there
  11229.    have been no changes since the last save operation.
  11230.  
  11231.    MIA_FRAMED  Set when a submenu item in the menu bar is framed by vertical
  11232.    lines to the left and right when its pull-down menu is displayed. This is
  11233.    typically handled by the system; an application does not usually have to
  11234.    set this attribute.
  11235.  
  11236.    MIA_HILITED  Set only when the item is currently selected. The application
  11237.    rarely sets this attribute directly, relying instead on the default
  11238.    processing of user input to set the highlighted state of an item.
  11239.  
  11240.  17.6.3  Menu Functions
  11241.  
  11242.    Most applications will not use the menu functions listed below, relying
  11243.    instead on the automatic association of menus and frame windows provided
  11244.    by menu resources and the WinCreateStdWindow function. These menu
  11245.    functions are useful if you want to use menus in a nonstandard way.
  11246.  
  11247.    WinCreateMenu  Creates a menu window from a menu-template data structure,
  11248.    assigning ownership to the specified window. This function is like the
  11249.    WinLoadMenu function, except that the menu data is stored as a menu
  11250.    template in memory, rather than in a resource-definition file.
  11251.  
  11252.    WinLoadMenu  Loads a menu resource from the specified resource-definition
  11253.    file (NULL for the current application's resource file) and assigns
  11254.    ownership to the specified window. The menu is owned by the specified
  11255.    window and is displayed when the owner window receives a WM_UPDATEFRAME
  11256.    message.
  11257.  
  11258.  17.6.4  Messages Sent from a Menu to an Owner Window
  11259.  
  11260.    These messages are sent from a menu to an owner. If the owner window is a
  11261.    standard frame window, the messages are passed to the client window's
  11262.    window procedure. All applications that use menus must respond to
  11263.    WM_COMMAND messages. Other messages in this section are appropriate for
  11264.    applications that use the more advanced features of menus.
  11265.  
  11266.    WM_COMMAND  Notifies the owner window when the user chooses a menu item.
  11267.    Applications must respond to this message to use menus.
  11268.  
  11269.    WM_SYSCOMMAND  Notifies the owner window when the user chooses a System
  11270.    menu item; this is equal to the WM_COMMAND message except that the menu
  11271.    item has the MIS_SYSCOMMAND style. The frame window usually does not pass
  11272.    this message to the client window. To process a WM_SYSCOMMAND message, the
  11273.    application must subclass the frame window.
  11274.  
  11275.    WM_HELP  Notifies the owner window when the user chooses a Help menu item;
  11276.    equal to the WM_COMMAND message except that the menu item has the MIS_HELP
  11277.    style. This message is usually generated by the "F1=Help" command item in
  11278.    the menu bar. Applications should respond to this message with a help
  11279.    dialog-box or by using the help-hook facility.
  11280.  
  11281.    WM_INITMENU  Notifies the owner window that the menu or submenu is about
  11282.    to be displayed. This message allows an application to change the state of
  11283.    a menu before the menu is displayed.
  11284.  
  11285.    WM_MENUSELECT  Notifies the owner window each time a menu item is
  11286.    selected. Applications do not need to handle this message to obtain the
  11287.    default menu behavior. For example, an application receives multiple
  11288.    WM_MENUSELECT messages when a user moves the mouse pointer up and down in
  11289.    a menu while the mouse button is pressed. This message allows an
  11290.    application to perform some other action coincident with the selection of
  11291.    a menu item, such as displaying a context-appropriate message in another
  11292.    part of the window. This message is also sent when the user actually
  11293.    chooses a menu item. If the application returns FALSE in response to this
  11294.    message when the user chooses a menu item, the command associated with the
  11295.    menu item is not posted, and the menu is not dismissed.
  11296.  
  11297.    WM_MENUEND  Notifies the owner window when exiting from menu mode.
  11298.  
  11299.    WM_DRAWITEM  Notifies the owner window when an item with the style
  11300.    MIA_OWNERDRAW needs to be drawn. Applications with owner-drawn menu items
  11301.    must respond to this message. The message contains a pointer to a data
  11302.    structure containing a presentation space handle and a rectangle in which
  11303.    to draw the item.
  11304.  
  11305.    WM_MEASUREITEM  Allows the owner window to specify the dimensions of an
  11306.    owner-drawn menu item. Applications with owner-drawn menu items must
  11307.    respond to this message.
  11308.  
  11309.    WM_QUERYFOCUSCHAIN  Temporarily sets the focus to the menu bar while in
  11310.    menu mode. This message is routed to the window from which the menu took
  11311.    the focus. WM_FOCUSCHANGE  Exits from menu mode, if the menu is losing the
  11312.    focus. If the exit operation fails, this message sets the state and is
  11313.    passed to the window that had the focus before menu mode was started.
  11314.  
  11315.    WM_SETFOCUS  Posts an MM_STARTMENUMODE message to initiate menu
  11316.    processing, if receiving the focus. If losing the focus, call the
  11317.    WinDefWindowProc function.
  11318.  
  11319.    WM_QUERYDLGCODE  Returns DLGC_MENU or DLGC_STATIC to indicate that this is
  11320.    a menu control and that the menu should not receive the focus when the
  11321.    user presses the DIRECTION keys or the TAB key.
  11322.  
  11323.    WM_PAINT  Draws the menu.
  11324.  
  11325.    WM_CREATE  Creates a list of items from the menu-template structure.
  11326.  
  11327.    WM_DESTROY  Destroys the menu and all its submenus and any display objects
  11328.    associated with the menu items.
  11329.  
  11330.    WM_ENABLE  Invalidates the window rectangle, causing it to be redrawn.
  11331.  
  11332.    WM_ADJUSTWINDOWPOS  Reformats the contents of the menu window.
  11333.  
  11334.    WM_CONTROLHEAP  Notifies the owner of a menu that a control needs the
  11335.    handle of a heap from which memory will be allocated.
  11336.  
  11337.    WM_CONTROLPOINTER  Notifies the owner of a menu that the mouse pointer is
  11338.    over the window.
  11339.  
  11340.    WM_BUTTON1DOWN  Begins processing a user's menu choice.
  11341.  
  11342.    WM_MOUSEMOVE  Sets the default mouse pointer (arrow cursor).
  11343.  
  11344.    WM_BUTTON2DOWN  Activates the menu window.
  11345.  
  11346.    WM_BUTTON3DOWN  Activates the menu window.
  11347.  
  11348.    WM_QUERYCONVERTPOS  Determines whether or not to begin double-byte
  11349.    character set (Kanji) conversion. Menus in MS OS/2 version 1.1 return
  11350.    QCP_NOCONVERT, which indicates that the menu code does not set up
  11351.    the rectangle pointed to by the mp1 parameter with the cursor bounding
  11352.    rectangle and that conversion should not be performed. Edit controls
  11353.    return QCP_CONVERT and fill in a RECTL structure with the cursor
  11354.    boundaries. (Programs can use this rectangle to position a Kanji window
  11355.    next to the cursor.)
  11356.  
  11357.  17.6.5  Messages Sent to a Menu
  11358.  
  11359.    The messages in this section are sent to menus, either by the system or by
  11360.    applications. Many of these messages are for manipulating the data that
  11361.    represents the state of menu items. Applications will find these messages
  11362.    useful for dynamically adjusting menus to reflect the current processing
  11363.    environment. Other messages in this section control the display of menu
  11364.    items during menu selection; these typically are sent automatically by the
  11365.    system, although an application can send them to control its menus more
  11366.    directly and override the default behavior.
  11367.  
  11368.    MM_QUERYITEMCOUNT  Returns the number of items in the menu. For the menu
  11369.    bar, this is the number of items in the menu bar. For a submenu, this is
  11370.    the number of items in the submenu. MM_STARTMENUMODE  Starts
  11371.    menu-selection processing, including mouse tracking for menu-item
  11372.    selection.
  11373.  
  11374.    MM_ENDMENUMODE  Exits from menu mode and hides any active submenus.
  11375.  
  11376.    MM_INSERTITEM  Insert the specified menu item in the menu.
  11377.  
  11378.    MM_DELETEITEM  Removes the specified item from the menu and destroys any
  11379.    resources and data structures for that item (such as display objects or
  11380.    submenus).
  11381.  
  11382.    MM_REMOVEITEM  Same as the MM_DELETEITEM message, except that it does not
  11383.    destroy associated submenus or display objects.
  11384.  
  11385.    MM_SELECTITEM  Selects the specified item; and if the fDismiss flag is
  11386.    set, posts a WM_COMMAND, WM_SYSCOMMAND, or WM_HELP message.
  11387.  
  11388.    MM_QUERYSELITEMID  Returns the identifier of the currently selected item.
  11389.  
  11390.    MM_QUERYITEM  Copies information about a specified item into a
  11391.    caller-supplied MENUITEM data structure.
  11392.  
  11393.    MM_QUERYITEMTEXT  Copies the text for a specified menu item into a
  11394.    caller-supplied buffer.
  11395.  
  11396.    MM_QUERYITEMTEXTLENGTH  Returns the length of the text, not including the
  11397.    NULL terminator, for a specified item.
  11398.  
  11399.    MM_SETITEMHANDLE  Sets the menu-item handle for a nontext item and forces
  11400.    the item to be redrawn.
  11401.  
  11402.    MM_SETITEMTEXT  Sets the text for a menu item and forces the item to be
  11403.    redrawn.
  11404.  
  11405.    MM_ISITEMVALID  Returns TRUE if item can be selected.
  11406.  
  11407.    MM_SETITEM  Sets the state of an item, based on the data in a MENUITEM
  11408.    structure, and forces the item to be redrawn.
  11409.  
  11410.    MM_ITEMPOSITIONFROMID  Returns the position of a menu item in a menu
  11411.    window, searching submenus if requested.
  11412.  
  11413.    MM_ITEMIDFROMPOSITION  Returns the identifier of the menu item at the
  11414.    specified position in the menu window.
  11415.  
  11416.    MM_QUERYITEMATTR  Returns the current attributes of a menu item.
  11417.  
  11418.    MM_SETITEMATTR  Sets the specified attributes of a menu item.
  11419.  
  11420.  
  11421.  
  11422.  ────────────────────────────────────────────────────────────────────────────
  11423.  Chapter 18  Accelerator Tables
  11424.  
  11425.         18.1    Introduction
  11426.         18.2    About Accelerator Tables
  11427.         18.3    Accelerator Tables in a Resource-Definition File
  11428.         18.4    Accelerator-Table Data Structures
  11429.         18.5    Using an Accelerator Table in an Application
  11430.             18.5.1    Including an Accelerator Table in a Frame Window
  11431.             18.5.2    Modifying an Accelerator Table
  11432.         18.6    Summary
  11433.             18.6.1    Functions
  11434.             18.6.2    Accelerator-Item Styles
  11435.             18.6.3    Messages
  11436.  
  11437.  18.1  Introduction
  11438.  
  11439.    This chapter describes how to use accelerator tables in your applications.
  11440.    You should also be familiar with the following topics:
  11441.  
  11442.    ■  Standard user-interface guidelines
  11443.  
  11444.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  11445.  
  11446.    ■  Menus
  11447.  
  11448.    ■  Creating standard frame windows
  11449.  
  11450.    ■  Window messages and the message queue
  11451.  
  11452.  
  11453.  18.2  About Accelerator Tables
  11454.  
  11455.    Accelerators are keystrokes that generate command messages for an
  11456.    application; they elicit the same behavior as choosing a menu item. Menus
  11457.    provide an easy way to learn an application's command set, but
  11458.    accelerators provide quicker access to those commands.
  11459.  
  11460.    Accelerators filter keyboard input. Accelerator keystrokes are translated
  11461.    into command messages before they reach the application. When an
  11462.    accelerator is used, the application receives a command message rather
  11463.    than a keyboard message.
  11464.  
  11465.    Accelerators function differently from the usual keyboard-to-menu
  11466.    interface. By default, a user can use the ALT key to access submenus and
  11467.    the arrow keys to move along the menu bar. Accelerators provide single
  11468.    keystrokes that generate command messages without the visual effects of
  11469.    pulling down menus or stepping from one item to another.
  11470.  
  11471.    Like menu items, accelerators can generate WM_COMMAND, WM_HELP, and
  11472.    WM_SYSCOMMAND messages, depending on the setting of the accelerator's
  11473.    style bits. Although accelerators are normally used to generate commands
  11474.    that already exist as menu items, they can also send commands that have no
  11475.    equivalent menu items.
  11476.  
  11477.    An accelerator table contains an array of accelerators. Accelerator tables
  11478.    exist at two levels within MS OS/2. MS OS/2 maintains a single accelerator
  11479.    table for the system queue and individual accelerator tables for
  11480.    application windows. Accelerators in the system queue apply to all
  11481.    applications──for example, the F1 key always generates a WM_HELP message.
  11482.    Having accelerators for individual application windows ensures that an
  11483.    application can define its own accelerators without interfering with other
  11484.    applications. An accelerator for an application window overrides the
  11485.    accelerator in the system queue. An application can modify both its own
  11486.    accelerator table and the system accelerator table.
  11487.  
  11488.  
  11489.  18.3  Accelerator Tables in a Resource-Definition File
  11490.  
  11491.    An application that uses accelerators typically creates an accelerator
  11492.    table resource-definition file containing its accelerators and associates
  11493.    that resource with a standard frame window when the window is created.
  11494.  
  11495.    The resource-definition file of an accelerator table is a list of
  11496.    accelerator items. Each item defines the keystroke that triggers the
  11497.    accelerator, the command that the accelerator generates, and the
  11498.    accelerator's style. The style bits specify whether the keystroke is a
  11499.    virtual key, a character, or a scan code, and whether the message that is
  11500.    generated is WM_COMMAND, WM_SYSCOMMAND, or WM_HELP. (WM_COMMAND is the
  11501.    default message.)
  11502.  
  11503.    A resource-definition file for an accelerator table is shown in the
  11504.    following code fragment:
  11505.  
  11506.    ACCELTABLE      ID_ACCEL_RESOURCE
  11507.    BEGIN
  11508.        VK_ESC,     IDM_ED_UNDO,   VIRTUALKEY,  SHIFT
  11509.        VK_DELETE,  IDM_ED_CUT,    VIRTUALKEY
  11510.        VK_F2,      IDM_ED_COPY,   VIRTUALKEY
  11511.        VK_INSERT,  IDM_ED_PASTE,  VIRTUALKEY
  11512.    END
  11513.  
  11514.    This accelerator table has four accelerator items. The first one is
  11515.    triggered when the user presses SHIFT+ESC; it sends a WM_COMMAND message
  11516.    (the default) just as if the IDM_ED_UNDO menu item had been chosen.
  11517.  
  11518.    The accelerator table resource-definition file has a
  11519.    resource-identification number that is usually the same as the identifier
  11520.    of the application's menu resource; this allows the accelerator table to
  11521.    be associated with a standard frame window when the frame window is
  11522.    created. You can also define accelerator-table resources with other
  11523.    identification numbers and associate them with windows after the windows
  11524.    are created.
  11525.  
  11526.  
  11527.  18.4  Accelerator-Table Data Structures
  11528.  
  11529.    Applications that manipulate accelerator tables can refer to them with a
  11530.    32-bit handle (HACCEL). Using this handle allows an application to make
  11531.    most API function calls for accelerators without needing to account for
  11532.    the internal structures that define the accelerator table. To use
  11533.    accelerator tables in the default manner, it is sufficient to define the
  11534.    table in the resource-definition file and associate it with a standard
  11535.    frame window when creating the window. When an application needs to
  11536.    dynamically create or change an accelerator table, it must use the ACCEL
  11537.    and ACCELTABLE data structures.
  11538.  
  11539.    An accelerator table is made up of individual accelerator items. Each item
  11540.    is represented by an ACCEL data structure that defines the accelerator's
  11541.    style, keystroke, and command identifier. The ACCEL structure has the
  11542.    following form:
  11543.  
  11544.    typedef struct _ACCEL {
  11545.        USHORT fs;
  11546.        USHORT key;
  11547.        USHORT cmd;
  11548.    } ACCEL;
  11549.  
  11550.    Typically, an application defines the aspects of the accelerator in the
  11551.    resource-definition file for the accelerator, but the data structure can
  11552.    be built in memory at run time, if necessary.
  11553.  
  11554.    An accelerator table is made up of one or more accelerator items and
  11555.    information that specifies the number of accelerator items in the table
  11556.    and the code page used for the keystrokes in the accelerator items. The
  11557.    ACCELTABLE structure has the following form:
  11558.  
  11559.    typedef struct _ACCELTABLE {
  11560.        SHORT  cAccel;
  11561.        USHORT codepage;
  11562.        ACCEL  aaccel[1];
  11563.    } ACCELTABLE;
  11564.  
  11565.    Notice that the array of accelerator items is defined as having only one
  11566.    member. Applications that use accelerator-table data structures directly
  11567.    must allocate sufficient memory to hold all the items in the table.
  11568.  
  11569.  
  11570.  18.5  Using an Accelerator Table in an Application
  11571.  
  11572.    An application can automatically load an accelerator table
  11573.    resource-definition file when creating a standard frame window, or it can
  11574.    load the resource independently and associate it with a window or with the
  11575.    entire system.
  11576.  
  11577.    An application can set and query the accelerator tables for a specific
  11578.    window or for the entire system. For example, an application could query
  11579.    the system accelerator table, copy it, modify the copied accelerator-table
  11580.    data structures, and then use the modified copy to set the system
  11581.    accelerator table. An application that does this should maintain the
  11582.    original accelerator table and restore it when the application terminates.
  11583.    An application can also modify its window's accelerator table at run time
  11584.    to respond more appropriately to the current environment.
  11585.  
  11586.  18.5.1  Including an Accelerator Table in a Frame Window
  11587.  
  11588.    An application can add an accelerator table to a frame window either by
  11589.    using the WinSetAccelTable function or by defining an accelerator-table
  11590.    resource and creating a frame window with the FCF_ACCELTABLE frame style.
  11591.    The second method is shown in the following code fragment:
  11592.  
  11593.    ULONG lControlStyle = FCF_MENU | FCF_SIZEBORDER
  11594.                          | FCF_TITLEBAR | FCF_ACCELTABLE;
  11595.  
  11596.    hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE,
  11597.        &lControlStyle, szClassName, szTitle, 0L, NULL, ID_MENU_RESOURCE,
  11598.        &hwndClient);
  11599.  
  11600.    Note that if you set the lControlStyle parameter to FCF_STANDARD you must
  11601.    define an accelerator-table resource, because FCF_STANDARD includes the
  11602.    FCF_ACCELTABLE flag.
  11603.  
  11604.    If the window being created also has a menu, the menu resource and the
  11605.    accelerator resource must have the same resource identifier; this is
  11606.    because the WinCreateStdWindow function has only one input parameter to
  11607.    specify the resource ID of menus, accelerator tables, and icons. If an
  11608.    application creates a resource-definition file for the accelerator table
  11609.    and then opens a standard frame window, as shown in the preceding example,
  11610.    the accelerator table is automatically installed in the window's input
  11611.    queue and keyboard events are translated during normal events-processing.
  11612.    The application responds to WM_COMMAND, WM_SYSCOMMAND, and WM_HELP
  11613.    messages; it does not matter whether they come from a menu or from an
  11614.    accelerator.
  11615.  
  11616.    An application can also add an accelerator table to a window by calling
  11617.    the WinSetAccelTable function with an accelerator-table handle and a
  11618.    frame-window handle. The application can call either the WinLoadAccelTable
  11619.    function to retrieve an accelerator table from a resource file or the
  11620.    WinCreateAccelTable function to create an accelerator table from an
  11621.    accelerator-table data structure in memory.
  11622.  
  11623.  18.5.2  Modifying an Accelerator Table
  11624.  
  11625.    An application can modify an accelerator table, either for its own windows
  11626.    or for the system, by retrieving the handle of the accelerator table,
  11627.    using the handle to copy the accelerator-table data to an
  11628.    application-supplied buffer, changing the data in the buffer, and then
  11629.    using the data in the buffer to create a new accelerator table. The
  11630.    application can then use the new accelerator-table handle to set the
  11631.    accelerator table, either for a window or for the system. This process is
  11632.    outlined in the following list:
  11633.  
  11634.    1.  Call the WinQueryAccelTable function to retrieve an accelerator-table
  11635.        handle.
  11636.  
  11637.    2.  Call the WinCopyAccelTable function with a null buffer handle to
  11638.        determine how many bytes are in the table.
  11639.  
  11640.    3.  Allocate sufficient memory for the accelerator-table data.
  11641.  
  11642.    4.  Call the WinCopyAccelTable function with a pointer to the allocated
  11643.        memory.
  11644.  
  11645.    5.  Modify the data in the buffer (assuming it has the form of an
  11646.        ACCELTABLE data structure).
  11647.  
  11648.    6.  Call the WinCreateAccelTable function, passing a pointer to the buffer
  11649.        with the modified accelerator-table data.
  11650.  
  11651.    7.  Call the WinSetAccelTable function with the handle returned by the
  11652.        WinCreateAccelTable function.
  11653.  
  11654.  
  11655.  18.6  Summary
  11656.  
  11657.    This section summarizes the functions, styles, and messages related to
  11658.    accelerator tables.
  11659.  
  11660.  18.6.1  Functions
  11661.  
  11662.    The following functions allow your application to use accelerator tables:
  11663.  
  11664.    WinCopyAccelTable  Copies the specified accelerator table to an
  11665.    application-provided ACCELTABLE data structure.
  11666.  
  11667.    WinCreateAccelTable  Creates an accelerator table using an ACCELTABLE data
  11668.    structure. This is similar to the WinLoadAccelTable function except that
  11669.    this function does not use resources.
  11670.  
  11671.    WinDestroyAccelTable  Destroys the specified accelerator table.
  11672.  
  11673.    WinLoadAccelTable  Loads a specified accelerator table from a specified
  11674.    dynamic-link module (the module handle is NULL for the current
  11675.    application) and returns a handle of the accelerator table.
  11676.  
  11677.    WinQueryAccelTable  Returns the accelerator-table handle for the specified
  11678.    window, or for the system if the window handle is NULL.
  11679.  
  11680.    WinSetAccelTable  Sets the accelerator table for the specified window, or
  11681.    for the system if the window handle is NULL. WinSetAccelTable will remove
  11682.    an existing accelerator table if the accelerator-table handle is NULL.
  11683.  
  11684.    WinTranslateAccel  Translates a WM_CHAR message into a WM_COMMAND,
  11685.    WM_SYSCOMMAND, or WM_HELP message by using the specified accelerator
  11686.    table. This function is normally called automatically by the WinGetMsg or
  11687.    WinPeekMsg function when a WM_CHAR message is received.
  11688.  
  11689.  18.6.2  Accelerator-Item Styles
  11690.  
  11691.    The following accelerator-item styles are specified in the fs field of the
  11692.    ACCEL structure:
  11693.  
  11694.    AF_ALT  Means the ALT key must be held down when the key is pressed.
  11695.  
  11696.    AF_CHAR  Means the keystroke is a translated character, using the code
  11697.    page for the accelerator table. This is the default style.
  11698.  
  11699.    AF_CONTROL  Means the CTRL key must be held down when the key is pressed.
  11700.  
  11701.    AF_HELP  Means the accelerator generates a WM_HELP message instead of a
  11702.    WM_COMMAND message.
  11703.  
  11704.    AF_LONEKEY  Means no other key is pressed while the key is down. This
  11705.    style is typically used with the ALT key to specify that simply pressing
  11706.    and releasing the ALT key triggers the accelerator.
  11707.  
  11708.    AF_SCANCODE  Means the keystroke is an untranslated scan code from the
  11709.    keyboard.
  11710.  
  11711.    AF_SHIFT  Means the SHIFT key must be held down when the key is pressed.
  11712.  
  11713.    AF_SYSCOMMAND  Means a WM_SYSCOMMAND message is generated by the
  11714.    accelerator, instead of a WM_COMMAND message.
  11715.  
  11716.    AF_VIRTUALKEY  Means the keystroke is a virtual key──for example, the F1
  11717.    function key.
  11718.  
  11719.  18.6.3  Messages
  11720.  
  11721.    The following messages are used in the management of accelerator tables:
  11722.  
  11723.    WM_QUERYACCELTABLE  Sent to a frame window by the WinQueryAccelTable
  11724.    function.
  11725.  
  11726.    WM_SETACCELTABLE  Sent to a frame window by the WinSetAccelTable function.
  11727.  
  11728.    WM_TRANSLATEACCEL  Sent to a frame window by the WinTranslateAccel
  11729.    function.
  11730.  
  11731.  
  11732.  
  11733.  ────────────────────────────────────────────────────────────────────────────
  11734.  Chapter 19  Dialog Windows
  11735.  
  11736.         19.1    Introduction
  11737.         19.2    About Dialog Windows
  11738.             19.2.1    Modal and Modeless Dialog Windows
  11739.             19.2.2    Dialog Items
  11740.             19.2.3    Dialog-Control Groups
  11741.             19.2.4    Message Boxes
  11742.         19.3    Dialog Data Structures
  11743.             19.3.1    Dialog Coordinates
  11744.         19.4    Dialog Resources
  11745.         19.5    Using Message and Dialog Boxes
  11746.             19.5.1    Message Boxes
  11747.                 19.5.1.1   System-Modal Message Boxes
  11748.             19.5.2    Dialog Boxes
  11749.                 19.5.2.1   Modal Dialog Boxes
  11750.                 19.5.2.2   Modeless Dialog Boxes
  11751.                 19.5.2.3   Initializing a Dialog Box
  11752.                 19.5.2.4   Menus in Dialog Boxes
  11753.                 19.5.2.5   Dialog Procedure
  11754.                 19.5.2.6   Manipulating Dialog Items
  11755.         19.6    Summary
  11756.             19.6.1    Dialog-Window Styles
  11757.             19.6.2    Message-Box Styles
  11758.             19.6.3    Message-Box Return Values
  11759.             19.6.4    Functions
  11760.             19.6.5    Messages Sent to Dialog Boxes and Dialog Items
  11761.  
  11762.  19.1  Introduction
  11763.  
  11764.    This chapter describes creating and using dialog windows and message boxes
  11765.    in your applications. You should also be familiar with the following
  11766.    topics:
  11767.  
  11768.    ■  Standard user interface guidelines
  11769.  
  11770.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  11771.  
  11772.    ■  Control windows
  11773.  
  11774.    ■  Window messages and message queues
  11775.  
  11776.  
  11777.  19.2  About Dialog Windows
  11778.  
  11779.    A dialog window (also called a dialog box or a dialog) is a window that
  11780.    contains one or more child control windows and is typically used to
  11781.    display messages to and gather input from the user. It is often a
  11782.    temporary window that an application creates to gather specific input,
  11783.    destroying the window immediately after use.
  11784.  
  11785.    Dialog windows provide a high-level method for applications to display and
  11786.    gather information. MS OS/2 contains many functions and messages that help
  11787.    manage the control windows that make up a dialog window, thus easing the
  11788.    burden of maintaining complex input and output systems.
  11789.  
  11790.  19.2.1  Modal and Modeless Dialog Windows
  11791.  
  11792.    Dialog windows can be modal or modeless. A modal dialog window requires
  11793.    that the dialog window be dismissed before the user can activate other
  11794.    windows in the same application. Generally, an application uses a modal
  11795.    dialog window to get essential information from the user before proceeding
  11796.    with an operation. A modeless dialog window allows the user to activate
  11797.    other windows without dismissing the dialog window.
  11798.  
  11799.    Both modal and modeless dialog windows allow the user to activate windows
  11800.    in another application before responding to the dialog window. For more
  11801.    information, see Section 19.2.4.
  11802.  
  11803.    Modal dialog windows are simpler for an application to manage because they
  11804.    are created, perform their task, and close, all in a single function call.
  11805.  
  11806.    Modeless dialog windows require more attention from the application
  11807.    because they exist until explicitly dismissed. Modeless dialog windows
  11808.    provide a more flexible interface, however, by allowing the user to move
  11809.    to other windows in the application before responding to the dialog
  11810.    window.
  11811.  
  11812.  19.2.2  Dialog Items
  11813.  
  11814.    A dialog item is a child window of the dialog window. The dialog window is
  11815.    usually a window of class WC_FRAME. MS OS/2 provides many predefined
  11816.    window classes, called control windows, that are used as dialog items.
  11817.    Predefined control windows include static display boxes, text-entry
  11818.    fields, buttons, and list boxes. Customized window classes can also be
  11819.    used as dialog items.
  11820.  
  11821.    Because dialog items are windows, they can be manipulated by all
  11822.    window-management functions relating to size, position, and visibility.
  11823.    Dialog items are always owned by the dialog frame window. Most predefined
  11824.    control-window classes send notification messages to their owners when the
  11825.    user interacts with their control windows. The dialog frame window
  11826.    receives these notification messages and passes them on to the application
  11827.    through the application-defined dialog procedure.
  11828.  
  11829.  19.2.3  Dialog-Control Groups
  11830.  
  11831.    Items within a dialog window can be organized into groups. When items are
  11832.    arranged in a group, the user can move from one item to another in the
  11833.    same group by using the direction keys. When the user presses a direction
  11834.    key, the focus moves from one item in a group to the next item of the same
  11835.    group, but not to items of other groups within the dialog window.
  11836.  
  11837.    Arranging items in groups is useful for radio buttons. Although other
  11838.    control types can also be displayed this way, entry-field controls cannot;
  11839.    they process direction keys themselves.
  11840.  
  11841.    The first item in a dialog-control group has the WS_GROUP window style.
  11842.    All subsequent items in the dialog template are considered part of that
  11843.    group until another item is given the WS_GROUP style, which begins a new
  11844.    group.
  11845.  
  11846.    The WS_TABSTOP style is often used along with the WS_GROUP style. This
  11847.    style marks the items that can receive the focus when the user presses the
  11848.    TAB key. Each time the user presses the TAB key, the focus moves to the
  11849.    next item that has the WS_TABSTOP style. Generally, the WS_GROUP and
  11850.    WS_TABSTOP styles are defined together for the first item of each group in
  11851.    the dialog template. This makes it possible for a user to press the TAB
  11852.    key to move between groups of items and to use the direction keys to move
  11853.    between items within a group.
  11854.  
  11855.    The WS_TABSTOP style should not be used for radio buttons because the
  11856.    system automatically maintains a tabstop on any selected item in a
  11857.    radio-button group; the focus will always be on the currently selected
  11858.    item when pressing the TAB key in a group of radio buttons.
  11859.  
  11860.    The WS_GROUP and WS_TABSTOP styles are also useful for preventing the user
  11861.    from moving to a particular button when using the keyboard. For example,
  11862.    if the dialog window has an OK and a Cancel button, you should put them in
  11863.    the same group, with the OK button as the first item in the group. The
  11864.    user can press the TAB key to select the OK button, but not the Cancel
  11865.    button. To move to the Cancel button by using the keyboard, the user must
  11866.    first press the TAB key to move to the OK button, and then press a
  11867.    direction key to move the focus to the Cancel button. For more information
  11868.    on how to define groups and tabstops in dialog windows, see Section 19.4.
  11869.  
  11870.  19.2.4  Message Boxes
  11871.  
  11872.    Message boxes are dialog windows predefined by the system and used as a
  11873.    simple interface for applications without creating dialog-template
  11874.    resources or dialog procedures. An application can call the WinMessageBox
  11875.    function and specify the type of message box and message text. The system
  11876.    displays the message and waits for the user to dismiss the message box by
  11877.    selecting a button in the message box. The system then returns a result
  11878.    code to the application, indicating which button the user selected.
  11879.  
  11880.    Message boxes are best for short notification messages that require a
  11881.    simple acknowledgment or choice by the user. Applications do not specify a
  11882.    dialog procedure for message boxes, so they cannot readily change the
  11883.    action of a message box. There are many predefined message-box styles.
  11884.    Figure 19.1 shows a sample message box.
  11885.  
  11886.    ┌────────────────────────────────────────────────────────────────────────┐
  11887.    │ Figure 19.1 can be found in Section 19.2.4 of the printed manual.      │
  11888.    └────────────────────────────────────────────────────────────────────────┘
  11889.  
  11890.    Figure 19.1  Sample Message Box
  11891.  
  11892.    Message boxes can be application-modal or system-modal. Application-modal
  11893.    means that the user cannot activate another window in the current
  11894.    application before responding to the message box, but can switch to
  11895.    another application before responding. System-modal means that the user
  11896.    cannot activate another window in any application while the message box is
  11897.    present. A system-modal message box should be used only to display urgent
  11898.    error messages (running out of memory, for example).
  11899.  
  11900.  
  11901.  19.3  Dialog Data Structures
  11902.  
  11903.    A dialog-window item is a control window that is owned by the dialog
  11904.    window. Each dialog-window item is described by a DLGTITEM data structure.
  11905.    The DLGTITEM structure is rarely accessed directly by an application. Most
  11906.    manipulation of dialog items is handled by system functions. Applications
  11907.    that create dialog items that are not defined as part of a dialog-template
  11908.    resource must create dialog-window-item structures in memory. The format
  11909.    of a DLGTITEM structure is as follows:
  11910.  
  11911.    typedef struct _DLGTITEM {
  11912.        USHORT    fsItemStatus;
  11913.        USHORT    cChildren;
  11914.        USHORT    cchClassName;
  11915.        USHORT    offClassName;
  11916.        USHORT    cchText;
  11917.        USHORT    offText;
  11918.        ULONG     flStyle;
  11919.        SHORT     x;
  11920.        SHORT     y;
  11921.        SHORT     cx;
  11922.        SHORT     cy;
  11923.        USHORT    id;
  11924.        USHORT    offPresParams;
  11925.        USHORT    offCtlData;
  11926.    } DLGTITEM;
  11927.  
  11928.    Because a dialog window can have many items, a DLGTEMPLATE data structure
  11929.    consists of header information followed by an array of dialog-window
  11930.    items. Applications that create dialog windows without using dialog
  11931.    resources must create a dialog template in memory and then call the
  11932.    WinCreateDlg function. The format of a DLGTEMPLATE structure is as
  11933.    follows:
  11934.  
  11935.    typedef struct _DLGTEMPLATE {
  11936.        USHORT      cbTemplate;
  11937.        USHORT      type;
  11938.        USHORT      codepage;
  11939.        USHORT      offadlgti;
  11940.        USHORT      fsTemplateStatus;
  11941.        USHORT      iItemFocus;
  11942.        USHORT      coffPresParams;
  11943.        DLGTITEM    adlgti[1];
  11944.    } DLGTEMPLATE;
  11945.  
  11946.  19.3.1  Dialog Coordinates
  11947.  
  11948.    Coordinates in a dialog template are specified in dialog coordinates and
  11949.    are based on the size of the system font. A horizontal unit is one-fourth
  11950.    of the system-font-character average width; a vertical unit is one-eighth
  11951.    of the system-font-character average height. The origin of the dialog
  11952.    template is the lower-left corner of the dialog window. MS OS/2 provides
  11953.    the WinMapDlgPoints function for converting dialog coordinates into window
  11954.    coordinates.
  11955.  
  11956.  
  11957.  19.4  Dialog Resources
  11958.  
  11959.    Most applications define dialog templates in resource files rather than
  11960.    constructing template data structures in memory at run time. The
  11961.    dialog-resource file defines the size and style of the dialog-window frame
  11962.    and specifies each control item.
  11963.  
  11964.    The following source-code fragment creates a dialog template. Notice that
  11965.    the WS_GROUP and WS_TABSTOP style designations are given for the first
  11966.    item in each group. The dimensions and position for each item are given in
  11967.    dialog coordinates rather than in window coordinates.
  11968.  
  11969.    DLGTEMPLATE IDD_ABOUT
  11970.    BEGIN
  11971.      DIALOG "", IDD_ABOUT2, 10, 10, 150, 110, FS_DLGBORDER, 0
  11972.      BEGIN
  11973.        CONTROL "Attributes:",100,
  11974.          10, 30, 100, 70,
  11975.          WC_STATIC,
  11976.          SS_GROUPBOX | WS_VISIBLE
  11977.        CONTROL "Highlighted",101,
  11978.          20, 80, 58, 12,
  11979.          WC_BUTTON,
  11980.          WS_GROUP | WS_TABSTOP | BS_AUTOCHECKBOX | WS_VISIBLE
  11981.        CONTROL "Enabled",102,
  11982.          20, 60, 58, 12,
  11983.          WC_BUTTON,
  11984.          BS_AUTOCHECKBOX | WS_VISIBLE
  11985.        CONTROL "Checked",103,
  11986.          20, 40, 58, 12,
  11987.          WC_BUTTON,
  11988.          BS_AUTOCHECKBOX | WS_VISIBLE
  11989.        CONTROL "Okay", DID_OK,
  11990.          10, 10, 50, 14,
  11991.          WC_BUTTON,
  11992.          WS_GROUP | WS_TABSTOP | BS_PUSHBUTTON | BS_DEFAULT | WS_VISIBLE
  11993.        CONTROL "Cancel", DID_CANCEL,
  11994.          80, 10, 50, 14,
  11995.          WC_BUTTON,
  11996.          BS_PUSHBUTTON | WS_VISIBLE
  11997.      END
  11998.    END
  11999.  
  12000.    Figure 19.2 shows the dialog box created by the previous dialog-template
  12001.    resource definition:
  12002.  
  12003.    ┌────────────────────────────────────────────────────────────────────────┐
  12004.    │ Figure 19.2 can be found in Section 19.4 of the printed manual.        │
  12005.    └────────────────────────────────────────────────────────────────────────┘
  12006.  
  12007.    Figure 19.2  Sample Dialog Box
  12008.  
  12009.  
  12010.  19.5  Using Message and Dialog Boxes
  12011.  
  12012.    The simplest dialog window is the message box. Most message boxes present
  12013.    simple messages and offer the user one, two, or three responses
  12014.    (represented by buttons). A message box is easy to use and is appropriate
  12015.    when an application requires a clearly defined response to a static
  12016.    message. However, message boxes lack flexibility in size and placement on
  12017.    the screen, and they are limited in the choices they offer the user.
  12018.    Applications that require more control over size, position, and content
  12019.    should use regular dialog boxes instead of message boxes.
  12020.  
  12021.  19.5.1  Message Boxes
  12022.  
  12023.    Message boxes provide an easy way for applications to display simple
  12024.    messages without creating dialog templates or writing dialog procedures.
  12025.    Message boxes are intended mainly for conveying information to users,
  12026.    although they do have limited input capabilities.
  12027.  
  12028.    There are several different kinds of predefined message boxes. There are
  12029.    three parts to a message box: the icon, the message, and buttons.
  12030.    Applications specify the icons and buttons using message-box style
  12031.    constants. Message text is specified by a null-terminated string.
  12032.  
  12033.    To create a message box, the application calls the WinMessageBox function,
  12034.    which displays the message box and processes user input until the user
  12035.    selects a button in the message box. The return value of the WinMessageBox
  12036.    function indicates which button was selected.
  12037.  
  12038.    The following code fragment illustrates how to create a message box with a
  12039.    default Yes button, a No button, and a question-mark (?) icon. This exam-
  12040.    ple assumes that you have defined a string resource with the identifier
  12041.    MY_MESSAGESTR_ID in the resource file.
  12042.  
  12043.    CHAR szMessageString[255];
  12044.    USHORT cch;
  12045.    USHORT usResult;
  12046.  
  12047.    cch = WinLoadString(hab,
  12048.        (HMODULE) NULL,
  12049.        MY_MESSAGESTR_ID,
  12050.        sizeof(szMessageString),
  12051.        szMessageString);
  12052.  
  12053.    usResult = WinMessageBox(hwndFrame,  /* parent    */
  12054.        hwndFrame,                       /* owner     */
  12055.        szMessageString,                 /* text      */
  12056.        (PSZ) "",                        /* caption   */
  12057.        MY_MESSAGEWIN,                   /* window ID */
  12058.        MB_YESNO |
  12059.        MB_ICONQUESTION |
  12060.        MB_DEFBUTTON1);                  /* style     */
  12061.  
  12062.     if (usResult == MBID_YES)
  12063.  
  12064.          /* do yes case */
  12065.  
  12066.     else
  12067.  
  12068.          /* do no case  */
  12069.  
  12070.    The WinMessageBox function returns predefined values indicating which
  12071.    button has been selected. These values are listed in Section 19.6.3.
  12072.  
  12073.    Note that strings for message boxes should be defined as string resources
  12074.    to facilitate program translation for other countries. However, there is a
  12075.    danger in using string resources in message boxes that are called in
  12076.    low-memory situations. Loading a string resource in these situations could
  12077.    cause severe memory problems and cause an application to fail. One way to
  12078.    solve this problem is to preload the string resource and make it
  12079.    nondiscardable so it will be available when the message box must be
  12080.    displayed.
  12081.  
  12082.    19.5.1.1  System-Modal Message Boxes
  12083.  
  12084.    Message boxes are always modal. The default style for a message box is
  12085.    application-modal. With this style, a user cannot select another window in
  12086.    the same application until the message box is dismissed. However, the user
  12087.    can switch to a different application.
  12088.  
  12089.    It is possible to create a message box that is system-modal. A
  12090.    system-modal message box prevents a user from selecting another window in
  12091.    the current application or switching to a different application until
  12092.    responding to the message box. A system-modal message box is useful when
  12093.    displaying a warning to the user that there may be serious problems with
  12094.    the system, such as insufficient memory.
  12095.  
  12096.    There are two levels of modality for system-modal message boxes──soft
  12097.    modal and hard modal. A soft-modal message box does not allow keystrokes
  12098.    or mouse input to reach any other window, but does allow other messages,
  12099.    such as deactivation and timer messages, to reach other windows. A
  12100.    hard-modal message box does not allow any messages to reach other windows.
  12101.    A hard-modal message box is appropriate for serious system warnings.
  12102.  
  12103.    A hard-modal message box is created by combining the MB_ICONHAND
  12104.    style with the MB_SYSTEMMODAL style. A soft-modal message box is
  12105.    created by using the MB_SYSTEMMODAL style with any style other than
  12106.    MB_ICONHAND. The MB_SYSTEMMODAL icon is always in memory and is available
  12107.    even in low-memory situations.
  12108.  
  12109.  19.5.2  Dialog Boxes
  12110.  
  12111.    When using dialog boxes, an application must load the dialog box, process
  12112.    user input, and destroy the dialog box when the user finishes the task.
  12113.    The process for handling dialog boxes varies, depending on whether the
  12114.    dialog box is modal or modeless. A modal dialog box requires the user to
  12115.    dismiss the dialog box before activating another window in the
  12116.    application. However, the user can activate windows in different
  12117.    applications. A modeless dialog box does not require an immediate response
  12118.    from the user. It is similar to a frame window containing control windows.
  12119.    The following sections discuss how to use both types of dialog boxes.
  12120.  
  12121.    19.5.2.1  Modal Dialog Boxes
  12122.  
  12123.    Modal dialog boxes present users with information and questions in such a
  12124.    way that they must respond before proceeding with other operations in the
  12125.    application.
  12126.  
  12127.    The easiest way to use a modal dialog box is to define a dialog template
  12128.    in the resource file and then call the WinDlgBox function, specifying the
  12129.    dialog-box resource ID and a pointer to the dialog procedure. The
  12130.    WinDlgBox function loads the dialog-box resource, displays the dialog box,
  12131.    and handles all user input until the user dismisses the dialog box. The
  12132.    dialog procedure receives messages when the dialog box is created
  12133.    (WM_INITDLG) and other messages when the user interacts with each dialog
  12134.    item, such as entering text in entry fields or selecting buttons.
  12135.  
  12136.    You must specify both the parent and owner windows when loading a dialog
  12137.    box using the WinDlgBox function. Generally, the parent window should be
  12138.    HWND_DESKTOP and the owner should be a client window in your application.
  12139.  
  12140.    Dialog boxes typically contain buttons that send WM_COMMAND messages when
  12141.    selected by the user. WM_COMMAND messages passed to the WinDefDlgProc
  12142.    function result in the WinDismissDlg function being called, with the
  12143.    window ID of the source button as the return code. Dialog boxes with OK or
  12144.    Cancel as the only buttons can ignore WM_COMMAND messages, allowing them
  12145.    to be passed to the WinDefDlgProc function. The WinDefDlgProc function
  12146.    calls the WinDismissDlg function to dismiss the dialog box and returns the
  12147.    DID_OK or DID_CANCEL code.
  12148.  
  12149.    Passing WM_COMMAND messages to the WinDefDlgProc function means that all
  12150.    button presses in the dialog box will dismiss the dialog box. If you want
  12151.    particular buttons to initiate operations without closing the dialog box
  12152.    or if you want to perform some processing without closing the dialog box,
  12153.    you should handle the WM_COMMAND messages in the dialog procedure.
  12154.  
  12155.    If you handle WM_COMMAND messages in the dialog procedure, you must call
  12156.    the WinDismissDlg function to dismiss the dialog box. Your dialog
  12157.    procedure passes the DID_OK code to the WinDismissDlg function if the user
  12158.    selects the OK button or the DID_CANCEL code if the user selects the
  12159.    Cancel button.
  12160.  
  12161.    When you call the WinDismissDlg function or pass the WM_COMMAND message to
  12162.    the WinDefDlgProc function, the dialog box is dismissed and the WinDlgBox
  12163.    function returns the value passed to the WinDismissDlg function. This
  12164.    return value identifies the button selected.
  12165.  
  12166.    An alternative to using the WinDlgBox function is to call the individual
  12167.    functions that duplicate its functionality, as shown in the following code
  12168.    fragment:
  12169.  
  12170.    dlg = WinLoadDlg(...);
  12171.    result = WinProcessDlg(dlg);
  12172.    WinDestroyWindow(dlg);
  12173.  
  12174.    After calling the WinProcessDlg function, your dialog procedure must call
  12175.    the WinDismissDlg function to dismiss the dialog box. Although the dialog
  12176.    box is dismissed (hidden), it still exists. You must call the
  12177.    WinDestroyWindow function to destroy a dialog box if it was loaded using
  12178.    the WinLoadDlg function. The WinDlgBox function automatically destroys a
  12179.    dialog box before returning.
  12180.  
  12181.    If you want to manipulate individual items in a dialog box or add a menu
  12182.    after loading the dialog box (but before calling WinProcessDlg), it is
  12183.    better to make individual calls rather than calling the WinDlgBox
  12184.    function. Individual calls are also useful for querying individual dialog
  12185.    items, such as the contents of an entry-field control after a dialog box
  12186.    is closed but before it is destroyed. Destroying a dialog box also
  12187.    destroys any dialog-item control windows that are child windows of the
  12188.    dialog box.
  12189.  
  12190.    19.5.2.2  Modeless Dialog Boxes
  12191.  
  12192.    A modeless dialog box, unlike a modal dialog box, does not require user
  12193.    interaction to activate another window in the current application.
  12194.  
  12195.    To use a modeless dialog box in an application, you should create a dialog
  12196.    template in the resource file, just as for a modal dialog box. Because
  12197.    modeless dialog boxes share the screen equally with other frame windows,
  12198.    it is a good idea to give modeless dialog boxes a title bar so they can be
  12199.    moved around the screen. The following Resource Compiler source fragment
  12200.    shows a dialog template for a dialog box with a title bar, a System menu,
  12201.    and a Minimize Box.
  12202.  
  12203.    DLGTEMPLATE IDD_SAMP
  12204.    BEGIN
  12205.        DIALOG "Modeless Dialog", IDD_SAMP, 80, 92, 126, 130,
  12206.            WS_VISIBLE | FS_DLGBORDER,
  12207.            FCF_TITLEBAR | FCF_SYSMENU | FCF_MINIMIZE
  12208.        BEGIN
  12209.  
  12210.        /* Put control-window definitions here. */
  12211.  
  12212.        END
  12213.    END
  12214.  
  12215.    The application loads the dialog resource from the resource file by using
  12216.    the WinLoadDlg function, receiving in return a window handle to the dialog
  12217.    box. The application treats the dialog box as if it were an ordinary
  12218.    window. Messages for the dialog box are dispatched through the event loop
  12219.    the application uses for its other windows. In fact, an application can
  12220.    have a modeless dialog box as its only window.
  12221.  
  12222.    The resource for a modeless dialog box is just like that used for a modal
  12223.    dialog box. The difference between modal and modeless dialog boxes is in
  12224.    the way applications handle input to each box. For a modal dialog, the
  12225.    WinDlgBox and WinProcessDlg functions handle all user input to the dialog
  12226.    box, preventing access to other windows in the application. For a modeless
  12227.    dialog box, the application does not call these functions, relying instead
  12228.    on a normal message loop to dispatch messages to the dialog procedure.
  12229.  
  12230.    The main difference between a modeless dialog box and a standard frame
  12231.    window with child control windows is that for a modeless dialog box, an
  12232.    application can define child windows for the dialog box in a dialog
  12233.    template, automating the creation process of the window and its child
  12234.    windows. The same effect can be achieved by creating a standard frame
  12235.    window, but the child control windows must be created individually.
  12236.  
  12237.    It is important that an application keep track of all open modeless dialog
  12238.    boxes so that it can destroy all open windows before terminating.
  12239.  
  12240.    19.5.2.3  Initializing a Dialog Box
  12241.  
  12242.    Generally, an application defines a dialog template in its resource file
  12243.    and loads the dialog box by calling the WinLoadDlg function or the
  12244.    WinDlgBox function (which itself calls WinLoadDlg). The dialog box is
  12245.    created as an invisible window unless the window style WS_VISIBLE is
  12246.    specified in the dialog template. A WM_INITDLG message is sent to the
  12247.    dialog procedure before the WinLoadDlg function returns. As each control
  12248.    defined in the template is created, the dialog procedure may receive
  12249.    various control notifications before the function returns. A dialog window
  12250.    can be destroyed by using the WinDestroyWindow function. The WinLoadDlg
  12251.    function returns a handle to the dialog window immediately after creating
  12252.    a dialog box.
  12253.  
  12254.    In general, it is a good idea to define a dialog box as invisible since
  12255.    this allows for optimization. For example, an experienced user may rapidly
  12256.    type ahead, anticipating the processing of a dialog-box command. In such a
  12257.    case, there is no need to display the dialog box because the user has
  12258.    finished the interaction before the window can be displayed. This is how
  12259.    the WinProcessDlg function works──it does not display a dialog box while
  12260.    there are still WM_CHAR messages in the input queue. It allows these
  12261.    messages to be processed first.
  12262.  
  12263.    As control windows in a dialog box are created from the template, strings
  12264.    in the template are processed by the WinSubstituteStrings function. Any
  12265.    WM_SUBSTITUTESTRING messages are sent to the dialog procedure before the
  12266.    WinLoadDlg function returns.
  12267.  
  12268.    When child windows of a dialog window are created, the
  12269.    WinSubstituteStrings function is used so child windows can make
  12270.    substitutions in their window text. If any child-window text string
  12271.    contains the percent sign (%) substitution character, the length of the
  12272.    text string is limited to 256 characters after it is returned from the
  12273.    substitution.
  12274.  
  12275.    19.5.2.4  Menus in Dialog Boxes
  12276.  
  12277.    To create a menu bar and menus in a dialog box, an application should
  12278.    first load the dialog box to get a handle to the dialog-frame window. The
  12279.    dialog-frame window can be associated with a menu resource by calling the
  12280.    WinLoadMenu function. This function requires arguments specifying the menu
  12281.    ID and handle of the parent window for the menu. Finally, the dialog-frame
  12282.    window must incorporate the menu by sending a WM_UPDATEFRAME message to
  12283.    the dialog box. The following code fragment illustrates these operations:
  12284.  
  12285.    /* Get the dialog resource. */
  12286.  
  12287.    hwndDialog = WinLoadDlg(...);
  12288.  
  12289.    /* Get the menu resource and attach it to the dialog. */
  12290.  
  12291.    hwndMenu = WinLoadMenu(hwndDialog, ...);
  12292.  
  12293.    /* Inform the dialog that it has a new menu. */
  12294.  
  12295.    WinSendMsg(hwndDialog, WM_UPDATEFRAME, 0L, 0L);
  12296.  
  12297.    Applications can create menus in modal and modeless dialog boxes. The code
  12298.    fragment above can be used for either type of dialog box. In the case of a
  12299.    modal dialog box, your application should call the WinProcessDlg function
  12300.    to handle user input until the dialog box is dismissed. For a modeless
  12301.    dialog box, your application should call the WinShowWindow function to
  12302.    display the dialog box, allowing the message loop to direct messages to
  12303.    the dialog box.
  12304.  
  12305.    19.5.2.5  Dialog Procedure
  12306.  
  12307.    The main difference between a dialog procedure and a window procedure is
  12308.    that a dialog procedure does not receive WM_CREATE messages. Instead, a
  12309.    dialog procedure receives WM_INITDLG messages, which are sent after a
  12310.    dialog box is created but before it is displayed. The WM_INITDLG message
  12311.    can be used to do the same type of initialization tasks that are handled
  12312.    by WM_CREATE messages.
  12313.  
  12314.    For example, if a dialog box contains a list box, you should use the
  12315.    message WM_INITDLG to fill the list box with items. This procedure can
  12316.    also be used to enable or disable buttons in a dialog box, depending on
  12317.    your application.
  12318.  
  12319.    You can also call the WinSetDlgItemText or WinSetDlgItemShort function
  12320.    during dialog initialization to set up text items that reflect the current
  12321.    conditions in your application.
  12322.  
  12323.    Another typical task for the WM_INITDLG message handler is centering a
  12324.    dialog on the screen or within its owner window. The following code
  12325.    fragment illustrates how to center a dialog box on screen using the
  12326.    WM_INITDLG message:
  12327.  
  12328.    case WM_INITDLG:
  12329.        /* Center the dialog box and get the screen rectangle. */
  12330.  
  12331.        WinQueryWindowRect(HWND_DESKTOP, &rclScreenRect);
  12332.  
  12333.        /* Get the dialog-box rectangle. */
  12334.  
  12335.        WinQueryWindowRect(hwnd, &rclDialogRect);
  12336.  
  12337.        /* Get the dialog-box width. */
  12338.  
  12339.        sWidth = (SHORT) (rclDialogRect.xRight - rclDialogRect.xLeft);
  12340.  
  12341.        /* Get the dialog-box height. */
  12342.  
  12343.        sHeight = (SHORT) (rclDialogRect.yTop - rclDialogRect.yBottom);
  12344.  
  12345.        /* Set the lower-left corner horizontal coordinate. */
  12346.  
  12347.        sBLCx = ((SHORT) rclScreenRect.xRight - sWidth) / 2;
  12348.  
  12349.        /* Set the lower-left corner vertical coordinate. */
  12350.  
  12351.        sBLCy = ((SHORT) rclScreenRect.yTop - sHeight) / 2;
  12352.  
  12353.        /* Move, size, and show the window. */
  12354.  
  12355.        WinSetWindowPos(hwnd,
  12356.            HWND_TOP,
  12357.            sBLCx, sBLCy,
  12358.            0, 0,          /* ignores size arguments */
  12359.            SWP_MOVE);
  12360.  
  12361.        return 0L;
  12362.  
  12363.    The dialog procedure receives notification messages from each
  12364.    control-window item in a dialog box whenever a user clicks an item or
  12365.    enters text in an entry field. Most dialog procedures wait for the user to
  12366.    select one or more dialog-window buttons to signal that he or she has
  12367.    finished with the dialog box. When the dialog procedure receives one of
  12368.    these messages, it should call the WinDismissDlg function, as shown in the
  12369.    following code fragment. The second argument to the WinDismissDlg function
  12370.    is the value returned by the WinDlgBox or WinProcessDlg function.
  12371.    Generally, the ID of the button that was pressed is returned.
  12372.  
  12373.    MRESULT FAR PASCAL SampDialogProc(hwnd, usMessage, mp1, mp2)
  12374.    HWND hwnd;
  12375.    USHORT usMessage;
  12376.    MPARAM mp1;
  12377.    MPARAM mp2;
  12378.    {
  12379.        switch (usMessage) {
  12380.            case WM_COMMAND:
  12381.                switch (SHORT1FROMMP(mp1)) {
  12382.                    case DID_OK:
  12383.  
  12384.                       /*
  12385.                        * Final dialog-item queries,
  12386.                        * dismiss the dialog.
  12387.                        */
  12388.  
  12389.                       WinDismissDlg(hwnd, DID_OK);
  12390.                       return 0L;
  12391.                }
  12392.                break;
  12393.        }
  12394.        return (WinDefDlgProc(hwnd, usMessage, mp1, mp2));
  12395.    }
  12396.  
  12397.    Other dialog-box items send notification messages specific to the type of
  12398.    control window. Your dialog procedure should respond to notification
  12399.    messages from each dialog item. Any messages that a dialog procedure does
  12400.    not handle should be passed to the WinDefDlgProc function for default
  12401.    processing. The default dialog procedure is exactly the same as the
  12402.    default frame-window procedure.
  12403.  
  12404.    The WM_COMMAND message from the OK button indicates that the user has
  12405.    selected the OK button and is finished with the dialog box. If the dialog
  12406.    box has other controls, such as entry fields or check boxes, your dialog
  12407.    procedure should query the contents or state of each control when it
  12408.    receives a message from the OK button. Before dismissing a dialog box,
  12409.    your dialog procedure should collect input from each dialog-box control
  12410.    before closing the dialog box.
  12411.  
  12412.    19.5.2.6  Manipulating Dialog Items
  12413.  
  12414.    Dialog items are control windows, and as such they can be manipulated
  12415.    using standard window-management function calls. The window handle is
  12416.    obtained for each dialog item by calling the WinWindowFromID function and
  12417.    passing the window handle for the dialog box and the window ID for the
  12418.    dialog item as defined in the dialog template. For example, the following
  12419.    Resource Compiler source-code fragment should be included in your dialog
  12420.    template:
  12421.  
  12422.    DLGTEMPLATE IDD_ABOUT
  12423.    BEGIN
  12424.        DIALOG "", IDD_ABOUT, 80, 92, 126, 130, FS_DLGBORDER, 0
  12425.        BEGIN
  12426.            PUSHBUTTON "My Button", ITEMID_MYBUTTON, 37, 107, 56, 12
  12427.  
  12428.            /* Other item definitions ... */
  12429.  
  12430.        END
  12431.    END
  12432.  
  12433.    Based on the above code fragment, your application will receive the
  12434.    button-item handle by initiating the following call to the WinWindowFromID
  12435.    function:
  12436.  
  12437.    hwndItem = WinWindowFromID(hwndDialog, ITEMID_MYBUTTON);
  12438.  
  12439.    Applications often change the contents, enabled state, or position of
  12440.    dialog items at run time. For example, in a dialog box that contains a
  12441.    list box of filenames and an Open button, the Open button should be
  12442.    disabled until the user selects a file from the list. To do this, the
  12443.    button should be defined as disabled in the dialog resource so that it is
  12444.    disabled when the dialog box is first displayed. At run time, the dialog
  12445.    procedure receives a notification message from the list box when the user
  12446.    selects a file. At that time, the dialog procedure calls the
  12447.    WinEnableWindow function to enable the Open button.
  12448.  
  12449.    Applications can also change the text in static dialog items and buttons.
  12450.    This is done by calling the WinSetWindowText function and using the window
  12451.    handle of particular dialog item.
  12452.  
  12453.  
  12454.  19.6  Summary
  12455.  
  12456.    The following sections summarize the styles, functions, and messages
  12457.    associated with dialog windows and message boxes.
  12458.  
  12459.  19.6.1  Dialog-Window Styles
  12460.  
  12461.    The following style constants can be used to specify the border and
  12462.    alignment of a dialog box:
  12463.  
  12464.    FCF_DLGBORDER  Draws the dialog window with a double border that
  12465.    identifies it as a dialog box.
  12466.  
  12467.    FCF_MOUSEALIGN  Draws the dialog window using the x- and y-position
  12468.    relative to the mouse position at the time the dialog window is created.
  12469.    The dialog window position is modified to keep it within the screen
  12470.    boundaries, if possible. The dialog window can be drawn with the OK button
  12471.    under the mouse pointer by using negative x- and y-position values in the
  12472.    dialog template.
  12473.  
  12474.    FCF_SCREENALIGN  Draws the dialog window using the x- and y-position
  12475.    relative to the coordinates of the entire screen rather than using the
  12476.    default coordinates of the owner window.
  12477.  
  12478.  19.6.2  Message-Box Styles
  12479.  
  12480.    The following style constants can be used to specify the type of message
  12481.    box created by calling the WinMessageBox function:
  12482.  
  12483.    MB_ABORTRETRYIGNORE  Creates a message box that has Abort, Retry, and
  12484.    Ignore buttons.
  12485.  
  12486.    MB_APPLMODAL  Creates an application-modal message box. A user cannot
  12487.    select other windows in the current application, but can switch to other
  12488.    applications.
  12489.  
  12490.    MB_CANCEL  Creates a message box that has a Cancel button.
  12491.  
  12492.    MB_DEFBUTTON1  Defines the first button in a message box as the default
  12493.    button. All message boxes have this style unless MB_DEFBUTTON2 or
  12494.    MB_DEFBUTTON3 is specified.
  12495.  
  12496.    MB_DEFBUTTON2  Defines the second button as the default button.
  12497.  
  12498.    MB_DEFBUTTON3  Defines the third button as the default button.
  12499.  
  12500.    MB_ENTER  Creates a message box that has an Enter button.
  12501.  
  12502.    MB_ENTERCANCEL  Creates a message box that has Enter and Cancel buttons.
  12503.  
  12504.    MB_HELP  Creates a message box that has a Help button.
  12505.  
  12506.    MB_ICONASTERISK  Creates a message box that has an asterisk (*) icon.
  12507.  
  12508.    MB_ICONEXCLAMATION  Creates a message box that has a exclamation-point (!)
  12509.    icon.
  12510.  
  12511.    MB_ICONHAND  Creates a message box that has the hand icon. This icon is
  12512.    always in memory and should be used when displaying message boxes in
  12513.    low-memory situations.
  12514.  
  12515.    MB_ICONQUESTION  Creates a message box that has a question-mark (?) icon.
  12516.  
  12517.    MB_MOVEABLE  Creates a message box that a user can move by using the
  12518.    mouse.
  12519.  
  12520.    MB_NOICON  Creates a message box that has no icons.
  12521.  
  12522.    MB_OK  Creates a message box that has an OK button.
  12523.  
  12524.    MB_OKCANCEL  Creates a message box that has OK and Cancel buttons.
  12525.  
  12526.    MB_RETRYCANCEL  Creates a message box that has Retry and Cancel buttons.
  12527.  
  12528.    MB_SYSTEMMODAL  Creates a system-modal message box. A user cannot select
  12529.    any other window in the current application or switch to another
  12530.    application until this message box is dismissed. This style is used in
  12531.    combination with MB_ICONHAND to prevent any messages from being sent to
  12532.    other windows or applications. This is useful in situations where the
  12533.    system is damaged or there are other serious problems.
  12534.  
  12535.    MB_YESNO  Creates a message box that has Yes and No buttons.
  12536.  
  12537.    MB_YESNOCANCEL  Creates a message box that has Yes, No, and Cancel
  12538.    buttons.
  12539.  
  12540.  19.6.3  Message-Box Return Values
  12541.  
  12542.    The following are predefined values returned by the WinMessageBox
  12543.    function, indicating which button is pressed to dismiss the message box:
  12544.  
  12545.    MBID_ABORT  Abort button dismisses the message box.
  12546.  
  12547.    MBID_CANCEL  Cancel button dismisses the message box.
  12548.  
  12549.    MBID_ENTER  Enter button dismisses the message box.
  12550.  
  12551.    MBID_ERROR  An error has occurred in processing the message box.
  12552.  
  12553.    MBID_HELP  Help button dismisses the message box.
  12554.  
  12555.    MBID_IGNORE  Ignore button dismisses the message box.
  12556.  
  12557.    MBID_NO  No button dismisses the message box.
  12558.  
  12559.    MBID_OK  OK button dismisses the message box.
  12560.  
  12561.    MBID_RETRY  Retry button dismisses the message box.
  12562.  
  12563.    MBID_YES  Yes button dismisses the message box.
  12564.  
  12565.  19.6.4  Functions
  12566.  
  12567.    The following functions are used with dialog windows and message boxes:
  12568.  
  12569.    WinAlarm  Creates an audible signal. The type of sound is specified by one
  12570.    of three predefined constants: WA_WARNING, WA_NOTE, and WA_ERROR. The
  12571.    actual sound emitted for these styles varies, depending on the hardware
  12572.    capabilities.
  12573.  
  12574.    WinCreateDlg  Functions similarly to the WinLoadDlg function except that
  12575.    the WinCreateDlg function dialog template is in memory rather than in a
  12576.    resource file. This function returns a handle to the dialog window.
  12577.  
  12578.    WinDefDlgProc  Creates the default dialog procedure that processes dialog
  12579.    messages (messages that the application dialog procedure does not
  12580.    process). This action is identical to that produced by the
  12581.    WinDefWindowProc function for frame windows.
  12582.  
  12583.    WinDestroyWindow  Destroys the dialog window and all its child control
  12584.    windows. This function uses the dialog-window handle.
  12585.  
  12586.    WinDismissDlg  Hides the dialog box and causes the WinProcessDlg or
  12587.    WinDlgBox function to return a specified result. Applications call this
  12588.    function from a dialog procedure when a user selects a button indicating
  12589.    the interaction with the dialog box is finished.
  12590.  
  12591.    WinDlgBox  Loads and processes a modal dialog box and returns the result
  12592.    generated by the WinDismissDlg function. This function makes the dialog
  12593.    box visible when the message queue is empty. This means that a dialog box
  12594.    defined as invisible will not become visible as long as there is input for
  12595.    it. This allows a user to type ahead and even dismiss the dialog box
  12596.    before the dialog box becomes visible, thus saving the time needed to draw
  12597.    the dialog box. The WinDlgBox function is equivalent to the following code
  12598.    fragment:
  12599.  
  12600.    dlg = WinLoadDlg(...);
  12601.    result = WinProcessDlg(dlg);
  12602.    WinDestroyWindow(dlg);
  12603.    return (result);
  12604.  
  12605.    WinEnumDlgItem  Searches dialog-box child windows for the next control
  12606.    window that fits a specified characteristic. An application can specify a
  12607.    child window from which to start the search; this facilitates repeated
  12608.    linear searches for the next occurrence of a particular type of child
  12609.    window. This function allows an application to identify the next tabstop
  12610.    or group item.
  12611.  
  12612.    WinLoadDlg  Loads a dialog resource from a specified resource-file module
  12613.    (NULL indicates the current application's executable file). The parent and
  12614.    owner window of the new dialog box must specified, as well as a pointer to
  12615.    the dialog procedure for the application. This function returns a handle
  12616.    to the dialog window.
  12617.  
  12618.    WinMapDlgPoints  Converts dialog coordinates into window coordinates and
  12619.    vice versa.
  12620.  
  12621.    WinMessageBox  Creates a modal message box with specified caption, icon,
  12622.    buttons, and text. The WinMessageBox function maintains control until the
  12623.    user selects one of the message-box buttons. The return value is a
  12624.    predefined constant that indicates which button is selected.
  12625.  
  12626.    WinProcessDlg  Processes messages for a modal dialog box, making the
  12627.    dialog box visible when the message queue is empty. This means that a
  12628.    dialog box defined as invisible will not become visible as long as there
  12629.    is input for it. This allows a user to type ahead and even dismiss the
  12630.    dialog box before the dialog box becomes visible, thus saving the time
  12631.    needed to draw the dialog box. This function does not return until the
  12632.    dialog procedure calls the WinDismissDlg function.
  12633.  
  12634.    WinQueryDlgItemShort  Translates the text of a specified dialog item into
  12635.    a short integer.
  12636.  
  12637.    WinQueryDlgItemText  Retrieves the window text of a specified dialog item.
  12638.  
  12639.    WinSendDlgItemMsg  Sends a message to a child window in the specified
  12640.    dialog box. This function is used for child windows in standard frame
  12641.    windows.
  12642.  
  12643.    WinSetDlgItemShort  Sets the text of the specified dialog item to the text
  12644.    representation of the specified short integer.
  12645.  
  12646.    WinSetDlgItemText  Sets the window text for a specified dialog item.
  12647.  
  12648.    WinSubstituteStrings  Performs a substitution process on a text string,
  12649.    replacing certain marker characters with application-supplied text. When
  12650.    the string %n (where "n" is a number from 0 through 9) is encountered in
  12651.    the source string, a WM_SUBSTITUTESTRING message is sent to a specified
  12652.    window. This message returns a text string that replaces the characters %n
  12653.    in the destination string, which is an exact copy of the source string.
  12654.    This function is important for dialog boxes because the
  12655.    WM_SUBSTITUTESTRING message is received by the dialog procedure, allowing
  12656.    an application to make string substitutions in dialog items that reflect
  12657.    the current environment.
  12658.  
  12659.  19.6.5  Messages Sent to Dialog Boxes and Dialog Items
  12660.  
  12661.    The following messages are sent to dialog boxes and dialog items:
  12662.  
  12663.    WM_INITDLG  Sent to a dialog procedure after a dialog box is created but
  12664.    before it is shown. This allows an application to perform run-time
  12665.    initialization for the dialog box, such as filling in default text for
  12666.    entry fields, static-text controls, or list boxes. If any control window
  12667.    in a dialog box requires text substitution, the dialog box receives a
  12668.    WM_SUBSTITUTESTRING message before the WM_INITDLG message. The WM_INITDLG
  12669.    message also contains a window handle of the control window in the dialog
  12670.    box that receives the keyboard focus when the dialog box is shown. An
  12671.    application can change the focus by calling the WinSetFocus function for
  12672.    another control window and then returning TRUE. To leave the focus as is,
  12673.    it should return FALSE.
  12674.  
  12675.    WM_QUERYDLGCODE  Sent by the system to control windows in a dialog box to
  12676.    determine the capabilities of the control. Most applications ignore this
  12677.    message unless they are creating custom control windows. The following are
  12678.    predefined result codes for the WM_QUERYDLGCODE message:
  12679.  
  12680.    Code                Meaning
  12681.    ──────────────────────────────────────────────────────────────────────────
  12682.    DLGC_BUTTON         Button item
  12683.  
  12684.    DLGC_CHECKBOX       Check box
  12685.  
  12686.    DLGC_DEFAULT        Default push button
  12687.  
  12688.    DLGC_ENTRYFIELD     Entry-field item, handles EM_SETSEL messages
  12689.  
  12690.    DLGC_MENU           Menu
  12691.  
  12692.    DLGC_PUSHBUTTON     Non-default push button
  12693.  
  12694.    DLGC_RADIOBUTTON    Radio button
  12695.  
  12696.    DLGC_SCROLLBAR      Scroll bar
  12697.  
  12698.    DLGC_STATIC         Static item
  12699.  
  12700.    DLGC_TABONCLICK     Next-on-tab control
  12701.    ──────────────────────────────────────────────────────────────────────────
  12702.  
  12703.    WM_SUBSTITUTESTRING  Sent to a dialog box when it is created (before the
  12704.    WM_INITDLG message is sent) when the system encounters the characters %n
  12705.    (where n is a number from 0 through 9) in the window text of a dialog
  12706.    control window. This message allows an application dialog procedure to
  12707.    make text substitutions. For example, an application can define dialog-box
  12708.    entry-field text as the characters %1, substituting context-appropriate
  12709.    text in the response to the WM_SUBSTITUTESTRING message.
  12710.  
  12711.  
  12712.  
  12713.  ────────────────────────────────────────────────────────────────────────────
  12714.  Chapter 20  Painting and Drawing
  12715.  
  12716.         20.1    Introduction
  12717.         20.2    About Painting and Drawing
  12718.             20.2.1    Presentation Spaces and Device Contexts
  12719.             20.2.2    Window Regions
  12720.         20.3    Strategies for Painting and Drawing
  12721.             20.3.1    When to Draw in a Window
  12722.             20.3.2    The WM_PAINT Message
  12723.                 20.3.2.1   Drawing the Minimized View
  12724.             20.3.3    Drawing Without the WM_PAINT Message
  12725.             20.3.4    Three Kinds of Presentation Spaces
  12726.                 20.3.4.1   Cached-Micro Presentation Spaces
  12727.                 20.3.4.2   Micro Presentation Spaces
  12728.                 20.3.4.3   Normal Presentation Spaces
  12729.         20.4    Printing
  12730.         20.5    Summary
  12731.             20.5.1    Window Styles for Painting
  12732.             20.5.2    Functions
  12733.             20.5.3    Messages for Painting
  12734.  
  12735.  20.1  Introduction
  12736.  
  12737.    This chapter describes presentation spaces, device contexts, and window
  12738.    regions, and how an application uses them for painting and drawing. (For
  12739.    information on functions that are specifically designed for graphics
  12740.    production, see Chapter 21, "Drawing in Windows," and Part 3, "Graphics
  12741.    Programming Interface.") You should also be familiar with the following
  12742.    topics:
  12743.  
  12744.    ■  Standard user-interface guidelines
  12745.  
  12746.    ■  Standard frame windows
  12747.  
  12748.    ■  Window messages and message queues
  12749.  
  12750.    ■  Presentation spaces and device contexts
  12751.  
  12752.    ■  Graphics programming interface (GPI)
  12753.  
  12754.  
  12755.  20.2  About Painting and Drawing
  12756.  
  12757.    An application typically maintains an internal representation of the data
  12758.    that it is manipulating. The information displayed by a screen, window, or
  12759.    by printed copy is a visual representation of some portion of that data.
  12760.    MS OS/2 provides a rich environment for displaying information in a
  12761.    variety of ways. This chapter introduces concepts and strategies necessary
  12762.    to make your application function smoothly and cooperatively in the MS
  12763.    OS/2 display environment.
  12764.  
  12765.  20.2.1  Presentation Spaces and Device Contexts
  12766.  
  12767.    A presentation space is a data structure maintained by the operating
  12768.    system that describes the drawing environment for an application. An
  12769.    application can create and hold several presentation spaces, each
  12770.    describing a different drawing environment. All drawing in an MS OS/2
  12771.    application must be directed into a presentation space.
  12772.  
  12773.    Each presentation space is associated with a device context that describes
  12774.    the physical device where graphics commands are displayed. The device
  12775.    context translates graphics commands made to the presentation space into
  12776.    commands that cause the physical device to display information. Typical
  12777.    device contexts are the screen (windows), printers and plotters, and
  12778.    off-screen memory bitmaps. Figure 20.1 shows how graphics commands from
  12779.    an application go through a presentation space, to a device context, and
  12780.    then to the physical device.
  12781.  
  12782.    ┌────────────────────────────────────────────────────────────────────────┐
  12783.    │ Figure 20.1 can be found in Section 20.2.1 of the printed manual.      │
  12784.    └────────────────────────────────────────────────────────────────────────┘
  12785.  
  12786.    Figure 20.1  Application-to-Device Path
  12787.  
  12788.    By creating presentation spaces and associating them with particular
  12789.    device contexts, an application can control where its graphics output
  12790.    appears. Because a presentation space and device context isolate the
  12791.    application from the physical details of displaying graphics, the same
  12792.    graphics commands can typically be used for many types of displays. This
  12793.    virtualization of output can reduce the amount of display code that an
  12794.    application needs to support.
  12795.  
  12796.    This chapter discusses how an application sets up its presentation spaces
  12797.    and device contexts before drawing and how to use window-drawing
  12798.    functions. Other chapters in this manual discuss the individual graphics
  12799.    routines available in MS OS/2.
  12800.  
  12801.  20.2.2  Window Regions
  12802.  
  12803.    A window and the presentation space associated with it have three regions
  12804.    that control where drawing takes place in the window. These regions ensure
  12805.    that the application does not draw outside the boundaries of the window or
  12806.    intrude into the space of an overlapping window.
  12807.  
  12808. ╓┌─┌───────────────┌─────────────────────────────────────────────────────────╖
  12809.    Region          Description
  12810.    ──────────────────────────────────────────────────────────────────────────
  12811.    Update region   This region represents the area of the window that needs
  12812.    Region          Description
  12813.    ──────────────────────────────────────────────────────────────────────────
  12814.    Update region   This region represents the area of the window that needs
  12815.                    to be redrawn. This region changes when overlapping
  12816.                    windows change their Z order or when an application
  12817.                    explicitly adds an area to the update region to force a
  12818.                    window to be painted.
  12819.  
  12820.    Clip region     This region and the visible region determine where drawing
  12821.                    takes place. Applications can change the clip region to
  12822.                    limit drawing to a particular portion of a window.
  12823.                    Typically, a presentation space is created with a clip
  12824.                    region equal to NULL, which means that there is no
  12825.                    clipping supplied by this region.
  12826.  
  12827.    Visible region  This region and the clip region determine where drawing
  12828.                    takes place. The system changes the visible region to
  12829.                    represent the portion of a window that is visible.
  12830.                    Typically, the visible region is used to mask out
  12831.                    overlapping windows. When the application calls the
  12832.                    WinBeginPaint function in response to a WM_PAINT message,
  12833.    Region          Description
  12834.    ──────────────────────────────────────────────────────────────────────────
  12835.                   WinBeginPaint function in response to a WM_PAINT message,
  12836.                    the system sets the visible region to the intersection of
  12837.                    the visible region and the update region to produce a new
  12838.                    visible region. Applications cannot change the visible
  12839.                    region directly.
  12840.    ──────────────────────────────────────────────────────────────────────────
  12841.  
  12842.  
  12843.    Whenever drawing occurs in a window's presentation space, the output is
  12844.    clipped to the intersection of the visible region and the clip region.
  12845.    Figure 20.2 shows how the intersection of the visible region and the clip
  12846.    region of a window that is behind another window prevents drawing in the
  12847.    back window from intruding into the front window. The clip region includes
  12848.    the overlapped part of the back window, but the visible region excludes
  12849.    that portion of the back window. The system maintains the visible region
  12850.    to protect other windows on the screen and the application maintains the
  12851.    clip region to specify the portion of the window in which it draws.
  12852.    Together, these two regions provide safe and controllable clipping.
  12853.  
  12854.    ┌────────────────────────────────────────────────────────────────────────┐
  12855.    │ Figure 20.2 can be found in Section 20.2.2 of the printed manual.      │
  12856.    └────────────────────────────────────────────────────────────────────────┘
  12857.  
  12858.    Figure 20.2  Clip Region and Visible Region
  12859.  
  12860.    The update region is manipulated by both the system and the application to
  12861.    further control drawing. For example, if the windows shown in Figure
  12862.    20.2 switch positions front to back, several changes occur in the regions
  12863.    of both windows. The system adds the lower-right corner of the new front
  12864.    window to that window's visible region. The system also adds that corner
  12865.    area to the window's update region, as shown in Figure 20.3. Adding an
  12866.    area to this window's update region causes the window's window procedure
  12867.    to receive a WM_PAINT message. During the processing of the WM_PAINT
  12868.    message, the system sets the new visible region to be the intersection of
  12869.    the previous visible region and the update region. With this restricted
  12870.    visible region, only the appropriate part of the window is redrawn──the
  12871.    lower-right corner.
  12872.  
  12873.    ┌────────────────────────────────────────────────────────────────────────┐
  12874.    │ Figure 20.3 can be found in Section 20.2.2 of the printed manual.      │
  12875.    └────────────────────────────────────────────────────────────────────────┘
  12876.  
  12877.    Figure 20.3  Update Region and Visible Region
  12878.  
  12879.  
  12880.  20.3  Strategies for Painting and Drawing
  12881.  
  12882.    The following sections discuss drawing strategies for an MS OS/2
  12883.    application. Because an application shares the screen with other windows
  12884.    and applications, drawing must not interfere with other applications and
  12885.    windows. When these strategies are followed, your application will coexist
  12886.    with other applications and still take full advantage of the graphics
  12887.    capabilities of MS OS/2.
  12888.  
  12889.  20.3.1  When to Draw in a Window
  12890.  
  12891.    Ideally, all drawing in a window should be done during the processing of
  12892.    the WM_PAINT message. Applications maintain an internal representation of
  12893.    what should be displayed in the window, such as text or a linked list of
  12894.    graphics objects, and use the WM_PAINT message as a cue to display a
  12895.    visual representation of that data in the window.
  12896.  
  12897.    To route all display output through the WM_PAINT message, an application
  12898.    should not draw on the screen at the time its data changes. Instead, the
  12899.    application should update the internal representation of the data and then
  12900.    call the WinInvalidateRect or WinInvalidateRegion function to invalidate
  12901.    the portion of the window that needs to be redrawn. Of course, it is often
  12902.    much more efficient to draw directly in a window without relying on the
  12903.    WM_PAINT message──for example, when drawing and redrawing an object for a
  12904.    user who is dragging or sizing with the mouse.
  12905.  
  12906.    If the window has the WS_SYNCPAINT or CS_SYNCPAINT style, invalidating a
  12907.    portion of the window causes a WM_PAINT message to be sent to the window
  12908.    immediately. Because sending a message is essentially like making a
  12909.    function call, the actions corresponding to the WM_PAINT message are
  12910.    carried out before the call that caused the invalidation returns──that is,
  12911.    the painting is synchronous.
  12912.  
  12913.    If the window does not have the WS_SYNCPAINT or CS_SYNCPAINT style,
  12914.    invalidating a portion of the window causes the invalidated region to be
  12915.    added to the window's update region. The next time the application calls
  12916.    the WinGetMsg or WinPeekMsg function when there are no other messages in
  12917.    the queue and the update region for the window is not empty, the
  12918.    application is sent a WM_PAINT message. If there are many messages in the
  12919.    queue the painting occurs after the invalidation──that is, the painting is
  12920.    asynchronous. Painting for windows that do not have the WS_SYNCPAINT or
  12921.    CS_SYNCPAINT style is a low-priority operation; all other messages are
  12922.    processed first. Because a WM_PAINT message is not posted to the queue in
  12923.    this case, all invalidation operations since the last WM_PAINT message are
  12924.    consolidated into a single WM_PAINT message the next time the application
  12925.    has no messages in the queue.
  12926.  
  12927.    There are advantages to both synchronous and asynchronous painting.
  12928.    Windows that have simple painting routines should be painted
  12929.    synchronously. Most of the system-defined control windows, such as buttons
  12930.    and frame controls, are painted synchronously because they can be painted
  12931.    quickly without interfering with the responsiveness of the program.
  12932.    Windows with more time-consuming painting operations should be painted
  12933.    asynchronously so that the painting can be initiated only when there are
  12934.    no other pending messages that might otherwise be blocked while waiting
  12935.    for the window to be painted. Also, windows that use an incremental
  12936.    approach to invalidating small portions of the window should usually allow
  12937.    those operations to consolidate into a single asynchronous WM_PAINT
  12938.    message, rather than a series of synchronous WM_PAINT messages.
  12939.  
  12940.    If necessary, an application can call the WinUpdateWindow function to
  12941.    cause an asynchronous window to update itself without going through the
  12942.    event loop. WinUpdateWindow sends a WM_PAINT message directly to the
  12943.    window if the window's update region is not empty.
  12944.  
  12945.  20.3.2  The WM_PAINT Message
  12946.  
  12947.    A window receives a WM_PAINT message whenever its update region is not
  12948.    NULL. A window procedure should respond to a WM_PAINT message by calling
  12949.    the WinBeginPaint function, drawing to fill in the update areas, and then
  12950.    calling the WinEndPaint function.
  12951.  
  12952.    The WinBeginPaint function returns a handle to a presentation space that
  12953.    is associated with the device context for the window and that has a
  12954.    visible region equal to the intersection of the window's update region and
  12955.    its visible region. This means that only those portions of the window that
  12956.    need to be redrawn are drawn. Attempts to draw outside this region are
  12957.    clipped and do not appear on the screen.
  12958.  
  12959.    If the application maintains its own presentation space for the window, it
  12960.    can pass that handle of the presentation space to the WinBeginPaint
  12961.    function, which modifies the visible region of the presentation space and
  12962.    passes the handle of the presentation-space back to the caller. If the
  12963.    application does not have its own presentation space, it can pass a NULL
  12964.    presentation-space handle and the system will return a cached-micro
  12965.    presentation space for the window. In either case, the application can use
  12966.    the presentation space to draw in the window.
  12967.  
  12968.    The WinBeginPaint function takes a pointer to a RECTL structure that it
  12969.    fills in with the coordinates of the rectangle enclosing the area to
  12970.    update. The application can use this rectangle to optimize drawing, by
  12971.    drawing only those portions of the window that intersect with the
  12972.    rectangle. If an application passes a NULL pointer for the rectangle
  12973.    argument, the application draws the entire window and relies on the
  12974.    clipping mechanism to filter out the unneeded areas.
  12975.  
  12976.    After the WinBeginPaint function sets the update region of a window to
  12977.    NULL, the application does the drawing necessary to fill the update areas.
  12978.    If an application handles a WM_PAINT message and does not call
  12979.    WinBeginPaint or otherwise empty the update region, the application
  12980.    continues to receive WM_PAINT messages as long as the update region is not
  12981.    empty.
  12982.  
  12983.    Once the application has finished drawing, it should call the WinEndPaint
  12984.    function to restore the presentation space to its former state. When a
  12985.    cached-micro presentation space is returned by the WinBeginPaint function,
  12986.    the presentation space is returned to the system for reuse. If the
  12987.    application supplies its own presentation space to WinBeginPaint, the
  12988.    presentation state is restored to its previous state.
  12989.  
  12990.    20.3.2.1  Drawing the Minimized View
  12991.  
  12992.    When an application creates a standard frame window, it has the option of
  12993.    specifying an icon that the system will use to represent the application
  12994.    in its minimized state. Typically, if an icon is supplied, the system
  12995.    draws the icon in the minimized window and labels the icon with the name
  12996.    of the window. If the application does not specify the FS_ICON style for
  12997.    the window, the window receives a WM_PAINT message when it is minimized.
  12998.    The code in the window procedure that handles the WM_PAINT message can
  12999.    determine if the frame window is currently minimized and then draw
  13000.    accordingly. Notice that because the WS_MINIMIZED style is relevant only
  13001.    for the frame window, not for the client, the window procedure checks the
  13002.    frame window rather than the client window. The following code fragment
  13003.    shows how to draw a window in the minimized state and the normal state:
  13004.  
  13005.    case WM_PAINT:
  13006.        hps = WinBeginPaint(hwnd, NULL, &rect);
  13007.  
  13008.        /* See if the frame window (client's parent) is minimized. */
  13009.  
  13010.        ulStyle = WinQueryWindowULong(WinQueryWindow(hwnd, QW_PARENT,
  13011.            FALSE), QWL_STYLE);
  13012.  
  13013.        if (ulStyle & WS_MINIMIZED) {
  13014.            .
  13015.            . /* paints the minimized state */
  13016.            .
  13017.        }
  13018.        else {
  13019.            .
  13020.            . /* paints the normal state    */
  13021.            .
  13022.        }
  13023.        WinEndPaint(hps);
  13024.        return 0L;
  13025.  
  13026.  20.3.3  Drawing Without the WM_PAINT Message
  13027.  
  13028.    An application can draw in a window's presentation space if it has not
  13029.    received a WM_PAINT message. As long as there is a presentation space for
  13030.    the window, an application can draw into the presentation space and avoid
  13031.    intruding into other windows or the desktop. Applications that draw
  13032.    without using the WM_PAINT message typically call the WinGetPS function to
  13033.    obtain a cached-micro presentation space for the window and call the
  13034.    WinReleasePS function when they have finished drawing. An application can
  13035.    also use any of the other types of presentation spaces described in the
  13036.    following sections.
  13037.  
  13038.  20.3.4  Three Kinds of Presentation Spaces
  13039.  
  13040.    All drawing must take place within a presentation space. MS OS/2 provides
  13041.    three kinds of presentation spaces for drawing: the normal presentation
  13042.    space, the micro presentation space, and the cached-micro presentation
  13043.    space.
  13044.  
  13045.    The normal presentation space provides the most functionality, allowing
  13046.    access to all the graphics functions of MS OS/2 and allowing the
  13047.    application to draw to all device types. The normal presentation space is
  13048.    more difficult to use than the other two kinds of presentation spaces and
  13049.    it uses more memory. It is created by using the GpiCreatePS function and
  13050.    it is destroyed by using the GpiDestroyPS function.
  13051.  
  13052.    The micro presentation space allows access to only a subset of the MS OS/2
  13053.    graphics functions, but it uses less memory and is faster than a normal
  13054.    presentation space. The micro presentation space also allows the
  13055.    application to draw to all device types. It is created by using the
  13056.    GpiCreatePS function and destroyed by using the GpiDestroyPS function.
  13057.  
  13058.    The cached-micro presentation space provides the least functionality of
  13059.    the three kinds of presentation spaces, but it is the most efficient and
  13060.    easiest to use. The cached-micro presentation space draws only to the
  13061.    screen. It is created and destroyed by using either the WinBeginPaint and
  13062.    WinEndPaint functions or the WinGetPS and WinReleasePS functions.
  13063.  
  13064.    The following sections describe each of the three types of presentation
  13065.    spaces in detail and discuss strategies for using each type in an
  13066.    application. (For more information, see Chapter 30, "Presentation Spaces
  13067.    and Device Contexts.") All three kinds of presentation spaces can be used
  13068.    in a single application. Some windows, especially if they will never be
  13069.    printed, are best served by cached-micro presentation spaces. Other
  13070.    windows may require the more flexible services of micro or normal
  13071.    presentation spaces.
  13072.  
  13073.    20.3.4.1  Cached-Micro Presentation Spaces
  13074.  
  13075.    The cached-micro presentation space provides the simplest and most
  13076.    efficient drawing environment. It can be used only for drawing on the
  13077.    screen, typically in the context of a window. It is most appropriate for
  13078.    application tasks that need simple window-drawing functions that do not
  13079.    need to be printed. Cached-micro presentation spaces do not support
  13080.    retained graphics.
  13081.  
  13082.    After an application draws to a cached-micro presentation space, the
  13083.    drawing commands are routed through an implied device context to the
  13084.    current display. The application does not need information about the
  13085.    actual device context, since it is assumed to be the display. This process
  13086.    makes cached-micro presentation spaces easy for applications to use.
  13087.    Figure 20.4 illustrates this process:
  13088.  
  13089.    ┌────────────────────────────────────────────────────────────────────────┐
  13090.    │ Figure 20.4 can be found in Section 20.3.4.1 of the printed manual.    │
  13091.    └────────────────────────────────────────────────────────────────────────┘
  13092.  
  13093.    Figure 20.4  Cached-Micro Presentation Space
  13094.  
  13095.    There are two common strategies for using cached-micro presentation spaces
  13096.    in an application. The simplest is to call the WinBeginPaint function
  13097.    during the WM_PAINT message, use the resulting cached-micro presentation
  13098.    space to draw in the window, and then return the presentation space to the
  13099.    system by calling the WinEndPaint function. By using this method, the
  13100.    application only interacts with the presentation space when it needs to
  13101.    draw in the presentation space. This method is most appropriate for simple
  13102.    drawing. A disadvantage of this method is that the application must set up
  13103.    any special attributes for the presentation space, such as line color and
  13104.    font, each time a new presentation space is obtained.
  13105.  
  13106.    A second strategy is for the application to allocate a cached-micro
  13107.    presentation space during initialization, by calling the WinGetPS function
  13108.    and saving the resulting presentation-space handle in a static variable.
  13109.    The application can then set attributes in the presentation space that
  13110.    persist for the life of the program. The presentation-space handle can be
  13111.    used as an argument to the WinBeginPaint function each time the window
  13112.    gets a WM_PAINT message; the system modifies the visible region and
  13113.    returns the presentation space to the application with its attributes
  13114.    intact. This strategy is appropriate for applications that need to
  13115.    customize their window-drawing attributes.
  13116.  
  13117.    A presentation space that is obtained by calling the WinGetPS function
  13118.    should be released by calling WinReleasePS when the application has
  13119.    finished using it. (Typically, this will be during program termination.) A
  13120.    presentation space that is obtained by calling the WinBeginPaint function
  13121.    should be released by calling the WinEndPaint function, typically as the
  13122.    last part of processing a WM_PAINT message.
  13123.  
  13124.    20.3.4.2  Micro Presentation Spaces
  13125.  
  13126.    The main advantage of a micro presentation space over a cached-micro
  13127.    presentation space is that it can be used for printing as well as for
  13128.    painting in a window. An applications that uses a micro presentation space
  13129.    must explicitly associate it with a device context. This makes the micro
  13130.    presentation space useful for painting to a printer, plotter, or an
  13131.    off-screen memory bitmap.
  13132.  
  13133.    A micro presentation space does not support the full set of MS OS/2
  13134.    graphics functions. Unlike a normal presentation space, a micro
  13135.    presentation space does not support retained graphics.
  13136.  
  13137.    An application that needs to display in a window and print to a printer or
  13138.    plotter typically maintains two presentation spaces: one for the window
  13139.    and one for the printing device. Figure 20.5 shows how an application's
  13140.    graphics output can be routed through separate presentation spaces to
  13141.    produce a screen display and printed copy:
  13142.  
  13143.    ┌────────────────────────────────────────────────────────────────────────┐
  13144.    │ Figure 20.5 can be found in Section 20.3.4.2 of the printed manual.    │
  13145.    └────────────────────────────────────────────────────────────────────────┘
  13146.  
  13147.    Figure 20.5  Micro Presentation Space
  13148.  
  13149.    An application creates a micro presentation space by calling the
  13150.    GpiCreatePS function. Because a device context must be supplied at the
  13151.    time the micro presentation space is created, an application typically
  13152.    creates a device context and then a presentation space. The following code
  13153.    fragment demonstrates this by obtaining a device context for a window and
  13154.    associating it with a new micro presentation space:
  13155.  
  13156.    hdc = WinOpenWindowDC(...);
  13157.    hps = GpiCreatePS(...,hdc,...,GPIA_ASSOC);
  13158.  
  13159.    To create a micro presentation space for a device other than the screen,
  13160.    replace the call to the WinOpenWindowDC function with a call to the
  13161.    DevOpenDC function, which obtains a device context for a device that is
  13162.    not the screen. The device context that is obtained by this call can be
  13163.    used as an argument to the GpiCreatePS function.
  13164.  
  13165.    An application typically creates a micro presentation space during
  13166.    initialization and uses it until termination. Each time the application
  13167.    receives a WM_PAINT message, it should pass the handle of the micro
  13168.    presentation space as an argument to the WinBeginPaint function; this
  13169.    prevents the system from returning a cached-micro presentation space. The
  13170.    system modifies the visible region of the supplied micro presentation
  13171.    space and returns the presentation space to the application. This method
  13172.    allows the application to use the same presentation space for all drawing
  13173.    in a specified window.
  13174.  
  13175.    Micro presentation spaces created by using the GpiCreatePS function should
  13176.    be destroyed by calling the GpiDestroyPS function before the application
  13177.    terminates. Do not call the WinReleasePS function to release a
  13178.    presentation space obtained by using the GpiCreatePS function. Before
  13179.    terminating, applications should also use the DevCloseDC function to close
  13180.    any device contexts opened by using the DevOpenDC function. No action is
  13181.    necessary for device contexts obtained with the WinOpenWindowDC function,
  13182.    since the system automatically closes these device contexts when
  13183.    destroying the associated windows.
  13184.  
  13185.    20.3.4.3  Normal Presentation Spaces
  13186.  
  13187.    The normal presentation space supports the full power of MS OS/2 graphics,
  13188.    including retained graphics. The main advantages of a normal presentation
  13189.    space over the other two presentation-space types are its support of all
  13190.    graphics functions, including retained graphics, and its ability to be
  13191.    associated with many kinds of device contexts.
  13192.  
  13193.    A normal presentation space can be associated with many different device
  13194.    contexts. Typically, this means that an application creates a normal
  13195.    presentation space and associates it with a window device context for
  13196.    screen display. When the user asks to print, the application associates
  13197.    the same presentation space with a printer device context. Later, the
  13198.    application can reassociate the presentation space with the window device
  13199.    context. A presentation space can be associated with only one device
  13200.    context at a time, but the normal presentation space allows the
  13201.    application to change the device context whenever necessary. Figure 20.6
  13202.    shows how an application typically routes graphics through one normal
  13203.    presentation space into another device context:
  13204.  
  13205.    ┌────────────────────────────────────────────────────────────────────────┐
  13206.    │ Figure 20.6 can be found in Section 20.3.4.3 of the printed manual.    │
  13207.    └────────────────────────────────────────────────────────────────────────┘
  13208.  
  13209.    Figure 20.6  Normal Presentation Space
  13210.  
  13211.    A normal presentation space can be associated with a device context when
  13212.    the normal presentation space is created, or association can be deferred
  13213.    to a later time. The GpiAssociate function associates a device context
  13214.    with a normal presentation space after the presentation space has been
  13215.    created. An application typically associates the normal presentation space
  13216.    with a device context when calling the GpiCreatePS function and later
  13217.    associates the presentation space with a different device context by
  13218.    calling GpiAssociate. To obtain a device context for a window, call the
  13219.    WinOpenWindowDC function. To obtain a device context for a device other
  13220.    than the screen, call the DevOpenDC function.
  13221.  
  13222.    An application typically creates a normal presentation space during
  13223.    initialization and uses it until termination. Each time the application
  13224.    receives a WM_PAINT message, it should pass the handle of the normal
  13225.    presentation space as an argument to the WinBeginPaint function; this
  13226.    prevents the system from returning a cached-micro presentation space. The
  13227.    system modifies the visible region of the supplied normal presentation
  13228.    space and returns the presentation space to the application. This method
  13229.    allows the application to use the same presentation space for all drawing
  13230.    in a specified window.
  13231.  
  13232.    Normal presentation spaces created by using the GpiCreatePS function
  13233.    should be destroyed by calling the GpiDestroyPS function before the
  13234.    application terminates. Do not call the WinReleasePS function to release a
  13235.    presentation space obtained by using the GpiCreatePS function. Before
  13236.    terminating, applications should also use the DevCloseDC function to close
  13237.    any device contexts opened by using the DevOpenDC function. No action is
  13238.    necessary for device contexts obtained with the WinOpenWindowDC function,
  13239.    since the system automatically closes these device contexts when
  13240.    destroying the associated windows.
  13241.  
  13242.  
  13243.  20.4  Printing
  13244.  
  13245.    Although a detailed discussion of printing is beyond the scope of this
  13246.    chapter, printing should be seen as a variation of screen painting. To
  13247.    draw in a window, an application issues graphics calls to a presentation
  13248.    space associated with a screen device context. To print, the application
  13249.    makes graphics calls to a presentation space associated with a printer
  13250.    device context. In an application that supports a what-you-see-is-
  13251.    what-you-get window display, the printing code should be
  13252.    the same as or very similar to the window-display code, as though the
  13253.    printed page were an 8 1/2-by-11-inch window. (Of course, many applications
  13254.    will optimize printing code to take advantage of such properties of the
  13255.    output device as high-resolution page-description languages.)
  13256.  
  13257.    An application achieves greater device-independence if it does not use
  13258.    pels as its drawing unit. For example, if an application does all its
  13259.    drawing into a presentation space with PU_LOENGLISH units (.01 inch), a
  13260.    100-unit line is certain to be one inch long on any printing device. The
  13261.    presentation space and device context automatically scale a drawing to
  13262.    compensate for the resolution of the output device.
  13263.  
  13264.  
  13265.  20.5  Summary
  13266.  
  13267.    This section summarizes the window styles related to window painting; the
  13268.    functions that control presentation spaces, device contexts, and window
  13269.    regions; and the messages related to window painting.
  13270.  
  13271.  20.5.1  Window Styles for Painting
  13272.  
  13273.    Most of the styles relating to window drawing can be set either for the
  13274.    window class (CS prefix) or for an individual window (WS prefix). The
  13275.    following styles control how the system manipulates the window's regions
  13276.    and how the window is notified to paint itself:
  13277.  
  13278.    WS_CLIPCHILDREN, CS_CLIPCHILDREN  All of the child windows of a window
  13279.    with this style are excluded from the window's visible region. This style
  13280.    protects child windows but more time is required when calculating the
  13281.    visible region. This style is normally not necessary, since if the parent
  13282.    and child overlap and are both invalidated, the parent is drawn before the
  13283.    child. If the child is invalidated independently from the parent, only the
  13284.    child is redrawn. If the update region of the parent does not intersect
  13285.    the child, drawing the parent should not disturb the child.
  13286.  
  13287.    WS_CLIPSIBLINGS, CS_CLIPSIBLINGS  Any windows that have the same parent as
  13288.    a window with this style and that are in front of the window are excluded
  13289.    from the window's visible region. This style protects windows with the
  13290.    same parent from being drawn in accidentally but requires more time when
  13291.    calculating the visible region. This style is appropriate for windows that
  13292.    overlap and that have same parent.
  13293.  
  13294.    WS_PARENTCLIP, CS_PARENTCLIP  The visible region for a window with this
  13295.    style is the same as the visible region of the parent window. This style
  13296.    simplifies the calculation of the visible region but is potentially
  13297.    dangerous, since the parent window's visible region is usually larger than
  13298.    the child window. Windows with this style should not draw outside their
  13299.    boundaries.
  13300.  
  13301.    WS_SAVEBITS, CS_SAVEBITS  The system saves the bits underneath a window
  13302.    with this style when the window is displayed. When the window moves or is
  13303.    hidden, the uncovered bits are simply restored by the system; there is no
  13304.    need to add the area to the uncovered window's update region. Because this
  13305.    operation can consume a great deal of memory, it is recommended only for
  13306.    transient windows such as menus and dialog boxes, not for main application
  13307.    windows.
  13308.  
  13309.    WS_SYNCPAINT, CS_SYNCPAINT  Windows that have this style receive WM_PAINT
  13310.    messages as soon as their update regions are not empty and are updated
  13311.    immediately (synchronously). For more details on synchronous painting, see
  13312.    Section 20.3.1.
  13313.  
  13314.    CS_SIZEREDRAW  A window with this class style receives a WM_PAINT message
  13315.    and is completely invalidated whenever the window is resized, even if it
  13316.    is made smaller. (Typically, only the uncovered area of a window is
  13317.    invalidated when a window is resized.) This class style is useful when an
  13318.    application scales graphics to fill the current window.
  13319.  
  13320.  20.5.2  Functions
  13321.  
  13322.    The following functions control presentation spaces, device contexts, and
  13323.    window regions:
  13324.  
  13325.    DevCloseDC  Closes a device context created by using the DevOpenDC
  13326.    function. Do not use this function to close a device context that was
  13327.    created by using the WinOpenWindowDC function.
  13328.  
  13329.    DevOpenDC  Creates a device context for a specified device type.
  13330.  
  13331.    GpiAssociate  Creates an association between a presentation space and a
  13332.    device context. Any subsequent drawing to the presentation space goes to
  13333.    the specified device. This function is typically used only with normal
  13334.    presentation spaces, since micro presentation spaces must be associated
  13335.    with a device context during the call to the GpiCreatePS function.
  13336.  
  13337.    fbGpiCreatePS  Creates a handle of a normal or micro presentation space.
  13338.    The presentation space can be associated with a specified device context
  13339.    at the time of creation (this is mandatory for micro presentation spaces),
  13340.    or it can be associated later by using the GpiAssociate function.
  13341.  
  13342.    GpiDestroyPS  Destroys a presentation space. Do not attempt to destroy a
  13343.    cached-micro presentation space by using this function.
  13344.  
  13345.    WinBeginPaint  Returns a handle of a presentation space that has a visible
  13346.    region equal to the intersection of the window's update region and the
  13347.    visible region of the window's presentation space. This function is called
  13348.    when a WM_PAINT message is received. If the hps parameter is a valid
  13349.    presentation-space handle, the visible region of the presentation space is
  13350.    modified and the handle is returned. If the hps parameter is NULL, the
  13351.    system returns the handle of a cached-micro presentation space. The update
  13352.    region of the window is set to NULL by this function because the system
  13353.    assumes that the caller will do all drawing necessary to fill the invalid
  13354.    region of the window.
  13355.  
  13356.    WinEnableWindowUpdate  Sets the window-visibility state for subsequent
  13357.    drawing, without causing any visible change to the window. This function
  13358.    can be used to defer drawing when making a series of changes to a window.
  13359.  
  13360.    WinEndPaint  Indicates that a drawing operation that was started by using
  13361.    the WinBeginPaint function is finished. The hps parameter is the
  13362.    presentation-space handle returned by WinBeginPaint. A cached-micro
  13363.    presentation space is returned to the system for reuse and the drawing
  13364.    environment of a previous presentation space is restored.
  13365.  
  13366.    WinExcludeUpdateRegion  Removes the update region from the clip region of
  13367.    the specified window. This can be useful for optimization, since it
  13368.    prevents drawing in the update region. The application must restore the
  13369.    clip region when the exclusion is no longer needed.
  13370.  
  13371.    WinGetClipPS  Returns a clipped presentation space for the specified
  13372.    window. The type of clipping depends on the flag settings of the
  13373.    function's parameters. The presentation space should be released by using
  13374.    the WinReleasePS function.
  13375.  
  13376.    WinGetPS  Returns the handle of a cached-micro presentation space for the
  13377.    specified window. The presentation space should be released by using the
  13378.    WinReleasePS function.
  13379.  
  13380.    WinGetScreenPS  Returns a presentation-space handle that can be used to
  13381.    draw anywhere on the screen.
  13382.  
  13383.    WinInvalidateRect  Adds the specified rectangle to the update region of
  13384.    the window. If the specified window has the WS_SYNCPAINT style, it
  13385.    receives a WM_PAINT message before WinInvalidateRect returns. This
  13386.    function can be used to force part of a window to be repainted. If the
  13387.    fIncludeChildren parameter is TRUE, any child windows that intersect the
  13388.    invalid rectangle are also invalidated.
  13389.  
  13390.    WinInvalidateRegion  Adds the specified region to the update region of the
  13391.    specified window. If the window has the WS_SYNCPAINT style, it receives a
  13392.    WM_PAINT message before WinInvalidateRegion returns. This function can be
  13393.    used to force a portion of a window to be repainted. If the
  13394.    fIncludeChildren parameter is TRUE, any child windows that intersect the
  13395.    invalid region are also invalidated.
  13396.  
  13397.    WinLockWindowUpdate  Prevents updates to the specified window and its
  13398.    child windows. This is useful if you need to delay updating during
  13399.    incremental data changes, such as adding items to a list box. Calling
  13400.    WinLockWindowUpdate with NULL for the hwndLockUpdate parameter invalidates
  13401.    the windows that were previously locked and causes WM_PAINT messages to be
  13402.    sent to those windows.
  13403.  
  13404.    WinLockVisRegions  Locks or unlocks the visible regions of all windows on
  13405.    the screen. This function is useful to threads because it prevents the
  13406.    visible regions of windows from changing while the thread performs a
  13407.    screen operation, such as copying screen pels into a memory bitmap.
  13408.  
  13409.    WinOpenWindowDC  Returns a device-context handle for the specified window.
  13410.    Attempting to open more than one device context for a given window is an
  13411.    error. The returned device context is automatically closed when the window
  13412.    is destroyed; it must not be closed by using the DevCloseDC function.
  13413.  
  13414.    WinQueryUpdateRect  Returns the coordinates of the smallest rectangle that
  13415.    encloses the window's update region.
  13416.  
  13417.    WinQueryUpdateRegion  Obtains the update region of the specified window.
  13418.  
  13419.    WinQueryWindowDC  Returns the device-context handle associated with the
  13420.    specified window.
  13421.  
  13422.    WinReleasePS  Releases the handle of a cached-micro presentation space
  13423.    that was obtained by using the WinGetPS or WinGetClipPS function. This
  13424.    function should not be used for presentation-space handles that are not
  13425.    cached──that is, WinReleasePS should not be used for presentation spaces
  13426.    obtained by using the GpiCreatePS function.
  13427.  
  13428.    WinValidateRect  Removes the specified rectangle from the update region of
  13429.    the window. This function can be used to avoid duplicate drawing, by
  13430.    signaling that part of the window has been drawn without using the
  13431.    WM_PAINT message.
  13432.  
  13433.    WinValidateRegion  Removes the specified region from the update region of
  13434.    the window. This function can be used to avoid duplicate drawing, by
  13435.    signaling that part of the window has been drawn without using the
  13436.    WM_PAINT message.
  13437.  
  13438.    WinWindowFromDC  Returns the handle of the window associated with the
  13439.    specified device-context.
  13440.  
  13441.  20.5.3  Messages for Painting
  13442.  
  13443.    The following message is used in the management of window painting:
  13444.  
  13445.    WM_PAINT  This message is sent when some portion of the window needs to be
  13446.    repainted. The window procedure should respond to the message by painting
  13447.    the relevant portion of the window.
  13448.  
  13449.  
  13450.  
  13451.  ────────────────────────────────────────────────────────────────────────────
  13452.  Chapter 21  Drawing in Windows
  13453.  
  13454.         21.1    Introduction
  13455.         21.2    Window-Drawing Functions
  13456.             21.2.1    Points and Rectangles
  13457.         21.3    Using Window-Drawing Functions
  13458.             21.3.1    Working with Points and Rectangles
  13459.             21.3.2    Scrolling Window Contents
  13460.             21.3.3    Drawing Bitmaps
  13461.             21.3.4    Drawing Text
  13462.         21.4    Summary
  13463.  
  13464.  21.1  Introduction
  13465.  
  13466.    This chapter describes the functions that are specifically designed to
  13467.    help you draw in windows. (For information on the complete set of drawing
  13468.    functions, see Part 3, "Graphics Programming Interface.") You should also
  13469.    be familiar with the following topics:
  13470.  
  13471.    ■  Standard user-interface guidelines
  13472.  
  13473.    ■  Standard frame windows
  13474.  
  13475.    ■  Presentation spaces and device contexts
  13476.  
  13477.    ■  Graphics programming interface (GPI)
  13478.  
  13479.  
  13480.  21.2  Window-Drawing Functions
  13481.  
  13482.    The functions described in this chapter overlap the functionality of
  13483.    similar drawing functions provided by the GPI sections of MS OS/2. The
  13484.    difference between the Gpi drawing functions and these window-drawing
  13485.    functions is that the functions described in this chapter are designed
  13486.    specifically for drawing in windows. Because these window-drawing
  13487.    functions are less general than the Gpi functions, they are somewhat
  13488.    easier to use, but they also offer fewer capabilities than the complete
  13489.    set of Gpi functions. The functions described in this chapter offer a
  13490.    quick and easy way to create simple graphics. Programmers seeking more
  13491.    functionality should use the Gpi functions of MS OS/2.
  13492.  
  13493.  21.2.1  Points and Rectangles
  13494.  
  13495.    All drawing in a window takes place in the context of the window's
  13496.    coordinate system. Locations in the window are described by POINTL
  13497.    structures that contain an x- and a y-coordinate for the location. The
  13498.    lower-left corner of a window always has the coordinates (0,0). The POINTL
  13499.    structure has the following form:
  13500.  
  13501.    typedef struct _POINTL  {
  13502.        LONG  x;
  13503.        LONG  y;
  13504.    } POINTL;
  13505.  
  13506.    The RECTL structure defines a rectangular area in a window. This structure
  13507.    is made up of two points that define the lower-left and upper-right
  13508.    corners of the rectangle. The RECTL structure has the following form:
  13509.  
  13510.    typedef struct _RECTL {
  13511.        LONG  xLeft;
  13512.        LONG  yBottom;
  13513.        LONG  xRight;
  13514.        LONG  yTop;
  13515.    } RECTL;
  13516.  
  13517.    An empty rectangle is a rectangle that has no area: the right coordinate
  13518.    is less than or equal to the left coordinate or the top coordinate is less
  13519.    than or equal to the bottom coordinate.
  13520.  
  13521.    There are two types of rectangles in MS OS/2: inclusive-exclusive and
  13522.    inclusive-inclusive. In inclusive-exclusive rectangles the lower-left
  13523.    coordinate of the rectangle is included in the rectangle area while the
  13524.    upper-right coordinate is excluded from the rectangle area. In an
  13525.    inclusive-inclusive rectangle, both the lower-left and the upper-right
  13526.    coordinates are included in the rectangle. Figure 21.1 shows both types
  13527.    of rectangles:
  13528.  
  13529.    ┌────────────────────────────────────────────────────────────────────────┐
  13530.    │ Figure 21.1 can be found in Section 21.2.1 of the printed manual.      │
  13531.    └────────────────────────────────────────────────────────────────────────┘
  13532.  
  13533.    Figure 21.1  Rectangle Types
  13534.  
  13535.    The dimensions of an inclusive-exclusive rectangle can be calculated as
  13536.    follows:
  13537.  
  13538.    cx = rcl.xRight - rcl.xLeft;
  13539.    cy = rcl.yTop - rcl.yBottom;
  13540.  
  13541.    The dimensions of an inclusive-inclusive rectangle can be calculated as
  13542.    follows:
  13543.  
  13544.    cx = (rcl.xRight - rcl.xLeft) + 1;
  13545.    cy = (rcl.yTop - rcl.yBottom) + 1;
  13546.  
  13547.    In general, graphics operations involving device coordinates (such as
  13548.    regions, bitmaps and bit blits, and window management) use
  13549.    inclusive-exclusive rectangles. All other graphics operations, such as Gpi
  13550.    functions that define paths, use inclusive-inclusive rectangles.
  13551.  
  13552.  
  13553.  21.3  Using Window-Drawing Functions
  13554.  
  13555.    The functions described in this chapter are intended for simple drawing.
  13556.    The rectangle functions manipulate and combine rectangles. The drawing and
  13557.    scrolling functions perform within a presentation space's coordinate
  13558.    system. For more advanced drawing you should use the Gpi functions of MS
  13559.    OS/2.
  13560.  
  13561.  21.3.1  Working with Points and Rectangles
  13562.  
  13563.    MS OS/2 includes many functions for manipulating rectangles. Many of these
  13564.    functions change the coordinates of a rectangle. Other functions draw in a
  13565.    presentation space, using a rectangle to position the drawing operation.
  13566.  
  13567.    The WinFillRect function fills a rectangle with a specified color. For
  13568.    example, to fill an entire window with blue in response to a WM_PAINT
  13569.    message, you could use the following code fragment, which is taken from a
  13570.    window procedure:
  13571.  
  13572.    case WM_PAINT:
  13573.        hps = WinBeginPaint(hwnd, NULL, NULL);
  13574.        WinQueryWindowRect(hwnd, &rect);
  13575.        WinFillRect(hps, &rect, CLR_BLUE);
  13576.        WinEndPaint(hps);
  13577.        return 0L;
  13578.  
  13579.    A more efficient way of painting a client window is to pass a rectangle to
  13580.    the WinBeginPaint function. The rectangle will be set to the coordinates
  13581.    of the rectangle that encloses the update region of the window. Drawing in
  13582.    this rectangle updates the window; this can make drawing faster if only a
  13583.    small portion of the window needs to be painted. This method is shown in
  13584.    the following code fragment. Notice that the WinFillRect function uses the
  13585.    presentation space and a rectangle defined in window coordinates to guide
  13586.    the paint operation.
  13587.  
  13588.    case WM_PAINT:
  13589.        hps = WinBeginPaint(hwnd, NULL, &rect);
  13590.        WinFillRect(hps, &rect, CLR_BLUE);
  13591.        WinEndPaint(hps);
  13592.        return 0L;
  13593.  
  13594.    Of course, you can draw the entire window during the WM_PAINT message, but
  13595.    the graphics output will be clipped to the update region.
  13596.  
  13597.    The default method of indicating that a particular portion of a window has
  13598.    been selected is for the WinInvertRect function to invert the rectangle's
  13599.    bits.
  13600.  
  13601.    The rest of the rectangle functions are mathematical and do not draw. They
  13602.    are used to manipulate and combine rectangles to produce new rectangles,
  13603.    which can then be used for drawing operations.
  13604.  
  13605.    The WinMapWindowPoints function converts the points from one
  13606.    window-coordinate space to another window-coordinate space. If one of the
  13607.    specified windows is HWND_DESKTOP, then screen coordinates are used. This
  13608.    function is useful for converting from window coordinates to screen
  13609.    coordinates and back again.
  13610.  
  13611.  21.3.2  Scrolling Window Contents
  13612.  
  13613.    An application normally responds to a click in a scroll bar by scrolling
  13614.    the contents of the window. This operation typically has three parts.
  13615.    First, the application changes its internal data-representation state to
  13616.    show what portion of the image should now be in the window. Next, the
  13617.    application moves the current image in the window. Finally, the
  13618.    application draws in the area that has been uncovered by the scrolling
  13619.    operation.
  13620.  
  13621.    For example, a simple text editor may display a small portion of several
  13622.    pages of text in a window. When the user clicks the down arrow of the
  13623.    vertical scroll bar, the application should move all the text up one line
  13624.    and display the next line at the bottom of the window.
  13625.  
  13626.    When the user clicks the down arrow of the vertical scroll bar, the client
  13627.    window of the frame window that owns the scroll bar receives a message.
  13628.    The application responds to this message by changing its internal
  13629.    data-representation state to show which line of text is topmost in the
  13630.    window, scrolling the text in the window up one line, and drawing the new
  13631.    line at the bottom of the window. There is normally no need to completely
  13632.    redraw the entire window, because the scrolled portion of the image
  13633.    remains valid.
  13634.  
  13635.    The WinScrollWindow function allows applications to scroll the contents of
  13636.    their windows. WinScrollWindow scrolls a specified rectangular area of the
  13637.    window by a specified x- and y-offset (in window coordinates). By setting
  13638.    the SW_INVALIDATERGN flag for this function, the areas uncovered by the
  13639.    scroll are automatically added to the window's update region, causing a
  13640.    WM_PAINT message to be sent to the window for those areas.
  13641.  
  13642.    For example, in the simple text editor described earlier, the following
  13643.    call scrolls the text up one line (assuming that iVScrollInc is the height
  13644.    of the current font) and adds the uncovered area at the bottom of the
  13645.    window to the update region.
  13646.  
  13647.    /* Scroll, adding new area to update region. */
  13648.  
  13649.    WinScrollWindow (hwnd, /* window                            */
  13650.        0,                 /* x-displacement                    */
  13651.        -(iVScrollInc),    /* y-displacement                    */
  13652.        NULL,              /* scroll rectangle is entire window */
  13653.        NULL,              /* clip rectangle is entire window   */
  13654.        NULL,              /* update region                     */
  13655.        NULL,              /* update rectangle                  */
  13656.        SW_INVALIDATERGN); /* flags                             */
  13657.  
  13658.    When the uncovered area at the bottom of the window is added to the
  13659.    window's update region, a WM_PAINT message is sent to the window. When the
  13660.    message is received, the window draws the line of text at the bottom of
  13661.    the window. If the window has the WS_SYNCPAINT style, the WM_PAINT message
  13662.    is sent to the window before the WinScrollWindow function returns.
  13663.  
  13664.    To optimize scrolling speed for repeated scrolling operations, you can
  13665.    omit the SW_INVALIDATERGN flag from the call to the WinScrollWindow
  13666.    function. This prevents WinScrollWindow from adding the invalid region
  13667.    uncovered by the scroll to the window's update region. If the
  13668.    SW_INVALIDATERGN flag is omitted, you must pass a region or rectangle to
  13669.    WinScrollWindow. The rectangle or region will contain the area that needs
  13670.    to be updated after scrolling.
  13671.  
  13672.  21.3.3  Drawing Bitmaps
  13673.  
  13674.    The WinDrawBitmap function draws a bitmap, specified by a bitmap handle,
  13675.    in a specified rectangle. This function allows you to shrink or enlarge
  13676.    the bitmap from the source rectangle to the destination. WinDrawBitmap can
  13677.    also draw in several different copy modes, including using the OR operator
  13678.    to combine source and destination pels.
  13679.  
  13680.  21.3.4  Drawing Text
  13681.  
  13682.    There are many ways to draw text in a window in an MS OS/2 application.
  13683.    The simplest way is to use the WinDrawText function, which draws a single
  13684.    line of text in a specified rectangle, using a variety of alignment
  13685.    methods.
  13686.  
  13687.    The WinDrawText function allows you to set a flag so that the function
  13688.    does not draw any text; instead, it returns the number of characters in
  13689.    the string that will fit in the specified rectangle. For a section of
  13690.    running text, an application could alternate between computation and calls
  13691.    to WinDrawText to draw successive lines of text. The DT_WORDBREAK flag in
  13692.    the WinDrawText function can be set, when performing this kind of
  13693.    repetitive operation, to put line breaks on word boundaries rather than
  13694.    between arbitrary characters.
  13695.  
  13696.  
  13697.  21.4  Summary
  13698.  
  13699.    The following functions are provided specifically for drawing in windows
  13700.    and manipulating rectangles:
  13701.  
  13702.    WinCopyRect  Copies the coordinates of one rectangle to another.
  13703.  
  13704.    WinDrawBitmap  Draws a bitmap in a rectangle, scaling the bitmap to fit,
  13705.    if necessary.
  13706.  
  13707.    WinDrawBorder  Draws a rectangle.
  13708.  
  13709.    WinDrawText  Draws a single line of formatted text in a specified
  13710.    rectangle.
  13711.  
  13712.    WinEqualRect  Returns TRUE if two rectangles have the same coordinates or
  13713.    FALSE if the coordinates are different.
  13714.  
  13715.    WinFillRect  Fills a rectangle with a specified color.
  13716.  
  13717.    WinInflateRect  Enlarges or shrinks the rectangle horizontally and
  13718.    vertically by the specified amounts. If the specified values are negative,
  13719.    the rectangle is inset.
  13720.  
  13721.    WinIntersectRect  Calculates the intersection of two source rectangles and
  13722.    returns the result in a destination rectangle, or returns FALSE if the
  13723.    result is an empty rectangle.
  13724.  
  13725.    WinInvertRect  Inverts the pels in a rectangle.
  13726.  
  13727.    WinIsRectEmpty  Returns TRUE if the rectangle is empty (that is, if
  13728.    the right coordinate is less than or equal to the left coordinate
  13729.    or if the top coordinate is less than or equal to the bottom
  13730.    coordinate).
  13731.  
  13732.    WinMapWindowPoints  Converts points from one window-coordinate system to
  13733.    another.
  13734.  
  13735.    WinOffsetRect  Changes the left and right coordinates of a rectangle by
  13736.    the specified offsets.
  13737.  
  13738.    WinPtInRect  Returns TRUE if the point is inside the rectangle or FALSE if
  13739.    it is not.
  13740.  
  13741.    WinScrollWindow  Scrolls the contents of a rectangular area of a window.
  13742.    If the proper flags are set, the area uncovered by scrolling is added to
  13743.    the window's update region, causing a WM_PAINT message to be sent. The
  13744.    application can then respond to the message by drawing in the invalidated
  13745.    region of the window.
  13746.  
  13747.    WinSetRect  Sets the rectangle's coordinates.
  13748.  
  13749.    WinSetRectEmpty  Sets the coordinates of a rectangle to (0,0,0,0).
  13750.  
  13751.    WinSubtractRect  Subtracts the coordinates of one rectangle from those of
  13752.    another rectangle. This function returns FALSE if the result is an empty
  13753.    rectangle.
  13754.  
  13755.    WinUnionRect  Calculates a rectangle that encloses two source rectangles.
  13756.    This function returns FALSE if the result is an empty rectangle.
  13757.  
  13758.  
  13759.  
  13760.  ────────────────────────────────────────────────────────────────────────────
  13761.  Chapter 22  Mouse Pointers and Icons
  13762.  
  13763.         22.1    Introduction
  13764.         22.2    About Mouse Pointers
  13765.             22.2.1    Mouse Pointers and Icon Bitmaps
  13766.             22.2.2    Mouse-Pointer Hot Spot
  13767.         22.3    Using a Mouse Pointer in an Application
  13768.             22.3.1    Creating or Loading a Mouse Pointer
  13769.             22.3.2    Changing the Mouse Pointer
  13770.             22.3.3    Drawing an Icon
  13771.             22.3.4    System Bitmaps
  13772.         22.4    Summary
  13773.             22.4.1    Predefined Mouse Pointers
  13774.             22.4.2    Mouse-Pointer Functions
  13775.  
  13776.  22.1  Introduction
  13777.  
  13778.    This chapter describes how to use mouse pointers and icons in your
  13779.    applications. You should also be familiar with the following topics:
  13780.  
  13781.    ■  Standard user-interface guidelines
  13782.  
  13783.    ■  Resources and using the MS OS/2 Resource Compiler (rc)
  13784.  
  13785.    ■  Window messages and message queues
  13786.  
  13787.    ■  Bitmaps
  13788.  
  13789.  
  13790.  22.2  About Mouse Pointers
  13791.  
  13792.    Mouse pointers are special bitmaps that MS OS/2 uses to show a user the
  13793.    current location of the mouse on the screen. The mouse pointer moves
  13794.    around the screen in response to user manipulation.
  13795.  
  13796.    Mouse pointers are also used to draw icons on the screen, such as graphics
  13797.    in message boxes and icons that represent minimized windows on the
  13798.    desktop. The data structures for mouse pointers and icon bitmaps are
  13799.    identical.
  13800.  
  13801.  22.2.1  Mouse Pointers and Icon Bitmaps
  13802.  
  13803.    Mouse pointers and icons are made up of monochrome bitmaps that MS OS/2
  13804.    uses to paint an image of the pointer or icon on the screen. A monochrome
  13805.    bitmap is a series of bytes. Each bit corresponds to a single pel in the
  13806.    image (the bitmap representing the display typically has four bits for
  13807.    each pel).
  13808.  
  13809.    A mouse pointer or icon bitmap is always twice as tall as it is wide. The
  13810.    top half of the bitmap is an AND mask, where the bits are combined using
  13811.    the AND operator with the screen bits where the pointer is being drawn.
  13812.    The lower half of the bitmap is the XOR mask, which is combined using the
  13813.    XOR operator with the destination screen bits.
  13814.  
  13815.    The combination of the AND and XOR masks results in four possible colors
  13816.    in the bitmap. The pels of an icon or pointer can be black, white,
  13817.    transparent (the screen color beneath the pel), or inverted (inverting the
  13818.    screen color beneath the pel). Figure 22.1 shows the relationship of the
  13819.    bit values in the AND and XOR masks:
  13820.  
  13821.    Figure 22.1  Bit Values in the AND and XOR Masks
  13822.  
  13823.    AND mask        0           0           1           1
  13824.    XOR mask        0           1           0           1
  13825.  
  13826.    Result        Black       White     Transparent   Inverted
  13827.  
  13828.  22.2.2  Mouse-Pointer Hot Spot
  13829.  
  13830.    Each mouse pointer has a hot spot defined as an x- and y-offset from the
  13831.    lower-left corner of the mouse-pointer bitmap. The hot spot defines the
  13832.    single point that represents the mouse-pointer location. For the
  13833.    arrow-shaped pointer, the hot spot is at the tip of the arrow. For the
  13834.    cross-hairs pointer, the hot spot is at the center of the cross. Each
  13835.    pointer has its own hot spot.
  13836.  
  13837.  
  13838.  22.3  Using a Mouse Pointer in an Application
  13839.  
  13840.    Applications typically use mouse-pointer resources to control the
  13841.    appearance of the mouse pointer and to draw icons in windows. The
  13842.    following sections show how to use mouse pointers in applications.
  13843.  
  13844.  22.3.1  Creating or Loading a Mouse Pointer
  13845.  
  13846.    Before an application can use a mouse pointer, it must first receive a
  13847.    handle to the pointer. Most applications load mouse pointers from the
  13848.    system or their own resource file. MS OS/2 maintains many predefined mouse
  13849.    pointers that an application can use by calling the WinQuerySysPointer
  13850.    function. System mouse pointers include all the standard mouse-pointer
  13851.    shapes and message-box icons.
  13852.  
  13853.    You can also load mouse pointers that are defined in the resource file for
  13854.    your application. Typically, you define the mouse-pointer resource using
  13855.    Icon Editor or a similar program. The resulting mouse pointer or icon can
  13856.    then be included in your resource file. This is done by pulling the Icon
  13857.    Editor data file into your resource file using the key word POINTER, a
  13858.    resource ID number, and a filename for the mouse-pointer data created by
  13859.    the Icon Editor. When the mouse-pointer resource is included in the
  13860.    resource file, you can use it by calling the WinLoadPointer function,
  13861.    specifying the pointer-resource ID and the resource-module handle.
  13862.    Typically, the resource resides in the executable file of the application,
  13863.    so you can supply NULL for the module handle to indicate the current
  13864.    application resource file.
  13865.  
  13866.    Finally, you can create mouse pointers at run time by constructing a
  13867.    bitmap for the pointer and calling the WinCreatePointer function. The
  13868.    bitmap must be twice as tall as it is wide, with the first half defining
  13869.    the AND mask and the second half defining the XOR mask. You also must
  13870.    specify the hot spot when you create a mouse pointer. The handle returned
  13871.    can be used to set or draw the mouse pointer.
  13872.  
  13873.  22.3.2  Changing the Mouse Pointer
  13874.  
  13875.    Once you create or load a mouse pointer, you can change its shape by
  13876.    calling the WinSetPointer function. The following are three main
  13877.    situations where an application typically changes the shape of the mouse
  13878.    pointer:
  13879.  
  13880.    ■  When an application receives a WM_MOUSEMOVE message, there is an
  13881.       opportunity to change the mouse pointer based on its location the
  13882.       window. If you want the standard arrow pointer, pass this message on to
  13883.       the WinDefWindowProc function.
  13884.  
  13885.    ■  When an application is about to start a time-consuming process during
  13886.       which it will not accept user input, the application should display the
  13887.       "system-wait" mouse pointer. This pointer is shaped like an hourglass,
  13888.       indicating that the user must wait. Once this process is complete, the
  13889.       application should reset the mouse pointer to its former shape.
  13890.  
  13891.    ■  The following code fragment shows how to save the current mouse
  13892.       pointer, set the hourglass pointer, and then restore the original mouse
  13893.       pointer. Notice that the hourglass pointer is also saved in a global
  13894.       variable so that the application can return it when responding to a
  13895.       WM_MOUSEMOVE message during a time-consuming process.
  13896.  
  13897.       /* Get current pointer. */
  13898.  
  13899.       hptrOld = WinQueryPointer(HWND_DESKTOP);
  13900.  
  13901.       /* Get wait mouse pointer. */
  13902.  
  13903.       hptrWait = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE);
  13904.  
  13905.       /* Save wait pointer to use in WM_MOUSEMOVE processing.*/
  13906.  
  13907.       hptrCurrent = hptrWait;
  13908.  
  13909.       /* Set mouse pointer to wait pointer.*/
  13910.  
  13911.       WinSetPointer(HWND_DESKTOP, hptrWait);
  13912.  
  13913.       /* Do time-consuming operation; restore original mouse pointer.*/
  13914.  
  13915.       WinSetPointer(HWND_DESKTOP, hptrOld);
  13916.  
  13917.    ■  The mouse pointer can be used to indicate the current operational mode
  13918.       of an application. For example, a paint program with a palette of
  13919.       drawing tools should change the mouse pointer shape to indicate which
  13920.       drawing tool is currently in use.
  13921.  
  13922.  22.3.3  Drawing an Icon
  13923.  
  13924.    You can use mouse-pointer resources to draw icons. The WinDrawPointer
  13925.    function draws a specified mouse pointer in a specified presentation
  13926.    space. Many of the predefined system mouse pointers are standard icons
  13927.    displayed in message boxes.
  13928.  
  13929.  22.3.4  System Bitmaps
  13930.  
  13931.    In addition to mouse pointers and icons defined by the system, you can use
  13932.    standard system bitmaps by calling the WinGetSysBitmap function. This
  13933.    function returns a bitmap handle that is passed to the WinDrawBitmap
  13934.    function or one of the Gpi bitmap calls. The system uses standard bitmaps
  13935.    to draw portions of control windows such as the system menu, the
  13936.    minimize/maximize box, and scroll-bar arrows.
  13937.  
  13938.  
  13939.  22.4  Summary
  13940.  
  13941.    The following sections describe the system mouse pointers and the
  13942.    functions available for mouse pointers, icons, and system bitmaps.
  13943.  
  13944.  22.4.1  Predefined Mouse Pointers
  13945.  
  13946.    MS OS/2 provides many predefined mouse-pointer shapes. You receive a
  13947.    handle to these pointers by using one of the following constants as an
  13948.    argument to the WinQuerySysPointer function:
  13949.  
  13950.    SPTR_APPICON  Square icon.
  13951.  
  13952.    SPTR_ARROW  Arrow that points to the upper-left corner of the screen.
  13953.  
  13954.    SPTR_ICONERROR  Icon containing an exclamation point, used in a warning
  13955.    dialog box.
  13956.  
  13957.    SPTR_ICONINFORMATION  Octagon-shaped icon containing the image of a human
  13958.    hand, used in a warning dialog box.
  13959.  
  13960.    SPTR_ICONQUESTION  Icon containing a question mark, used in a query dialog
  13961.    box.
  13962.  
  13963.    SPTR_ICONWARNING  Icon containing an asterisk, used in a warning dialog
  13964.    box.
  13965.  
  13966.    SPTR_MOVE  Four-headed arrow, used when dragging an object or window
  13967.    around the screen.
  13968.  
  13969.    SPTR_SIZENESW  Two-headed diagonal arrow that points from the upper-right
  13970.    (northeast) window border to the lower-left (southwest) window border,
  13971.    used when sizing a window.
  13972.  
  13973.    SPTR_SIZENS  Two-headed arrow that points from top to bottom (north to
  13974.    south), used when sizing a window.
  13975.  
  13976.    SPTR_SIZENWSE  Two-headed diagonal arrow that points from the upper-left
  13977.    (northwest) window border to the lower-right (southeast) window border,
  13978.    used when sizing a window.
  13979.  
  13980.    SPTR_SIZEWE  Two-headed arrow that points from left to right (west to
  13981.    east), used when sizing a window.
  13982.  
  13983.    SPTR_TEXT  Text-insertion and selection pointer, often called the I-beam
  13984.    pointer.
  13985.  
  13986.    SPTR_WAIT  Hourglass, used to indicate that a time-consuming operation is
  13987.    in progress.
  13988.  
  13989.    MS OS/2 contains a second set of predefined mouse pointers that are used
  13990.    as icons in Presentation Manager. The resulting mouse pointer must be
  13991.    explicitly destroyed using the WinDestroyPointer function before the
  13992.    application terminates. These icons are available for application use by
  13993.    supplying one of the following constants to the WinQuerySysPointer
  13994.    function:
  13995.  
  13996.    SPTR_FILE  Icon representing a single file (in the shape of a single sheet
  13997.    of paper). It must be explicitly destroyed before the application
  13998.    terminates.
  13999.  
  14000.    SPTR_FOLDER  Icon representing a file folder. It must be explicitly
  14001.    destroyed before the application terminates.
  14002.  
  14003.    SPTR_ILLEGAL  Circular icon containing a slash, used to indicate an
  14004.    illegal operation. It must be explicitly destroyed before the application
  14005.    terminates.
  14006.  
  14007.    SPTR_MULTFILE  Icon representing multiple files. It must be explicitly
  14008.    destroyed before the application terminates.
  14009.  
  14010.    SPTR_PROGRAM  Icon representing an executable file. It must be explicitly
  14011.    destroyed before the application terminates.
  14012.  
  14013.  22.4.2  Mouse-Pointer Functions
  14014.  
  14015.    The following mouse-pointer functions can be used in your application:
  14016.  
  14017.    WinCreatePointer  Creates a mouse pointer from a bitmap.
  14018.  
  14019.    WinDestroyPointer  Destroys a pointer or an icon. A pointer can only be
  14020.    destroyed by the thread that created it. This function decrements the use
  14021.    count of processes that have accessed the pointer. The pointer is deleted
  14022.    when the use count reaches zero.
  14023.  
  14024.    WinDrawPointer  Draws the specified mouse pointer (or icon) in a
  14025.    presentation space.
  14026.  
  14027.    WinGetSysBitmap  Returns a handle to one of the standard bitmaps provided
  14028.    by the system. The bitmap returned can be used for any routine bitmap
  14029.    operations. The WinGetSysBitmap function returns a new copy of the system
  14030.    bitmap each time it is called.
  14031.  
  14032.    The following bitmaps are available:
  14033.  
  14034. ╓┌─┌───────────────────────┌─────────────────────────────────────────────────╖
  14035.    Bitmap                  Description
  14036.    ──────────────────────────────────────────────────────────────────────────
  14037.    SBMP_BTNCORNERS         Push-button corners.
  14038.  
  14039.    SBMP_CHECKBOXES         Check-box or radio-button check mark.
  14040.  
  14041.    SBMP_CHILDSYSMENU       Smaller version of the system-menu bitmap, used in
  14042.                            child windows.
  14043.  
  14044.    SBMP_DRIVE              Symbol used by File System to indicate a disk
  14045.                            drive.
  14046.  
  14047.    SBMP_FILE               Symbol used by File System to indicate a .
  14048.  
  14049.    SBMP_FOLDER             Symbol used by File System to indicate
  14050.                            subdirectories.
  14051.    Bitmap                  Description
  14052.    ──────────────────────────────────────────────────────────────────────────
  14053.                           subdirectories.
  14054.  
  14055.    SBMP_MAXBUTTON          Maximize button.
  14056.  
  14057.    SBMP_MENUATTACHED       Symbol used to indicate that a menu item has an
  14058.                            attached, hierarchical menu.
  14059.  
  14060.    SBMP_MENUCHECK          Menu check mark.
  14061.  
  14062.    SBMP_MINBUTTON          Minimize button.
  14063.  
  14064.    SBMP_PROGRAM            Symbol used by File System to indicate that a file
  14065.                            is an executable program.
  14066.  
  14067.    SBMP_RESTOREBUTTON      Restore button.
  14068.  
  14069.    SBMP_SBDNARROW          Scroll-bar down arrow.
  14070.  
  14071.    SBMP_SBLFARROW          Scroll-bar left arrow.
  14072.    Bitmap                  Description
  14073.    ──────────────────────────────────────────────────────────────────────────
  14074.   SBMP_SBLFARROW          Scroll-bar left arrow.
  14075.  
  14076.    SBMP_SBRGARROW          Scroll-bar right arrow.
  14077.  
  14078.    SBMP_SBUPARROW          Scroll-bar up arrow.
  14079.  
  14080.    SBMP_SIZEBOX            Symbol used to indicate an area of a window that a
  14081.                            user can click to resize the window.
  14082.  
  14083.    SBMP_SYSMENU            System menu.
  14084.  
  14085.    SBMP_TREEMINUS          Symbol used by File System to indicate that an
  14086.                            entry in the directory tree is empty.
  14087.  
  14088.    SBMP_TREEPLUS           Symbol used by File System to indicate that an
  14089.                            entry in the directory tree contains more files.
  14090.    ──────────────────────────────────────────────────────────────────────────
  14091.  
  14092.  
  14093.    WinLoadPointer  Loads a pointer resource from a resource file into the
  14094.    system and returns a mouse-pointer handle. A new copy of the pointer is
  14095.    created each time this function is called. Once used, the pointer created
  14096.    by this function must be explicitly destroyed by using the
  14097.    WinDestroyPointer function.
  14098.  
  14099.    WinQueryPointer  Returns a mouse-pointer handle for the current mouse
  14100.    pointer and can be used to restore the mouse pointer after any temporary
  14101.    changes.
  14102.  
  14103.    WinQueryPointerInfo  Retrieves information about a specific mouse pointer,
  14104.    including its bitmap and its hot-spot coordinates.
  14105.  
  14106.    WinQueryPointerPos  Retrieves the current mouse-pointer position in screen
  14107.    coordinates.
  14108.  
  14109.    WinQuerySysPointer  Returns a handle to the specified system mouse
  14110.    pointer. You can specify whether you want a handle to the system's copy of
  14111.    the mouse pointer or if you want a separate copy for modification.
  14112.  
  14113.    WinSetPointer  Sets the current mouse pointer.
  14114.  
  14115.    WinSetPointerPos  Sets the mouse-pointer position in screen coordinates.
  14116.  
  14117.    WinShowPointer  Shows or hides the mouse pointer.
  14118.  
  14119.  
  14120.  
  14121.  ────────────────────────────────────────────────────────────────────────────
  14122.  Chapter 23  Cursors
  14123.  
  14124.         23.1    Introduction
  14125.         23.2    About Cursors
  14126.         23.3    Using Cursors in an Application
  14127.             23.3.1    Creating a Cursor
  14128.             23.3.2    Destroying a Cursor
  14129.             23.3.3    Showing the Cursor
  14130.             23.3.4    Positioning the Cursor
  14131.         23.4    Summary
  14132.  
  14133.  23.1  Introduction
  14134.  
  14135.    This chapter describes the functions that allow you to use cursors in your
  14136.    applications. You should also be familiar with the following topics:
  14137.  
  14138.    ■  Standard user-interface guidelines
  14139.  
  14140.    ■  Window activation and deactivation
  14141.  
  14142.    ■  Keyboard focus
  14143.  
  14144.  
  14145.  23.2  About Cursors
  14146.  
  14147.    A cursor is a rectangle that can be shown at any location in a window. It
  14148.    is usually used to mark a text-insertion point or to indicate when a
  14149.    control window has the keyboard focus. For example, entry-field controls
  14150.    use a flashing vertical bar to show the insertion point when the control
  14151.    has the keyboard focus. A button control, on the other hand, appears as a
  14152.    halftone rectangle the size of the button when the button has the keyboard
  14153.    focus. MS OS/2 draws and flashes the cursor, freeing the application from
  14154.    handling these details. Note that the cursor has no direct relationship
  14155.    with the mouse pointer.
  14156.  
  14157.  
  14158.  23.3  Using Cursors in an Application
  14159.  
  14160.    Typically, applications use cursors to mark the text-insertion point in a
  14161.    text window or to indicate that a window has the keyboard focus.
  14162.  
  14163.    There can be only one cursor in use by the system at one time, so windows
  14164.    must create and destroy cursors as they gain and lose the keyboard focus.
  14165.    The following code fragment shows how an application should respond to a
  14166.    WM_SETFOCUS message when using a cursor in a particular window:
  14167.  
  14168.    case WM_SETFOCUS:
  14169.        if (SHORT1FROMMP(mp2)) {
  14170.  
  14171.            /* gain focus */
  14172.  
  14173.            WinCreateCursor(...);
  14174.            WinShowCursor(hwnd, TRUE);
  14175.        } else {
  14176.  
  14177.            /* lose focus */
  14178.  
  14179.            WinDestroyCursor(hwnd);
  14180.        }
  14181.        return 0L;
  14182.  
  14183.  23.3.1  Creating a Cursor
  14184.  
  14185.    An application creates a cursor by calling the WinCreateCursor function.
  14186.    Generally, this is done when a window gains the keyboard focus. An
  14187.    application specifies the window in which the cursor will be displayed.
  14188.    This window may be HWND_DESKTOP, an application window, or a control
  14189.    window.
  14190.  
  14191.    An application specifies the cursor position, in window coordinates, and
  14192.    the cursor height and width. It also specifies whether the cursor
  14193.    rectangle should be filled, framed, flashing, or halftone.
  14194.  
  14195.    The cursor width is usually zero (nominal border width is used) for
  14196.    text-insertion cursors. This is preferable to a value of 1, since such a
  14197.    fine width is almost invisible on a high-resolution monitor. The cursor
  14198.    width may also be related to the window size; for example, when a button
  14199.    control uses a dotted-line cursor around the button text to indicate
  14200.    focus.
  14201.  
  14202.    Finally, an application can specify a clipping rectangle, in window
  14203.    coordinates, that controls the cursor clipping region. Typically, the most
  14204.    efficient strategy is to specify NULL, causing the rectangle to clip the
  14205.    cursor to the window rectangle.
  14206.  
  14207.  23.3.2  Destroying a Cursor
  14208.  
  14209.    Applications should destroy cursors by calling the WinDestroyCursor
  14210.    function when they lose the keyboard focus. It is important that they be
  14211.    destroyed when they lose the focus. Manipulating two cursors in MS OS/2
  14212.    simultaneously can have unpredictable results and affect other
  14213.    applications.
  14214.  
  14215.  23.3.3  Showing the Cursor
  14216.  
  14217.    MS OS/2 maintains a "show level" for the cursor. The cursor is visible
  14218.    when the show level is zero. Each time the cursor is hidden, its show
  14219.    level is incremented. Each time the cursor is shown, its show level is
  14220.    decremented. Because the show/hide relationship is one for one, the show
  14221.    level can never go below zero.
  14222.  
  14223.    An application should show the cursor when it is first created since the
  14224.    cursor is created with a show level of 1.
  14225.  
  14226.    MS OS/2 automatically hides the cursor when the WinBeginPaint function is
  14227.    called, and shows the cursor when the WinEndPaint function is called.
  14228.    Therefore, there is no conflict with the cursor during WM_PAINT
  14229.    processing.
  14230.  
  14231.  23.3.4  Positioning the Cursor
  14232.  
  14233.    An application can set the position of an existing cursor by calling the
  14234.    WinCreateCursor function with the CURSOR_SETPOS flag set. This function
  14235.    can also be used to move a cursor around a window. Position arguments are
  14236.    given in window coordinates. To change the cursor size, destroy the
  14237.    current cursor and then create a new one with the desired size.
  14238.  
  14239.  
  14240.  23.4  Summary
  14241.  
  14242.    The following section summarizes the functions related to cursor
  14243.    management.
  14244.  
  14245.    WinCreateCursor  Creates a new cursor or changes the position of an
  14246.    existing cursor. The cursor is created when the window gains the keyboard
  14247.    focus (receives a WM_SETFOCUS message with the fFocus parameter set to
  14248.    TRUE).
  14249.  
  14250.    WinDestroyCursor  Destroys the cursor. The cursor is destroyed when the
  14251.    window loses the keyboard focus (receives a WM_SETFOCUS message with the
  14252.    fFocus parameter set to FALSE).
  14253.  
  14254.    WinShowCursor  Shows or hides the cursor. The cursor is visible if its
  14255.    show level is zero. Hiding the cursor increments its show level. Showing
  14256.    the cursor decrements the show level. The show level cannot go below zero
  14257.    (so the cursor can be shown an infinite number of times).
  14258.  
  14259.    WinQueryCursorInfo  Fills in a supplied CURSORINFO data structure with
  14260.    information about the cursor, including its size, position, and current
  14261.    show level.
  14262.  
  14263.  
  14264.  
  14265.  ────────────────────────────────────────────────────────────────────────────
  14266.  Chapter 24  Printing
  14267.  
  14268.         24.1    Introduction
  14269.         24.2    About Printing
  14270.             24.2.1    The Print Queue and the Spooler
  14271.         24.3    Printing
  14272.             24.3.1    Specifying the Default Printer
  14273.             24.3.2    Opening a Device Context for a Printer
  14274.                 24.3.2.1   Logical Address
  14275.                 24.3.2.2   Printer-Driver Name
  14276.                 24.3.2.3   The Driver-Data Field
  14277.                 24.3.2.4   The Data-Type Field
  14278.                 24.3.2.5   Using the Print Queue
  14279.                 24.3.2.6   Creating a Device Context
  14280.             24.3.3    Starting a Print Job
  14281.             24.3.4    Associating a Presentation Space
  14282.             24.3.5    Drawing for Printing
  14283.                 24.3.5.1   Determining Page Size
  14284.                 24.3.5.2   Printing a Page
  14285.                 24.3.5.3   Finishing a Print Job
  14286.             24.3.6    Destroying the Printer Device Context
  14287.         24.4    Special Printing Topics
  14288.             24.4.1    Page Setup
  14289.             24.4.2    Using a Thread to Print
  14290.             24.4.3    Printing to a File
  14291.             24.4.4    Printing a Bitmap
  14292.             24.4.5    Optimizing Printing for a Particular Printer
  14293.         24.5    Summary
  14294.  
  14295.  24.1  Introduction
  14296.  
  14297.    This chapter describes how to print graphics and text to printers and
  14298.    plotters. You should also be familiar with the following topics:
  14299.  
  14300.    ■  Standard user-interface guidelines
  14301.  
  14302.    ■  Device contexts and presentation spaces
  14303.  
  14304.    ■  Window painting
  14305.  
  14306.    ■  Graphics programming interface (GPI)
  14307.  
  14308.    ■  Extracting information from the os2.ini file
  14309.  
  14310.  
  14311.  24.2  About Printing
  14312.  
  14313.    The graphics model in MS OS/2 is based on presentation spaces and device
  14314.    contexts. Applications draw in a presentation space by using Gpi graphics
  14315.    functions. The presentation space is associated with a device context that
  14316.    translates graphics commands into device-specific operations that display
  14317.    graphics on a device. By associating a presentation space with different
  14318.    device contexts, an application can direct output to different devices,
  14319.    ranging from screen displays to printers and plotters.
  14320.  
  14321.    The central concept when printing in MS OS/2 is device independence. The
  14322.    same graphics commands used to draw on the screen can be used to draw
  14323.    graphics. For example, a word processor can display its text in a window
  14324.    by calling Gpi character and string-drawing functions. When printing, the
  14325.    same application can use the same Gpi functions to draw the text, the only
  14326.    difference being that the presentation space is associated with a printer
  14327.    instead of with a window. Printing can be thought of as drawing in a
  14328.    window the size of a sheet of paper. Figure 24.1 shows how output goes
  14329.    through a presentation space to a device context and finally to an output
  14330.    device.
  14331.  
  14332.    ┌────────────────────────────────────────────────────────────────────────┐
  14333.    │ Figure 24.1 can be found in Section 24.2 of the printed manual.        │
  14334.    └────────────────────────────────────────────────────────────────────────┘
  14335.  
  14336.    Figure 24.1  Application to Device Path
  14337.  
  14338.    Choosing the appropriate presentation-space units is an important
  14339.    consideration in achieving device independence for an application. If you
  14340.    use device-independent units, such as LOENGLISH, HIENGLISH, LOMETRIC, or
  14341.    HIMETRIC, your graphics commands will produce nearly the same results on
  14342.    all devices. If you use the PELS unit, you must explicitly allow for the
  14343.    pel size and aspect ratio of the output device.
  14344.  
  14345.    For example, if you use LOENGLISH units (each unit is 0.01 inch), a call
  14346.    to the GpiBox function asking for a 100-unit box produces a 1-inch box on
  14347.    any output device, regardless of the pel size or aspect ratio. In
  14348.    contrast, if you issue the same command using the PELS unit, the box will
  14349.    be one size on the screen (approximately 72 pels per inch) and much
  14350.    smaller on a laser printer (300 pels per inch). Additionally, the box will
  14351.    not be square on an EGA display because its pels are not square.
  14352.  
  14353.    Of course, there are limits to the device-independence of MS OS/2
  14354.    graphics, depending on the physical limitations of the output device.
  14355.    Output typically looks better on a laser printer with 300 pels per inch
  14356.    than on a dot-matrix printer with lower resolution. The value of device
  14357.    independence is that you do not have to be concerned with the different
  14358.    capabilities of each device. Instead, images are drawn in a virtual page
  14359.    and the device context makes the best use of the available resolution.
  14360.  
  14361.    If you use the PELS units, you can do scaling by querying the device
  14362.    context to determine the horizontal and vertical resolution. But it is
  14363.    much better to use a device-independent measurement unit and allow MS OS/2
  14364.    to scale your drawings to the selected device.
  14365.  
  14366.  24.2.1  The Print Queue and the Spooler
  14367.  
  14368.    MS OS/2 provides the means for applications to spool printing jobs so that
  14369.    applications do not wait for printing to finish before proceeding with
  14370.    other processing. The main components of the spooling capability of MS
  14371.    OS/2 are the spooler (pmspool.exe) and the queue processor (pmprint.qpr).
  14372.    When an application submits a queued printing job, the graphics commands
  14373.    that comprise the print job are output in a device-independent metafile
  14374.    format. The queue processor takes the metafile output and sends it to the
  14375.    printer, translating the contents into printer-specific commands. (The
  14376.    queue processor calls the printer driver to help translate the metafile
  14377.    commands into printer-specific commands.)
  14378.  
  14379.    The spooler may or may not be involved in this process. If it is active,
  14380.    the spooler manages the metafile output as a spool file and coordinates a
  14381.    queue of spool files waiting to be processed by the queue processor. If
  14382.    the spooler is not active, the metafile is passed directly from the
  14383.    application to the queue processor. The spooler is an optional
  14384.    intermediary between the application and the queue processor.
  14385.  
  14386.    It is irrelevant to an application whether or not the spooler is active.
  14387.    The user determines if the spooler is running by using Control Panel. An
  14388.    application should always queue its printing output because this takes
  14389.    advantage of the device-independent features of metafiles and the queue
  14390.    processor. If the spooler is active, the queued output will be managed by
  14391.    the spooler. If the spooler is not active, the spooled output will go
  14392.    directly to the queue processor. An application might need to wait longer
  14393.    before printing finishes when the spooler is not active.
  14394.  
  14395.  
  14396.  24.3  Printing
  14397.  
  14398.    The following sections describe the typical steps for printing from an MS
  14399.    OS/2 application. The procedures described here allow you to print to the
  14400.    widest range of output devices. Special printing strategies are described
  14401.    later in this chapter. The following topics will be discussed:
  14402.  
  14403.    ■  Specifying the default printer
  14404.  
  14405.    ■  Opening a device context for a printer
  14406.  
  14407.    ■  Starting a print job
  14408.  
  14409.    ■  Associating a presentation space for printing
  14410.  
  14411.    ■  Drawing the print job in the presentation space
  14412.  
  14413.    ■  Finishing a print job
  14414.  
  14415.    ■  Destroying the printer device context
  14416.  
  14417.  24.3.1  Specifying the Default Printer
  14418.  
  14419.    A user specifies each printer attached to a particular system by making
  14420.    choices in Control Panel that is part of the user shell. A user can
  14421.    install new printer drivers and associate printers with print queues.
  14422.    Information about available printers can be found in the os2.ini file. You
  14423.    can access this information by calling the WinQueryProfileString function,
  14424.    specifying the appropriate sections and keywords.
  14425.  
  14426.    An application should not set the default printer directly. Applications
  14427.    should use the printer specified as the default in the os2.ini file.
  14428.  
  14429.    Before using a printer with an application, you should know its driver
  14430.    name and the logical address. To find this information, find the name of
  14431.    the default printer by calling the WinQueryProfileString function for the
  14432.    "PM_SPOOLER" section and the "PRINTER" keyword, as shown in the following
  14433.    code fragment:
  14434.  
  14435.    /* Get the default printer name, for example, "PRINTER1." */
  14436.  
  14437.    cb = WinQueryProfileString(hab,
  14438.        "PM_SPOOLER",        /* section name           */
  14439.        "PRINTER",           /* keyname                */
  14440.        "",                  /* default                */
  14441.        szPrinter,           /* profile string         */
  14442.        32);                 /* maximum characters     */
  14443.  
  14444.    szPrinter[cb-2] = 0;     /* remove terminating ";" */
  14445.  
  14446.    The call to the WinQueryProfileString function fills the supplied string
  14447.    variable with the name of the installed printer. A typical printer name is
  14448.    "PRINTER1". You use this name of the printer as the keyword specifier and
  14449.    "PM_SPOOLER_PRINTER" as the section name, and then call the
  14450.    WinQueryProfileString function again to get a string, called the "printer
  14451.    details," containing several substrings. The substrings contain the name
  14452.    of the printer driver and the name of the logical port that the printer is
  14453.    attached to. The following code fragment shows how to use the
  14454.    WinQueryProfileString function to extract this information. The code
  14455.    fragment assumes that the name of the default printer in the variable
  14456.    szPrinter has been filled in by a call to WinQueryProfileString.
  14457.  
  14458.    /* Get the printer details.
  14459.     *   Fill in a supplied string with substrings:
  14460.     *   <physical port>;<driver name>;<queue port>;<network params>;
  14461.     *   typically "LPT1;IBM4201;LPT1Q;;"
  14462.     */
  14463.    cb = WinQueryProfileString(hab,
  14464.        "PM_SPOOLER_PRINTER", /* section name       */
  14465.        szPrinter,            /* keyname            */
  14466.        "",                   /* default            */
  14467.        szDetails,            /* profile string     */
  14468.        256);                 /* maximum characters */
  14469.  
  14470.    Once you extract the long string of substrings from os2.ini, you must
  14471.    parse the string to find the substrings. The string contains four
  14472.    substrings: the name of the physical-printer port (for example, LPT1), the
  14473.    name of the printer driver (for example, IBM4201), the name of the logical
  14474.    port (for example, LPT1Q), and network information (if any). Each
  14475.    substring is separated from the next by a semicolon (;), so you can use
  14476.    the library function strchr to search for semicolons and return pointers
  14477.    to the positions in the string.
  14478.  
  14479.    There can be more than one driver name. For example, the string might look
  14480.    like the following:
  14481.  
  14482.    LPT1;IBM4201,PSCRIPT;LPT1Q;;
  14483.  
  14484.    When more than one name is included, the first name is the default name.
  14485.    You should always check for a comma (,) in the driver name to make sure
  14486.    only one name is returned. Control Panel sometimes appends other
  14487.    information to the driver name. You should always parse the driver name
  14488.    and strip off text beginning at the period.
  14489.  
  14490.    Once you determine the name of the driver and the logical address of the
  14491.    printer, you can open a device context and a presentation space for the
  14492.    printer.
  14493.  
  14494.  24.3.2  Opening a Device Context for a Printer
  14495.  
  14496.    Calls to the WinQueryProfileString function to produce the name of the
  14497.    installed-printer driver and logical address. Using this information, you
  14498.    can open a device context for a printer. The main role of the device
  14499.    context is to translate graphics calls from an application into
  14500.    device-specific operations. The device context is associated with a
  14501.    presentation space. All drawing in the presentation space is directed to
  14502.    the device rather than to the screen.
  14503.  
  14504.    You open a device context for a printer by calling the DevOpenDC function
  14505.    and passing it a pointer to a DEVOPENSTRUC data structure. There are eight
  14506.    pointers in DEVOPENSTRUC, but typically only the first four fields must be
  14507.    filled (the logical address, the printer-driver name, driver data, and
  14508.    data type) to open a device context.
  14509.  
  14510.    24.3.2.1  Logical Address
  14511.  
  14512.    The logical address of a printer is the destination for the print data.
  14513.    Generally, you use the third substring of the printer-detail string
  14514.    returned by the WinQueryProfileString function, as explained earlier in
  14515.    this chapter. You can also print directly to a physical port, such as
  14516.    LPT1, by specifying the name of the physical port as the logical address.
  14517.    You can also supply a filename to direct print output to a file.
  14518.  
  14519.    24.3.2.2  Printer-Driver Name
  14520.  
  14521.    The printer-driver name identifies the driver that controls the printing
  14522.    device. The printer-driver name is usually extracted from the
  14523.    printer-detail string in the os2.ini file, as explained earlier in this
  14524.    chapter. MS OS/2 adds a filename extension (.drv) to the name you supply.
  14525.  
  14526.    24.3.2.3  The Driver-Data Field
  14527.  
  14528.    The driver-data field points to a printer-specific data structure that
  14529.    describes aspects of the page, such as the page layout (portrait or
  14530.    landscape) and the default data format (PM_Q_STD or PM_Q_RAW). If you set
  14531.    this field to NULL, the printer driver uses the default settings
  14532.    established by the user when the printer driver was installed with Control
  14533.    Panel. The user can also use Control Panel at any time to change printer
  14534.    settings.
  14535.  
  14536.    If NULL is passed for the driver-data pointer, the settings most recently
  14537.    set in Control Panel will be used. Because Control Panel is always
  14538.    available, it is not necessary for an application to provide the means to
  14539.    change these settings. However, it is possible to change the driver data
  14540.    for a particular print job from an application by calling the
  14541.    DevPostDeviceModes function.
  14542.  
  14543.    24.3.2.4  The Data-Type Field
  14544.  
  14545.    The data-type field is a string that specifies the print-data format. The
  14546.    two possibilities supported by MS OS/2 version 1.1 are PM_Q_STD and
  14547.    PM_Q_RAW. You can supply NULL for this field to obtain the default data
  14548.    type for the printer.
  14549.  
  14550.    ■  The PM_Q_STD format contains data generated by Gpi graphics calls,
  14551.       including graphics calls to draw text. This format is generally used
  14552.       and is the most versatile and printer-independent.
  14553.  
  14554.    ■  The PM_Q_RAW format contains a printer-specific data stream generated
  14555.       by the application rather than by the translated graphics commands of
  14556.       the PM_Q_STD format. You should use the PM_Q_RAW format only if you
  14557.       know the exact capabilities of the printer. For example, this format
  14558.       might be useful for an application that produces its own PostScript
  14559.       output directly rather than relying on Gpi commands to be translated by
  14560.       the device context. It might also be useful for sending a text stream
  14561.       to a printer that does not support graphics. If you use the PM_Q_RAW
  14562.       format, you can send the data to the printer by calling DevEscape with
  14563.       the DEVESC_RAWDATA control code.
  14564.  
  14565.    24.3.2.5  Using the Print Queue
  14566.  
  14567.    One of the arguments to the DevOpenDC function specifies the type of
  14568.    device context to open. The possibilities that are applicable to
  14569.    printing-device contexts are OD_QUEUED, OD_DIRECT, and OD_INFO. Generally,
  14570.    OD_QUEUED is used to take advantage of the spooling capabilities of MS
  14571.    OS/2. If a user has the spooler turned on, graphics calls are captured as
  14572.    a spool file and placed in the print queue. The spooler passes the spool
  14573.    file to the queue processor for actual printing. Once a queued file has
  14574.    been written to its spool file, the application is free to continue with
  14575.    other tasks. This means that a user can continue working without waiting
  14576.    for a document to print.
  14577.  
  14578.    Even if the spooler is turned off, you should use a OD_QUEUED device
  14579.    context. If the spooler is absent, printing data is passed directly from
  14580.    the application to the queue processor where it is processed for final
  14581.    output to the device. It does not matter if the spooler is running or not.
  14582.    You should always queue your printing output, except when you want to
  14583.    bypass the print queue or when you want to open a device context for
  14584.    information only. You can use OD_DIRECT when you want to bypass the print
  14585.    queue, such as when printing to a file.
  14586.  
  14587.    You can use OD_INFO to open a device context for information only, such as
  14588.    during program initialization when determining the page size of the
  14589.    current printer. Knowing the page size of the printer can be used to
  14590.    provide on-screen pagination information. However, an application should
  14591.    always check the page dimensions before printing because the user may have
  14592.    changed the default printer.
  14593.  
  14594.    24.3.2.6  Creating a Device Context
  14595.  
  14596.    Once the device-specific information described earlier in this chapter is
  14597.    obtained, you can open the device context. In the DEVOPENSTRUC structure,
  14598.    the first three fields point to the driver name, the logical-address name,
  14599.    and the DRIVDATA structure, respectively. The device-context type is set
  14600.    to OD_QUEUED so that the output will be queued. The following code
  14601.    fragment shows how to open a device context, assuming that the
  14602.    printer-driver name and the logical-address name have been obtained:
  14603.  
  14604.    /*
  14605.     * Fill in the DEVOPENSTRUC structure
  14606.     *
  14607.     * The name of the driver and logical address were obtained by calling
  14608.     * WinQueryProfileString. The driver data came from DevPostDeviceModes.
  14609.     */
  14610.  
  14611.  
  14612.    DEVOPENSTRUC dop;
  14613.    PSZ          pszDriverName;
  14614.    PSZ          pszLogAddress;
  14615.  
  14616.    /*
  14617.     * Use WinQueryProfileString to fill in pszDriverName
  14618.     * and pszLogAddress.
  14619.     */
  14620.  
  14621.    dop.pszDriverName = pszDriverName; /* from os2.ini */
  14622.    dop.pszLogAddress = pszLogAddress; /* from os2.ini */
  14623.    dop.pdriv = NULL;
  14624.    dop.pszDataType = "PM_Q_STD";
  14625.  
  14626.    /* Now open the device context. */
  14627.    hdcPrinter = DevOpenDC(hab,
  14628.                           OD_QUEUED,
  14629.                           "*",
  14630.                           4L,       /* use first four fields */
  14631.                           (PDEVOPENDATA) &dop,
  14632.                           (HDC) NULL);
  14633.  
  14634.  24.3.3  Starting a Print Job
  14635.  
  14636.    Once a device context is successfully opened using a printer driver, a
  14637.    "start doc" message must be issued to the device context to tell it a new
  14638.    document is starting. The start-doc escape call includes a string that is
  14639.    displayed by the queue manager as the print-job name. Typically, a
  14640.    filename is supplied as the document name, as shown in the following code
  14641.    fragment:
  14642.  
  14643.    LONG lrc;
  14644.  
  14645.    /* Start a document. */
  14646.  
  14647.    lrc = DevEscape(hdcPrinter,
  14648.                    DEVESC_STARTDOC,
  14649.                    strlen(pszDocName),
  14650.                    pszDocName,
  14651.                    NULL,
  14652.                    NULL);
  14653.  
  14654.  24.3.4  Associating a Presentation Space
  14655.  
  14656.    The device-context handle returned by the DevOpenDC function is used to
  14657.    create a presentation space for drawing. You specify zero for the x- and
  14658.    y- dimensions of the presentation space so that the system can make the
  14659.    presentation space large enough to include a single page using the
  14660.    specified device context. You cannot use a cached-micro presentation space
  14661.    for printing. If you use an absolute-measurement environment──for example,
  14662.    PU_LOENGLISH or PU_HIMETRIC, graphics will automatically be the same size
  14663.    on screen and when printed. If you use PU_PELS, you must scale the
  14664.    graphics commands to match the different resolutions of the screen and the
  14665.    printer.
  14666.  
  14667.    SIZEL sizl;
  14668.  
  14669.    sizl.cx = 0L;
  14670.    sizl.cy = 0L;
  14671.  
  14672.    hpsPrinter = GpiCreatePS(hab, hdcPrinter, &sizl,
  14673.        PU_LOENGLISH | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
  14674.  
  14675.    Another strategy is to use for printing the same presentation space used
  14676.    for window painting. This saves creating a new presentation space. In this
  14677.    case, the presentation space must be a GPIT_NORMAL presentation space. The
  14678.    presentation space must first be disassociated from the device context
  14679.    that it has been associated with (usually a window device context), and
  14680.    then associated with the printer device context, as shown in the following
  14681.    code fragment:
  14682.  
  14683.    GpiAssociate(hpsWindow, NULL);        /* disassociate first     */
  14684.        .
  14685.        .
  14686.        .
  14687.    GpiAssociate(hpsWindow, hdcPrinter);  /* associate with printer */
  14688.  
  14689.    You must be cautious of the WM_PAINT message during printing operations if
  14690.    you use the same presentation space for printing and window drawing. The
  14691.    presentation space cannot be used to respond to the paint message while
  14692.    the presentation space is associated with the printer device context. For
  14693.    more information, see Section 24.4.2.
  14694.  
  14695.    Once a printer device context has been associated with a presentation
  14696.    space, graphics functions can be called to draw each document page.
  14697.  
  14698.  24.3.5  Drawing for Printing
  14699.  
  14700.    Application data images are usually expressed in "world space." This is
  14701.    the coordinate system in which all graphics commands are expressed. The
  14702.    units of the world space are typically application-convenient units, such
  14703.    as 0.01-inch (LOENGLISH). Images are drawn in windows by expressing
  14704.    graphics commands in convenient units. The system scales and converts
  14705.    these units to the device-specific units of the display so that the image
  14706.    appears correct in the window.
  14707.  
  14708.    If an image is larger than a window, a matrix translation is used to slide
  14709.    the coordinate system of the world space to match the coordinate system of
  14710.    the window. Figure 24.2 illustrates how a translation might be used to
  14711.    map a portion of the world space to a window display space.
  14712.  
  14713.    ┌────────────────────────────────────────────────────────────────────────┐
  14714.    │ Figure 24.2 can be found in Section 24.3.5 of the printed manual.      │
  14715.    └────────────────────────────────────────────────────────────────────────┘
  14716.  
  14717.    Figure 24.2  World-Space to Device-Space Translation
  14718.  
  14719.    The central idea behind drawing for printing is that it is very similar to
  14720.    drawing for a window that is the size of a piece of paper. The system
  14721.    performs the same scaling transformation to convert world-space units to
  14722.    device units. This automatic scaling allows the same imaging code to draw
  14723.    for both a 72-dot-per-inch impact printer and a 300-dot-per-inch laser
  14724.    printer.
  14725.  
  14726.    24.3.5.1  Determining Page Size
  14727.  
  14728.    In order to print images to a printer or plotter, the page size must be
  14729.    expressed in convenient units. For example, if you do all your drawing in
  14730.    0.01-inch (LOENGLISH) units, you will need the page size in 0.01-inch
  14731.    units rather than in device units (PELS). To determine the page size, call
  14732.    the DevQueryCaps function for the given device to get the width and height
  14733.    of the device page in device units. These units can be converted to
  14734.    presentation-space units by calling the GpiConvert function, as shown in
  14735.    the following code fragment:
  14736.  
  14737.    SIZEL sizl;
  14738.  
  14739.    /* page size */
  14740.  
  14741.    DevQueryCaps(hdcPrinter, CAPS_WIDTH, 2L, (PLONG) &sizl);
  14742.  
  14743.    GpiConvert(hpsWindow, CVTC_DEVICE, CVTC_WORLD, 1L, (PPOINTL) &sizl);
  14744.  
  14745.    Once the page size has been determined, the image can be divided and drawn
  14746.    into pages for printing. Figure 24.3 shows how a multiple-page document
  14747.    might be broken into pages, assuming a user has selected portrait mode
  14748.    during printer setup. The figure shows how the page size is used to divide
  14749.    the world space into pages.
  14750.  
  14751.    ┌────────────────────────────────────────────────────────────────────────┐
  14752.    │ Figure 24.3 can be found in Section 24.3.5.1 of the printed manual.    │
  14753.    └────────────────────────────────────────────────────────────────────────┘
  14754.  
  14755.    Figure 24.3  Portrait-Mode Pages in World Space
  14756.  
  14757.    The page size returned reflects either portrait or landscape mode,
  14758.    depending on what the user selects in Control Panel. Figure 24.4 shows
  14759.    how these same pages are divided for landscape mode. Notice that no
  14760.    additional page rotation or extra support work must be done for landscape
  14761.    mode. As long as you use the x- and y-sizes returned by the DevQueryCaps
  14762.    and GpiConvert functions, a document will be correctly paginated.
  14763.  
  14764.    ┌────────────────────────────────────────────────────────────────────────┐
  14765.    │ Figure 24.4 can be found in Section 24.3.5.1 of the printed manual.    │
  14766.    └────────────────────────────────────────────────────────────────────────┘
  14767.  
  14768.    Figure 24.4  Landscape-Mode Pages in World Space
  14769.  
  14770.    24.3.5.2  Printing a Page
  14771.  
  14772.    Each page of a print job is drawn by making Gpi calls to the world space
  14773.    of the presentation space. If a document consists of only one page, then
  14774.    the origin of the world space probably corresponds to the origin of the
  14775.    device page, so no translation is necessary. To print a multi-page
  14776.    document, you must translate world-space coordinates so that they line up
  14777.    each page with the origin before drawing.
  14778.  
  14779.    For example, to print page 2 in Figure 24.4, you would apply a
  14780.    translation on the x- and y-axis to slide the desired page so that its
  14781.    lower-left corner sits at the origin. Assuming that a SIZEL structure
  14782.    holds the horizontal and vertical dimensions of the page, a call to the
  14783.    GpiSetDefaultViewMatrix function slides page 2 down and over to the
  14784.    origin. Notice that first you call the GpiQueryDefaultViewMatrix function
  14785.    to fill in the other values of the nine-element matrix, then the x- and
  14786.    y-translation fields are filled in, then the matrix is set.
  14787.  
  14788.    MATRIXLF matrix;
  14789.    SIZEL    sizl;   /* size of page, in world units */
  14790.  
  14791.    /* First get the current transformation matrix. */
  14792.  
  14793.    GpiQueryDefaultViewMatrix(hps, 9, &matrix);
  14794.  
  14795.    /* Change the x- and y-translation elements. */
  14796.  
  14797.    matrix.lM31 = -sizl.cx;
  14798.    matrix.lM32 = -sizl.cy;
  14799.  
  14800.    /* Call GpiSetDefaultViewMatrix to translate image to page. */
  14801.  
  14802.    GpiSetDefaultViewMatrix(hps, 9, &matrix, TRANSFORM_REPLACE);
  14803.  
  14804.    For a multi-page document, you must call the DevEscape function with the
  14805.    DEVESC_NEWFRAME escape at the end of each page to begin a new page. It is
  14806.    not necessary to send a DEVESC_NEWFRAME escape after the last page.
  14807.  
  14808.    24.3.5.3  Finishing a Print Job
  14809.  
  14810.    After printing all pages in a print job, you must call the DevEscape
  14811.    function with the DEVESC_ENDDOC code telling the queue processor that the
  14812.    print job is finished.
  14813.  
  14814.  24.3.6  Destroying the Printer Device Context
  14815.  
  14816.    Once drawing is finished, the presentation space should be disassociated
  14817.    from the printer device context. If a special presentation space was
  14818.    created for printing, it can be destroyed along with the device context,
  14819.    as shown in the following code fragment:
  14820.  
  14821.    GpiAssociate(hpsPrinter, NULL);
  14822.    DevCloseDC(hdcPrinter);
  14823.    GpiDestroyPS(hpsPrinter);
  14824.  
  14825.    However, if an existing presentation space was used for printing, you
  14826.    should disassociate the presentation space from the printing device
  14827.    context, reassociating the presentation space with its original window
  14828.    device context.
  14829.  
  14830.  
  14831.  24.4  Special Printing Topics
  14832.  
  14833.    The following sections describe special printing techniques.
  14834.  
  14835.  24.4.1  Page Setup
  14836.  
  14837.    One of the fields in the DEVOPENSTRUC structure, used when opening a
  14838.    device context, is pDriverData, a pointer to a DRIVDATA structure. This
  14839.    structure contains device-specific information about the page
  14840.    configuration (landscape or portrait), page size, default font, and other
  14841.    page-configuration details. The size and contents of the DRIVDATA
  14842.    structure depend on the printer being used. Typically, a user specifies
  14843.    the default configuration information from Control Panel. Control Panel
  14844.    stores this information for each printer in the os2.ini file. If NULL is
  14845.    supplied for the driver data when opening the device context, the printer
  14846.    driver retrieves the system-wide default driver data from os2.ini and uses
  14847.    it to configure page characteristics.
  14848.  
  14849.    An application can always use the page configuration specified by the user
  14850.    in Control Panel. If more control is required, calling the
  14851.    DevPostDeviceModes function displays a dialog window that can be used to
  14852.    specify new page characteristics for individual print jobs. Driver data
  14853.    retrieved by this dialog window applies to the current print job. It does
  14854.    not change the system default settings.
  14855.  
  14856.    Figure 24.5 shows a dialog window that fills in the DRIVDATA structure
  14857.    for an IBM4201 printer.
  14858.  
  14859.    ┌────────────────────────────────────────────────────────────────────────┐
  14860.    │ Figure 24.5 can be found in Section 24.4.1 of the printed manual.      │
  14861.    └────────────────────────────────────────────────────────────────────────┘
  14862.  
  14863.    Figure 24.5  IBM4201 Page Setup
  14864.  
  14865.    The DevPostDeviceModes function displays the page-setup dialog window. Any
  14866.    changes in page setup are reflected in the DRIVDATA structure and passed
  14867.    to the DevOpenDC function to obtain a device context matching the page
  14868.    characteristics.
  14869.  
  14870.    The following code fragment shows how to call the DevPostDeviceModes
  14871.    function to fill the DRIVDATA structure. You call it first with a NULL
  14872.    structure pointer to determine the size of the device-specific structure.
  14873.    Using the size value returned, it is possible to allocate memory and pass
  14874.    a far pointer to the DevPostDeviceModes function, which in turn fills the
  14875.    device information in the structure.
  14876.  
  14877.    ULONG     ulSize;
  14878.    PDRIVDATA pdriv;
  14879.  
  14880.    ulSize = DevPostDeviceModes(hab,
  14881.        NULL,             /* NULL for data size only */
  14882.        pszDriverName,    /* driver name             */
  14883.        NULL,             /* device name             */
  14884.        szPrinter,        /* printer name            */
  14885.        0L);              /* not used here           */
  14886.  
  14887.    /* Now allocate some memory. */
  14888.  
  14889.    usResult = DosAllocSeg(ulSize, &sel, 0);
  14890.  
  14891.    pdriv = MAKEP(sel, 0);
  14892.  
  14893.    ulSize = DevPostDeviceModes(hab,
  14894.        pdriv,                       /* buffer for drivdata */
  14895.        pszDriverName,               /* driver name         */
  14896.        NULL,                        /* device name         */
  14897.        szPrinter,                   /* printer name        */
  14898.        0L);      /* Display dialog. Do not change os2.ini. */
  14899.  
  14900.    Notice that the last argument to the DevPostDeviceModes function is a long
  14901.    word that determines whether or not the function changes the contents of
  14902.    the os2.ini file. The following values are valid:
  14903.  
  14904.    Value     Meaning
  14905.    ──────────────────────────────────────────────────────────────────────────
  14906.    0         Displays a dialog window for driver data without changing the
  14907.              defaults in the os2.ini file. This is appropriate for an
  14908.              application that configures a single print job without changing
  14909.              system-wide settings.
  14910.  
  14911.    1         Displays a dialog window for driver data and writes the new
  14912.              driver data, which becomes the default, to the os2.ini file.
  14913.              This is appropriate for Control Panel because the new default
  14914.              settings affect the entire system. Generally, applications
  14915.              should not change the driver data for the entire system.
  14916.  
  14917.    2         Does not display a dialog window; returns the default-driver
  14918.              data from the os2.ini file. This is useful for saving
  14919.              default-driver data with a particular document.
  14920.    ──────────────────────────────────────────────────────────────────────────
  14921.  
  14922.    If you use the DevPostDeviceModes function to set up the driver data for
  14923.    an individual document, you should save the driver data along with the
  14924.    document so that the settings are available to the user when the document
  14925.    is reopened. Be sure the printer driver is the same as it was when the
  14926.    driver data was created because the data format is unique to each printer
  14927.    driver.
  14928.  
  14929.  24.4.2  Using a Thread to Print
  14930.  
  14931.    An MS OS/2 application should not be unresponsive to user input for an
  14932.    extended period of time. Any operation that takes longer than 1 second
  14933.    should be carried out in a separate thread, allowing the user-interface
  14934.    thread to continue to respond to user input.
  14935.  
  14936.    Printing typically begins when a user chooses a command from a menu in an
  14937.    application. A client window receives a WM_COMMAND message from the menu
  14938.    and begins the printing operation. No further mouse clicks or keystrokes
  14939.    are processed until the application calls the WinGetMsg or WinPeekMsg
  14940.    function again. Therefore, the user cannot interact with an application
  14941.    menu or switch to another application until one of these two functions is
  14942.    called.
  14943.  
  14944.    The following are two basic ways to allow an application to remain
  14945.    responsive during a lengthy printing operation:
  14946.  
  14947.    ■  Call the WinGetMsg or WinPeekMsg function at regular intervals during
  14948.       printing to handle user input.
  14949.  
  14950.    ■  Create a separate thread to handle printing. The main thread can
  14951.       continue to call the WinGetMsg function while the printing thread
  14952.       executes.
  14953.  
  14954.    Handling user input during printing can cause many problems with data
  14955.    integrity and synchronization. For example, should a user be allowed to
  14956.    modify a document while it is printing? Semaphores should be used to
  14957.    protect shared resources whenever there are potential conflicts.
  14958.  
  14959.    One simple solution to the data synchronization problem is to create a
  14960.    thread for printing and display a message box in the main thread that
  14961.    allows a user to cancel printing. The printing thread could periodically
  14962.    check a semaphore controlled by a message box to determine if printing has
  14963.    been cancelled. This way a user cannot modify data in an application while
  14964.    it is printing, but can switch to another application while printing
  14965.    continues.
  14966.  
  14967.    Another possible problem when handling messages during printing is
  14968.    receiving WM_PAINT messages. Because printing and window drawing typically
  14969.    use the same drawing functions and the same data, drawing routines must be
  14970.    reentrant. If the same presentation space is used for window painting and
  14971.    printing, an application should not draw in the window when the
  14972.    presentation space is associated with the printer device context.
  14973.  
  14974.  24.4.3  Printing to a File
  14975.  
  14976.    Some printer drivers allow data to be sent to a file rather than to a
  14977.    device. In particular, a PostScript device driver and a plotter device
  14978.    driver direct print data to files if a filename is supplied in the
  14979.    pszLogAddress field of the DEVOPENSTRUC structure when opening a device
  14980.    context for printing. All output from printing is sent to this file. If
  14981.    the file already exists, its data is overwritten. If the file does not
  14982.    exist, the device driver creates it. These two device drivers support this
  14983.    feature because their data stream is ASCII text. The IBM4201 device
  14984.    driver, which sends mostly binary data to the printer, does not support
  14985.    printing to a file.
  14986.  
  14987.    You should open an OD_DIRECT device context when printing to a file.
  14988.  
  14989.  24.4.4  Printing a Bitmap
  14990.  
  14991.    Printing a bitmap requires that the bitmap be converted from its original
  14992.    format, which is usually compatible with the video display, to a format
  14993.    for the current printing device. The GpiSetBitmap function converts
  14994.    bitmaps from one device format to another.
  14995.  
  14996.    You must perform the following steps to print a bitmap on a printer:
  14997.  
  14998.    1.  Create a device context and a presentation space for the screen.
  14999.  
  15000.    2.  Create a memory device context for the screen and associate it with a
  15001.        presentation space.
  15002.  
  15003.    3.  Create a bitmap and attach it to the memory presentation space and
  15004.        device context using the GpiSetBitmap function.
  15005.  
  15006.    4.  Draw the bitmap from the screen presentation space and device context
  15007.        to the memory presentation space and device context using the
  15008.        GpiBitBlt or GpiWCBitBlt function.
  15009.  
  15010.    5.  Create a device context and presentation space for the printer.
  15011.  
  15012.    6.  Create a memory device context for the printer and associate it with a
  15013.        presentation space.
  15014.  
  15015.    7.  Convert the bitmap from the display-memory presentation space and
  15016.        device context to the format of the printer-memory presentation space
  15017.        and device context.
  15018.  
  15019.    8.  Attach it to the printer-memory presentation space and device context
  15020.        by calling the GpiSetBitmap function.
  15021.  
  15022.    9.  Draw the bitmap from the printer-memory presentation space and device
  15023.        context to the printer presentation space and device context by using
  15024.        the GpiBitBlt or GpiWCBitBlt function. Do any scaling necessary to
  15025.        correct for resolution differences between the display and the
  15026.        printer.
  15027.  
  15028.    The GpiSetBitmap function converts the different device formats, such as
  15029.    color to monochrome, but does not correct for differences in pel
  15030.    resolution between devices. For example, if you are printing a screen
  15031.    bitmap (typically about 72 pels per inch to a laser printer with 300 pels
  15032.    per inch, you must scale the image when converting from the printer-memory
  15033.    device context to the device context. You can determine the differences in
  15034.    pel resolution by calling the DevQueryCaps function for each device.
  15035.  
  15036.  24.4.5  Optimizing Printing for a Particular Printer
  15037.  
  15038.    You can optimize printing for certain printers not usually available
  15039.    through the API by using the DevEscape function. Escape calls are sent to
  15040.    the device driver, which must interpret them. The DevEscape function
  15041.    signals the beginning and end of documents of single pages, and sends
  15042.    printer-specific binary data to a printer.
  15043.  
  15044.  
  15045.  24.5  Summary
  15046.  
  15047.    The following functions can be used in setting up a printing operation:
  15048.  
  15049.    DevCloseDC  Closes a device context opened by the DevOpenDC function.
  15050.  
  15051.    DevEscape  Sends escape codes to the specified device. Starts and stops
  15052.    printing, signals the end of a page, and sends printer-specific binary
  15053.    data to a printer.
  15054.  
  15055.    DevOpenDC  Opens a device context for a printing device.
  15056.  
  15057.    DevPostDeviceModes  Displays a dialog window for a user to specify various
  15058.    printer configuration information.
  15059.  
  15060.    DevQueryCaps  Returns information about a specific device, such as the
  15061.    width and height of a page.
  15062.  
  15063.    GpiAssociate  Associates a presentation space with a device context for a
  15064.    particular printer, or disassociates the presentation space from its
  15065.    current device context if a NULL device context is specified.
  15066.  
  15067.    GpiConvert  Converts device units to world coordinates from one coordinate
  15068.    system to another.
  15069.  
  15070.    GpiCreatePS  Creates a presentation space that can be associated with a
  15071.    printing-device context.
  15072.  
  15073.    GpiDestroyPS  Destroys a presentation space created by the GpiCreatePS
  15074.    function.
  15075.  
  15076.    GpiQueryDefaultViewMatrix  Queries the current viewing transformation
  15077.    matrix and fills in a supplied MATRIXL structure. This function retrieves
  15078.    the current viewing transformation matrix so that the x- and y-translation
  15079.    elements can be changed.
  15080.  
  15081.    GpiSetBitmap  Connects a bitmap with a presentation space that is
  15082.    associated with a memory device context, converting a bitmap from one
  15083.    device format to another, such as converting between the screen and a
  15084.    printer.
  15085.  
  15086.    GpiSetDefaultViewMatrix  Sets the viewing transformation matrix so that
  15087.    the x- and y-translation values can be used to move portions of a
  15088.    world-space image to the origin for printing.
  15089.  
  15090.    WinQueryProfileString  Retrieves the name of the current default printer
  15091.    and printer driver from the os2.ini file.
  15092.  
  15093.  
  15094.  
  15095.  ────────────────────────────────────────────────────────────────────────────
  15096.  Chapter 25  Heaps
  15097.  
  15098.         25.1    Introduction
  15099.         25.2    About Heaps
  15100.         25.3    Using a Heap in an Application
  15101.             25.3.1    Creating a Heap
  15102.             25.3.2    Heaps in a Separate Data Segment
  15103.             25.3.3    Moveable Heap Objects
  15104.                 25.3.3.1   Moveable Heaps in an Automatic Data Segment
  15105.                 25.3.3.2   Moveable Heaps in a Separate Data Segment
  15106.             25.3.4    Allocating Memory from Heaps
  15107.             25.3.5    Deallocating Memory from a Heap
  15108.             25.3.6    Using Dedicated Free Lists
  15109.             25.3.7    Destroying Heaps
  15110.         25.4    Summary
  15111.  
  15112.  25.1  Introduction
  15113.  
  15114.    This chapter describes the functions that allow you to use heaps for
  15115.    memory management in your applications. You should also be familiar with
  15116.    the following topic:
  15117.  
  15118.    ■  Memory management in MS OS/2
  15119.  
  15120.  
  15121.  25.2  About Heaps
  15122.  
  15123.    A heap is a memory segment containing other memory-block objects that are
  15124.    allocated and deallocated by the functions of the heap manager (the group
  15125.    of functions that manage heaps in MS OS/2). The heap functions are
  15126.    provided to supplement, and in some cases replace, the basic
  15127.    memory-management functions of MS OS/2. The heap functions provide more
  15128.    functionality than the basic memory-management functions, including
  15129.    moveable objects within a segment and faster allocation implementation.
  15130.  
  15131.    A heap exists within a memory segment. The segment can be the automatic
  15132.    data segment of an application or dynamic-link module, or it can be
  15133.    another segment that has been allocated explicitly by using the
  15134.    DosAllocSeg function. Typically, the heap is part of an automatic data
  15135.    segment, and it shares that segment with the application's static data and
  15136.    stack. The combined size of the heap, static data, and stack cannot be
  15137.    larger than 64K──this is the maximum segment size in MS OS/2. Heaps in
  15138.    separate segments also cannot be larger than 64K.
  15139.  
  15140.    Figure 25.1 shows how a heap can share an automatic data segment with the
  15141.    static data and stack:
  15142.  
  15143.    ┌────────────────────────────────────────────────────────────────────────┐
  15144.    │ Figure 25.1 can be found in Section 25.2 of the printed manual.        │
  15145.    └────────────────────────────────────────────────────────────────────────┘
  15146.  
  15147.    Figure 25.1  Heap in Automatic Data Segment
  15148.  
  15149.    A heap typically contains many memory-allocation objects. Each object is
  15150.    accessed by an offset (near pointer) from the beginning of the segment.
  15151.    Notice that the beginning of the heap is not necessarily at the beginning
  15152.    of the segment. For heaps in the automatic data segment, the application
  15153.    or dynamic-link module can use the near pointer to the memory object
  15154.    directly, because the data-segment selector is implicit. For heaps
  15155.    allocated in separate segments, the near pointer must be combined with the
  15156.    segment selector to make a far pointer.
  15157.  
  15158.    A heap can be created so that objects within the heap are moveable. This
  15159.    allows the system to rearrange objects on the heap to make more free
  15160.    memory available and avoid heap fragmentation.
  15161.  
  15162.    MS OS/2 attempts to make the heap larger if a memory-allocation request
  15163.    cannot be filled by using the existing heap. This growth is controlled by
  15164.    setting growth limits when the heap is created.
  15165.  
  15166.  
  15167.  25.3  Using a Heap in an Application
  15168.  
  15169.    Applications typically create a heap, allocate and deallocate memory
  15170.    blocks in the heap as needed, and destroy the heap when terminating. A
  15171.    heap can be created using many different memory sources and it can have
  15172.    moveable or nonmoveable memory objects. The following sections discuss how
  15173.    to use heaps in applications and dynamic-link libraries.
  15174.  
  15175.  25.3.1  Creating a Heap
  15176.  
  15177.    Applications and dynamic-link libraries create a heap by calling the
  15178.    WinCreateHeap function. The heap is created within an automatic data
  15179.    segment or in a separate segment, depending on the values of the
  15180.    selHeapBase and cbHeap parameters of WinCreateHeap. The possible values of
  15181.    these parameters are summarized in the following list:
  15182.  
  15183.    selHeapBase cbHeap    Meaning
  15184.    ──────────────────────────────────────────────────────────────────────────
  15185.    Zero        Zero      The calling process is an application that places
  15186.                          the heap at the end of its automatic data segment.
  15187.  
  15188.    Selector    Nonzero   The calling process is either a dynamic-link library
  15189.                          that places a heap at the end of its automatic data
  15190.                          segment, or an application or dynamic-link library
  15191.                          that has explicitly allocated a segment and places
  15192.                          the heap at the end of the segment.
  15193.  
  15194.    Selector    Zero      The calling process is either an application or
  15195.                          dynamic-link library that has explicitly allocated a
  15196.                          segment and places a heap in that segment.
  15197.  
  15198.    Zero        Nonzero   The calling process is either an application or
  15199.                          dynamic-link library that places a heap of a
  15200.                          specific size in a separate segment but does not
  15201.                          call the DosAllocSeg function.
  15202.    ──────────────────────────────────────────────────────────────────────────
  15203.  
  15204.    In addition to the characteristics of the heap described by the preceding
  15205.    list, the creator of the heap may specify whether the heap contains
  15206.    moveable objects and whether the functions should check the validity of
  15207.    certain arguments to heap-manager functions. The HM_MOVEABLE attribute
  15208.    specifies that the heap can contain moveable objects. The HM_VALIDSIZE
  15209.    attribute, which can be used only in conjunction with HM_MOVEABLE,
  15210.    specifies that the heap manager should check the validity of size
  15211.    arguments in heap-deallocation calls. Moveable heap objects allow a more
  15212.    flexible memory-management scheme for applications with heavy memory
  15213.    requirements.
  15214.  
  15215.    You must specify the minimum amount the heap will grow each time it
  15216.    enlarges to satisfy a memory request. The default minimum is 512 bytes.
  15217.  
  15218.    The cbMinDed and cbMaxDed parameters of the WinCreateHeap function define
  15219.    how many dedicated free lists the heap manager should maintain for the
  15220.    heap. Dedicated free lists can make the allocation of fixed-size blocks
  15221.    significantly faster, but they are not essential to the operation of the
  15222.    heap. Zeros can be passed as values for these parameters to generate the
  15223.    default heap behavior without using dedicated free lists. More information
  15224.    about dedicated free lists is given later in this chapter.
  15225.  
  15226.    For more information on the WinCreateHeap function, see the Microsoft
  15227.    Operating System/2 Programmer's Reference, Volume 2.
  15228.  
  15229.    The following code fragment shows how to create a heap with the default
  15230.    behavior and the moveable attribute:
  15231.  
  15232.    hHeap = WinCreateHeap(0,  /* uses automatic data segment         */
  15233.        0,                    /* uses HEAPSIZE from .def file        */
  15234.        1024,                 /* minimum size to grow heap           */
  15235.        0,                    /* minimum size of dedicated free list */
  15236.        0,                    /* maximum size of dedicated free list */
  15237.        HM_MOVEABLE);
  15238.  
  15239.    The ability to share a heap depends upon the sharing attributes of the
  15240.    segment containing the heap. Heaps in an application's data segment are
  15241.    private to that application. Segments explicitly allocated with the
  15242.    DosAllocSeg function are shared or private, depending upon the value of
  15243.    the fsAlloc parameter. Segments allocated by using the WinCreateHeap
  15244.    function are shareable. Because shared segments cannot shrink, heaps
  15245.    within a shared segment also do not shrink.
  15246.  
  15247.    The heap manager does not prevent multiple threads from calling the heap
  15248.    manager with the same heap handle. The calling process must ensure that
  15249.    this does not occur.
  15250.  
  15251.  25.3.2  Heaps in a Separate Data Segment
  15252.  
  15253.    One of the options you can specify when creating a heap is that the heap
  15254.    will be created in a data segment that is separate from the automatic data
  15255.    segment. You might choose this option if there is insufficient space in
  15256.    the automatic data segment for the static variables, the stack, and the
  15257.    heap. A heap in a separate data segment can occupy up to 64K.
  15258.  
  15259.    The pointer returned by the WinAllocMem function is an offset value that
  15260.    locates the allocated memory block relative to the beginning of the
  15261.    segment that contains the heap. If the heap is in a separate segment, you
  15262.    must use far pointers to access memory blocks that are allocated on the
  15263.    heap. You can determine the far pointer to a heap object by using the
  15264.    heap's segment selector and the offset. The WinLockHeap function returns a
  15265.    far pointer to the beginning of a specified heap. You can combine the
  15266.    selector from this far pointer with the offset to a memory block on the
  15267.    heap to produce a far pointer to the heap object, as shown in the
  15268.    following code fragment:
  15269.  
  15270.    HHEAP   hHeap;
  15271.    SEL     selHeap;
  15272.    NPBYTE  npbObject;
  15273.    PBYTE   pbObject;
  15274.    PVOID   pvHeap;
  15275.  
  15276.    /* Allocate a heap in a separate segment. */
  15277.  
  15278.    hHeap = WinCreateHeap(0,  /* uses a separate segment             */
  15279.        32*1024,              /* allocates 32K for heap              */
  15280.        1024,                 /* minimum size to grow heap           */
  15281.        0,                    /* minimum size of dedicated free list */
  15282.        0,                    /* maximum size of dedicated free list */
  15283.        HM_MOVEABLE);
  15284.  
  15285.    /* Allocate an object and retrieve a near pointer. */
  15286.  
  15287.    npbObject = WinAllocMem(hHeap,...);
  15288.  
  15289.    /* Retrieve a far pointer to the start of the heap. */
  15290.  
  15291.    pvHeap = WinLockHeap(hHeap);
  15292.  
  15293.    /* Make a far pointer to the heap object. */
  15294.  
  15295.    pbObject = MAKEP(SELECTOROF(pvHeap), npbObject);
  15296.  
  15297.  25.3.3  Moveable Heap Objects
  15298.  
  15299.    A moveable heap allows the memory objects within the heap to move in order
  15300.    to reclaim fragmented heap space. All heaps are moveable in the sense that
  15301.    a segment that contains a heap can move as a result of the mapping of
  15302.    selectors to physical addresses that is provided by MS OS/2. Moveable
  15303.    heaps differ from regular heaps in that individual objects within a
  15304.    movable heap can change their positions relative to the beginning of the
  15305.    segment. The moveable-heap attribute is specified when the heap is created
  15306.    and lasts until the heap is destroyed.
  15307.  
  15308.    Allocated memory blocks in a moveable heap have a header structure that is
  15309.    attached to the beginning of the block. This header structure contains a
  15310.    pointer to the variable holding the pointer to the memory block and a
  15311.    field containing the size of the block (not including the header
  15312.    structure). The near pointer returned by the WinAllocMem function points
  15313.    to the first byte after the block-header words. The C definition of the
  15314.    header structure is as follows:
  15315.  
  15316.    typedef struct _MOVBLOCKHDR {
  15317.        NPBYTE  *ppmem;
  15318.        USHORT  cb;
  15319.    } MOVBLOCKHDR;
  15320.  
  15321.    The size parameter of the WinReallocMem and WinFreeMem functions is
  15322.    ignored for objects in a moveable heap and the value of the size word is
  15323.    used instead. However, if the HM_VALIDSIZE option is specified in the
  15324.    WinCreateHeap function when the heap is created, the WinReallocMem and
  15325.    WinFreeMem functions verify that the passed size matches the current size
  15326.    and return an error if it does not.
  15327.  
  15328.    Objects in a moveable heap can move whenever the WinAvailMem function is
  15329.    called. Because this function is also called by WinAllocMem and
  15330.    WinReallocMem, objects can also move when these functions are called.
  15331.    WinReallocMem and WinAvailMem move blocks that have a back pointer.
  15332.    Allocated objects whose back pointer is zero are considered fixed and do
  15333.    not move.
  15334.  
  15335.    When allocating memory blocks within a moveable heap, the calling process
  15336.    specifies that the block is moveable by altering the back pointer (ppmem)
  15337.    field of the header structure so that it points to the variable holding
  15338.    the pointer returned by the WinAllocMem function. When WinAllocMem creates
  15339.    a block on a moveable heap, it clears the back pointer to zero. As long as
  15340.    the back pointer remains zero, the heap manager cannot move the block. If
  15341.    the application alters the value of the back pointer so that it points to
  15342.    a valid variable address within the same segment (by using an offset from
  15343.    the beginning of the segment), the heap manager will move the block, when
  15344.    necessary, to compact the heap. Whenever the heap manager moves the
  15345.    moveable block it also updates the variable pointed to by the back pointer
  15346.    so that the variable points to the new location of the block. The back
  15347.    pointer ensures that the application's reference to the moveable block is
  15348.    updated when the block moves.
  15349.  
  15350.    Note that MS OS/2 alters only the variable pointed to by the back pointer
  15351.    when it moves a moveable block. If the application has made copies of this
  15352.    variable, those copies will be invalid if the memory object moves.
  15353.  
  15354.    The SETMEMBACKPTR macro sets the back pointer of a moveable block. (It is
  15355.    assumed that the MOVBLOCKHDR data structure described above is also
  15356.    defined.) SETMEMBACKPTR uses the variable that holds the pointer returned
  15357.    by the WinAllocMem function and sets the back pointer of that block to
  15358.    point to the variable. The SETMEMPACKPTR macro is shown below. Note that
  15359.    it should not be used on nonmoveable heaps.
  15360.  
  15361.    #define SETMEMBACKPTR(npb) (((PMOVBLOCKHDR) npb) -1) -> ppmem = &npb
  15362.  
  15363.    The back pointer of a moveable block should point to the variable that
  15364.    holds the pointer returned by the WinAllocMem function. Since the back
  15365.    pointer is a near pointer, the variable pointed to must be in the same
  15366.    data segment as the heap. If the heap is in the automatic data segment
  15367.    (the default case), you can use a static or stack-based variable to hold
  15368.    the pointer. If the heap is in a separate data segment, you must allocate
  15369.    space for the pointer variable as a nonmoveable block on the heap.
  15370.  
  15371.    Using moveable blocks allows an application to use memory more efficiently
  15372.    and to avoid most memory-fragmentation problems. Using moveable heap
  15373.    objects, however, requires that the pointer references to the objects
  15374.    remain valid even when the objects move. The back pointer allows MS OS/2
  15375.    to handle updating an application's pointer variables, but the application
  15376.    must use the macro SETMEMBACKPTR to set the original link between the
  15377.    moveable block and its pointer variable.
  15378.  
  15379.    25.3.3.1  Moveable Heaps in an Automatic Data Segment
  15380.  
  15381.    Figure 25.2 shows the relationship of the pointer returned by the
  15382.    WinAllocMem function and the back pointer of the memory-block header when
  15383.    the heap is in the automatic data segment:
  15384.  
  15385.    ┌────────────────────────────────────────────────────────────────────────┐
  15386.    │ Figure 25.2 can be found in Section 25.3.3.1 of the printed manual.    │
  15387.    └────────────────────────────────────────────────────────────────────────┘
  15388.  
  15389.    Figure 25.2  Back Pointer for Moveable Heap Object in Automatic Data
  15390.    Segment
  15391.  
  15392.    The following code fragment shows how to allocate a block and then make it
  15393.    moveable by altering the value of the back pointer. This code works only
  15394.    if the heap is in the automatic data segment (the default case for most
  15395.    applications).
  15396.  
  15397.    static NPBYTE  pObject;
  15398.  
  15399.    /* Allocate the block for the object. */
  15400.  
  15401.    pObject = WinAllocMem(hHeap, sizeof(YOUR_OBJECT_TYPE));
  15402.  
  15403.    /* Make the block moveable. */
  15404.  
  15405.    SETMEMBACKPTR(pObject);
  15406.  
  15407.    You should avoid placing a pointer to a moveable heap object on the
  15408.    stack──that is, making it a local variable──if the heap object will
  15409.    continue to exist after the function has ended and the local variable has
  15410.    been cleared from the stack. This is dangerous because the heap manager
  15411.    could attempt to update the pointer variable, using the back pointer, and
  15412.    inadvertently write into the stack frame of another function.
  15413.  
  15414.    25.3.3.2  Moveable Heaps in a Separate Data Segment
  15415.  
  15416.    The variable pointed to by the back pointer must be in the same segment as
  15417.    the moveable block. For most applications, in which the heap is in the
  15418.    application's automatic data segment, the pointer variable can be in the
  15419.    application's static-data area. If the heap is in a separate segment, the
  15420.    variable must also be allocated on the same heap, and it must be in a
  15421.    nonmoveable block.
  15422.  
  15423.    Figure 25.3 shows the relationship of the pointer returned by the
  15424.    WinAllocMem function and the back pointer of the memory-block header when
  15425.    the heap is in a separate data segment:
  15426.  
  15427.    ┌────────────────────────────────────────────────────────────────────────┐
  15428.    │ Figure 25.3 can be found in Section 25.3.3.2 of the printed manual.    │
  15429.    └────────────────────────────────────────────────────────────────────────┘
  15430.  
  15431.    Figure 25.3  Back Pointer for Moveable Heap Object in Separate Data
  15432.    Segment
  15433.  
  15434.    Figure 25.3 shows a variable in the application's static-data area that
  15435.    points to the nonmoveable block containing the pointer to the moveable
  15436.    memory block. The variable that the application uses in its static-data
  15437.    area is a pointer to a pointer. Since the pointer to a pointer is pointing
  15438.    to another data segment, it must be a far pointer, consisting of the
  15439.    selector of the heap's data segment and the offset within that segment.
  15440.  
  15441.    The following code fragment shows how to allocate a block in a heap in a
  15442.    separate data segment and then make the block moveable by altering the
  15443.    value of the back pointer. The ppObject variable is declared with the
  15444.    static storage class so that it will be in the static area of the
  15445.    automatic data segment, rather than on the stack.
  15446.  
  15447.    static NPBYTE FAR *ppObject;
  15448.  
  15449.    /*
  15450.     * Allocate nonmoveable space for the pointer to the object
  15451.     * and make a far pointer to the pointer.
  15452.     */
  15453.  
  15454.    ppObject = MAKEP(SELECTOROF(WinLockHeap(hHeap)),
  15455.                                WinAllocMem(hHeap, sizeof(NPBYTE)));
  15456.  
  15457.    /* Allocate the block for the object. */
  15458.  
  15459.    *ppObject = WinAllocMem(hHeap, sizeof(YOUR_OBJECT_TYPE));
  15460.  
  15461.    /* Make the block moveable. */
  15462.  
  15463.    SETMEMBACKPTR(*ppObject);
  15464.  
  15465.    Once the pointer to a pointer is set up correctly and the back pointer is
  15466.    initialized, the ppObject variable should be dereferenced twice whenever
  15467.    the moveable memory block is accessed, as shown in the following example:
  15468.  
  15469.    /* Put a value into the moveable block. */
  15470.  
  15471.    **ppObject = 2;
  15472.  
  15473.  25.3.4  Allocating Memory from Heaps
  15474.  
  15475.    Once an application or dynamic-link library has created a heap, it can
  15476.    allocate blocks on the heap by calling the WinAllocMem function. The value
  15477.    returned by this function is a near pointer to the memory block, or NULL
  15478.    if the function is unsuccessful.
  15479.  
  15480.    All pointers to memory objects within a heap are 16-bit offsets from the
  15481.    start of the heap's segment. All memory objects in the heap are aligned on
  15482.    a 32-bit-word boundary──this means that the contents of the 2 low-order
  15483.    bits of a returned pointer are unused. The WinAllocMem function clears
  15484.    these bits. (The WinReallocMem and WinFreeMem functions require that they
  15485.    be zero.) The application can use these two bits for any purpose. The
  15486.    HEAP_MASK constant can be used to clear the bits when passing a parameter
  15487.    for a memory-block pointer to WinReallocMem or WinFreeMem.
  15488.  
  15489.    If the heap is created with the HM_MOVEABLE attribute, the size argument
  15490.    for the allocation is retained in the size word of the allocated block's
  15491.    header. The returned address is the address of the first byte after the
  15492.    header.
  15493.  
  15494.    The heap manager searches the heap for the first free block large enough
  15495.    to fulfill the allocation request. If the free block that is found is
  15496.    larger than what is needed to satisfy the request, the extra space is
  15497.    added to the appropriate dedicated free list. If no free block is found
  15498.    that is large enough, the heap manager attempts to combine free blocks by
  15499.    calling the WinAvailMem function. If this call does not generate a large
  15500.    enough free block, the heap manager attempts to enlarge the heap segment
  15501.    by the combined values of the size of the request and the minimum-growth
  15502.    parameter specified in the call to the WinCreateHeap function. If this
  15503.    attempt fails, the WinAllocMem function returns NULL, indicating that it
  15504.    could not allocate the memory block.
  15505.  
  15506.  25.3.5  Deallocating Memory from a Heap
  15507.  
  15508.    Memory blocks on the heap can be deallocated by calling the WinFreeMem
  15509.    function. The calling process must specify the heap handle, the pointer to
  15510.    the block, and the size of the block. The size argument must be accurate
  15511.    because the heap manager does not normally validate this argument. Passing
  15512.    an incorrect size argument to WinFreeMem can damage other blocks on the
  15513.    heap.
  15514.  
  15515.    The WinFreeMem function returns NULL if it successfully deallocates the
  15516.    memory block. The return value is NULL for success because of the
  15517.    following idiom for deallocating a memory block and invalidating the
  15518.    variable that contains the pointer to the block, all in one line of code:
  15519.  
  15520.    pMem = WinAllocMem(...);
  15521.  
  15522.    /* Code that uses the block. */
  15523.  
  15524.    pMem = WinFreeMem(pMem);
  15525.  
  15526.    For nonmoveable heaps, the heap manager has no way to check the size of
  15527.    blocks that it deallocates. For moveable blocks on a heap created with the
  15528.    HM_MOVEABLE and HM_VALIDSIZE attributes, the heap manager checks the size
  15529.    argument against the size specification in the moveable block's header and
  15530.    returns the pointer (instead of NULL) if the size parameter is invalid.
  15531.  
  15532.  25.3.6  Using Dedicated Free Lists
  15533.  
  15534.    A dedicated free list is a linked list of free blocks of a particular size
  15535.    on the heap. For example, the heap manager might maintain a dedicated free
  15536.    list of memory blocks that are 1024 bytes in length. It is much faster to
  15537.    search for a memory block in a dedicated free list than to do a straight
  15538.    linear search of all blocks on the heap. Thus, dedicated free lists are
  15539.    very useful if your application allocates many blocks with the same size.
  15540.  
  15541.    The size of memory blocks that should be maintained in dedicated free
  15542.    lists is specified when the heap is created. Two arguments to the
  15543.    WinCreateHeap function specify the minimum block size and the maximum
  15544.    block size to put into dedicated free lists. All memory sizes between the
  15545.    minimum and maximum sizes, in four-byte increments, are maintained in
  15546.    separate lists.
  15547.  
  15548.    For example, if you specify 1024 for the minimum size and 2048 for the
  15549.    maximum size, the heap manager creates dedicated free lists for memory
  15550.    blocks of 1024 bytes, 1028 bytes, 1032 bytes, and so on, through 2048
  15551.    bytes. The cost of each dedicated free list is an additional two bytes in
  15552.    the heap-control block for each size of memory block that is maintained in
  15553.    the list.
  15554.  
  15555.    Blocks that are not within the size limits of existing dedicated free
  15556.    lists are maintained in a single nondedicated free list. The heap manager
  15557.    first looks in the dedicated free lists, starting with the list whose
  15558.    memory-block size is greater than or equal to the requested size. It
  15559.    continues to look in the dedicated free lists until it either finds the
  15560.    smallest block that is greater than or equal to the requested size or it
  15561.    exhausts the dedicated free lists. If no block is found on the dedicated
  15562.    free lists that is large enough, the heap manager does a linear search of
  15563.    the nondedicated free list for the first block that satisfies the request.
  15564.    (This may not be the smallest free block that would satisfy the request,
  15565.    since the order of the nondedicated free list is
  15566.    implementation-dependent.) Dedicated free lists are organized in last-in,
  15567.    first-out (LIFO) order.
  15568.  
  15569.    To produce dedicated free lists in a heap, pass nonzero arguments for the
  15570.    cbMinDed and cbMaxDed parameters of the WinCreateHeap function.
  15571.  
  15572.  25.3.7  Destroying Heaps
  15573.  
  15574.    The WinDestroyHeap function destroys a heap that was created by using the
  15575.    WinCreateHeap function. If WinCreateHeap calls the DosAllocSeg function to
  15576.    allocate space for the heap, then WinDestroyHeap calls DosFreeSeg to free
  15577.    the allocated segment. Otherwise, WinDestroyHeap frees only the heap
  15578.    handle that is passed to it.
  15579.  
  15580.    The return value is zero if the WinDestroyHeap function is successful.
  15581.    Otherwise, the return value is the heap handle that is passed to the
  15582.    function. (A reason this function could fail is if the heap handle is
  15583.    invalid.) This function is not affected by allocated memory objects within
  15584.    the heap.
  15585.  
  15586.    The return value is zero for success because of the following idiom for
  15587.    destroying a heap and invalidating the variable that contains the handle
  15588.    to the heap, all in one line of code:
  15589.  
  15590.    hHeap = WinCreateHeap(...);
  15591.  
  15592.    /* Code that manipulates the heap. */
  15593.  
  15594.    hHeap = WinDestroyHeap(hHeap);
  15595.  
  15596.  
  15597.  25.4  Summary
  15598.  
  15599.    The following functions allow your application to manage heaps:
  15600.  
  15601.    WinAllocMem  Returns a near pointer to a memory block of the specified
  15602.    size on the heap. Returns NULL if the memory cannot be allocated.
  15603.  
  15604.    WinAvailMem  Returns the largest free block of memory on the heap.
  15605.  
  15606.    WinCreateHeap  Creates a heap that can be used for memory management.
  15607.  
  15608.    WinDestroyHeap  Destroys a heap. All memory objects on the heap are lost.
  15609.  
  15610.    WinFreeMem  Frees a memory block that was allocated by using the
  15611.    WinAllocMem function.
  15612.  
  15613.    WinLockHeap  Returns a far pointer to the beginning of the segment
  15614.    containing the heap and locks the heap. This is useful for a heap
  15615.    allocated in a separate segment.
  15616.  
  15617.    WinReallocMem  Reallocates a heap memory block to a new size. If the new
  15618.    size is larger than the previous size, a new block is allocated by using
  15619.    the WinAllocMem function and the previous block is copied to the new
  15620.    block.
  15621.  
  15622.  
  15623.  
  15624.  ────────────────────────────────────────────────────────────────────────────
  15625.  Chapter 26  Clipboard
  15626.  
  15627.         26.1    Introduction
  15628.         26.2    About the Clipboard
  15629.             26.2.1    Cutting, Copying, and Pasting Data
  15630.             26.2.2    Clipboard-Data Formats
  15631.             26.2.3    Shared Memory and the Clipboard
  15632.         26.3    Using the Clipboard
  15633.             26.3.1    Putting Data on the Clipboard
  15634.             26.3.2    Retrieving Data from the Clipboard
  15635.             26.3.3    Becoming the Clipboard Viewer
  15636.             26.3.4    Becoming the Clipboard Owner
  15637.             26.3.5    Custom Clipboard Formats
  15638.                 26.3.5.1   Assigning a Unique Format ID
  15639.                 26.3.5.2   Display Formats
  15640.             26.3.6    Delayed Rendering
  15641.         26.4    Summary
  15642.             26.4.1    Standard Clipboard Formats
  15643.             26.4.2    Clipboard Functions
  15644.             26.4.3    Clipboard Messages
  15645.  
  15646.  26.1  Introduction
  15647.  
  15648.    This chapter describes how to use the clipboard to transfer data between
  15649.    applications. You should also be familiar with the following topics:
  15650.  
  15651.    ■  Standard user-interface guidelines
  15652.  
  15653.    ■  Window messages and message queues
  15654.  
  15655.    ■  MS OS/2 memory management and shared memory
  15656.  
  15657.  
  15658.  26.2  About the Clipboard
  15659.  
  15660.    The clipboard is a set of functions that can be used by Presentation
  15661.    Manager applications for exchanging data. In particular, the clipboard
  15662.    provides support for the generalized cut, copy, and paste user-interface
  15663.    common to Presentation Manager applications. The clipboard supports data
  15664.    formats common to most applications, as well as allowing individual
  15665.    applications to define new formats for special purposes.
  15666.  
  15667.    The data on the clipboard is maintained in memory only. Clipboard data is
  15668.    lost when the computer is turned off.
  15669.  
  15670.    Data exchange on the clipboard is controlled by the user. An application
  15671.    should not perform any clipboard operations unless the user explicitly
  15672.    initiates them. Other MS OS/2 features, such as pipes, queues, and shared
  15673.    memory should be used when data exchange is needed without the knowledge
  15674.    of the user. For example, an application that continuously passes remotely
  15675.    collected data to a data-analysis application should not use the
  15676.    clipboard. Such an application should use the other interprocess data
  15677.    communication capabilities of MS OS/2 instead.
  15678.  
  15679.  26.2.1  Cutting, Copying, and Pasting Data
  15680.  
  15681.    All Presentation Manager programs should support the cut, copy, and paste
  15682.    data exchange in a single application and between applications. These are
  15683.    all user-initiated operations. Typically, a user selects data in an
  15684.    application, called the "current selection." The application should
  15685.    provide visual feedback, such as inverting the data display, to indicate
  15686.    the current selection. The user can then initiate a cut, copy, or paste
  15687.    operation on the current selection.
  15688.  
  15689.    The standard cut, copy, and paste operations are summarized below:
  15690.  
  15691.    Operation Description
  15692.    ──────────────────────────────────────────────────────────────────────────
  15693.    Cut       Copies the current selection to the clipboard and deletes the
  15694.              current selection from the application document. The previous
  15695.              contents of the clipboard are destroyed.
  15696.  
  15697.    Copy      Copies the current selection to the clipboard. The current
  15698.              selection remains unchanged. The previous contents of the
  15699.              clipboard are destroyed.
  15700.  
  15701.    Paste     Deletes the current selection and replaces it with the contents
  15702.              of the clipboard. The contents of the clipboard are not changed.
  15703.  
  15704.    Clear     Deletes the current selection without putting the data on the
  15705.              clipboard. The contents of the clipboard are not changed.
  15706.    ──────────────────────────────────────────────────────────────────────────
  15707.  
  15708.  26.2.2  Clipboard-Data Formats
  15709.  
  15710.    The clipboard accepts data in several formats. MS OS/2 supports three
  15711.    standard formats: text, bitmap, and metafile. Applications can use these
  15712.    predefined formats or create their own formats.
  15713.  
  15714.    Typically, all formats on the clipboard are simply different
  15715.    representations of the most recent selection on the clipboard. For
  15716.    example, a word processor that supports multiple fonts might write a
  15717.    selection to the clipboard in three formats: straight text, rich text, and
  15718.    metafile. Another application (pasting from the clipboard) could then
  15719.    choose the format most applicable to its own capabilities. All of these
  15720.    formats refer to the same data.
  15721.  
  15722.  26.2.3  Shared Memory and the Clipboard
  15723.  
  15724.    Because data on the clipboard can be accessed by different applications,
  15725.    it is important that it be stored in shared memory. The clipboard uses two
  15726.    types of memory: selectors for shareable segments (allocated by the
  15727.    DosAllocSeg function), and Presentation Manager objects such as bitmaps
  15728.    and metafiles. Clipboard functions use two flag values, CFI_SELECTOR and
  15729.    CFI_HANDLE, to distinguish each memory type.
  15730.  
  15731.    When an application writes either a bitmap or a metafile to the clipboard,
  15732.    it passes a bitmap or metafile handle to the clipboard. The clipboard
  15733.    functions make the object "shareable." The application cannot access the
  15734.    object once it closes the clipboard. Once an object is passed to the
  15735.    clipboard, it can no longer be used in the application. Likewise, when an
  15736.    application requests a bitmap or metafile from the clipboard, it receives
  15737.    a handle to a bitmap or metafile object that is good only until the
  15738.    application closes the clipboard. Typically, the application either uses
  15739.    the object immediately before closing the clipboard, or it copies the
  15740.    object to local memory for future use, then closes the clipboard.
  15741.  
  15742.    To give a selector to the clipboard, an application must put data into a
  15743.    segment allocated by using the DosAllocSeg function with the SEG_GIVEABLE
  15744.    attribute. Once an application passes the selector for that segment to the
  15745.    clipboard and closes the clipboard, the clipboard owns the segment. The
  15746.    application cannot access the shared segment. When an application requests
  15747.    a selector from the clipboard, the clipboard gives the segment to the
  15748.    application. An application must use the selector before closing the
  15749.    clipboard or it must copy the data from the shared segment to a local
  15750.    segment before closing the clipboard.
  15751.  
  15752.    An application must use a shared segment when writing text to the
  15753.    clipboard. An application must also use shared segments for any
  15754.    application-defined clipboard formats. In this case, it is important to
  15755.    specify the CFI_SELECTOR flag when sending data to the clipboard.
  15756.  
  15757.  
  15758.  26.3  Using the Clipboard
  15759.  
  15760.    Applications should use the clipboard when cutting, copying, or pasting
  15761.    data. Typically, an application places data on the clipboard for cut and
  15762.    copy operations and removes data from the clipboard for paste operations.
  15763.    An application can use the standard clipboard-data formats or create its
  15764.    own formats. An application that uses custom clipboard formats often
  15765.    becomes the clipboard owner, assuming control of drawing or freeing data
  15766.    on the clipboard.
  15767.  
  15768.    Clipboard data does not need to be generated, or rendered, when it is
  15769.    placed on the clipboard. Instead, an application can delay rendering,
  15770.    waiting until the data is requested by another application.
  15771.  
  15772.    Finally, an application can become the clipboard viewer, showing the
  15773.    clipboard contents, and receiving messages when the clipboard contents
  15774.    change.
  15775.  
  15776.  26.3.1  Putting Data on the Clipboard
  15777.  
  15778.    To put data on the clipboard, an application must first call the
  15779.    WinOpenClipbrd function to verify that other applications are not trying
  15780.    to retrieve or set clipboard data. The WinOpenClipbrd function does not
  15781.    return if another thread has the clipboard open. The WinOpenClipbrd
  15782.    function waits until the clipboard is free or there is a message in the
  15783.    calling thread's message queue. In practice, this means that the
  15784.    WinOpenClipbrd function waits until the clipboard is available or until
  15785.    the calling application responds to a message. If the clipboard cannot be
  15786.    opened before a message arrives, the application receives the message and
  15787.    the WinOpenClipbrd function continues to try to open the clipboard. The
  15788.    WinOpenClipbrd function does not return until the clipboard is open.
  15789.    However, the application continues receiving messages.
  15790.  
  15791.    Once an application successfully opens the clipboard, it should remove any
  15792.    previously stored data on the clipboard by calling the WinEmptyClipbrd
  15793.    function. Although the clipboard supports many data formats, all the
  15794.    formats on the clipboard should represent the same data at any one time.
  15795.    For this reason, it is important to clear the clipboard of old data before
  15796.    writing new data. If the clipboard is not cleared, writing a format that
  15797.    already exists on the clipboard will replace the old data with the new
  15798.    data.
  15799.  
  15800.    When the clipboard is cleared, an application should write its data to the
  15801.    clipboard in as many standard formats as possible. For each format, the
  15802.    application should pass the data to the clipboard by calling the
  15803.    WinSetClipbrdData function, specifying the data format. Because the
  15804.    clipboard is not cleared when a new format is written to the clipboard,
  15805.    all new data formats coexist with each other until the clipboard is
  15806.    cleared by the next clipboard user.
  15807.  
  15808.    Data passed to the clipboard can take many forms, depending on the format
  15809.    of the data. For text data, the data handle is a selector to a shared
  15810.    segment containing the text. For bitmap data, the data handle is a bitmap
  15811.    handle. For a metafile format, the data handle is a metafile handle. If an
  15812.    application passes NULL for the data handle, it renders the data on
  15813.    request.
  15814.  
  15815.    Once an application passes a selector or a handle to the clipboard, the
  15816.    application should not alter the contents of that segment or handle. The
  15817.    clipboard owns that data from then on.
  15818.  
  15819.    Finally, when an application finishes writing the clipboard data, it
  15820.    should release the clipboard by calling the WinCloseClipbrd function so
  15821.    that other applications can use the clipboard.
  15822.  
  15823.    The following code fragment shows how an application places text data on
  15824.    the clipboard, how it opens the clipboard, copies the text to a shared
  15825.    segment, empties the clipboard, and passes the selector to the clipboard:
  15826.  
  15827.    if (WinOpenClipbrd(hab)) {
  15828.  
  15829.        /*
  15830.         * Allocate a shareable segment for the data szClipString in the
  15831.         * application's copy of the text.
  15832.         */
  15833.  
  15834.        if (usSuccess = DosAllocSeg(strlen(szClipString) + 1,
  15835.                &sel, SEG_GIVEABLE )) {
  15836.  
  15837.            /* Make a far pointer (selector:0) out of the selector. */
  15838.  
  15839.            pszDest = MAKEP(sel, 0);
  15840.  
  15841.            /* Set up the source pointer to point to text. */
  15842.  
  15843.            pszSrc = &szClipString[0];
  15844.  
  15845.            /* Copy the string to the segment. */
  15846.  
  15847.            while (*pszDest++ = *pszSrc++);
  15848.  
  15849.            /* Clear old data from the clipboard. */
  15850.  
  15851.            WinEmptyClipbrd(hab);
  15852.  
  15853.            /*
  15854.             * Pass the selector to the clipboard in CF_TEXT format. Note
  15855.             * that the selector must be a ULONG value.
  15856.             */
  15857.  
  15858.            fSuccess = WinSetClipbrdData(hab, (ULONG) sel,
  15859.                CF_TEXT, CFI_SELECTOR);
  15860.  
  15861.            /* Close the clipboard. */
  15862.  
  15863.            WinCloseClipbrd(hab);
  15864.        }
  15865.    }
  15866.  
  15867.  26.3.2  Retrieving Data from the Clipboard
  15868.  
  15869.    To retrieve data from the clipboard, an application must first call the
  15870.    WinOpenClipbrd function to verify that no other applications are trying to
  15871.    retrieve or set the clipboard data.
  15872.  
  15873.    Once an application successfully opens the clipboard, it should call the
  15874.    WinQueryClipbrdData function, specifying a preferred format. If that
  15875.    format is not available, indicated by a NULL return from the
  15876.    WinQueryClipbrdData function, the application should repeat calls to the
  15877.    WinQueryClipbrdData function for other possible formats until it either
  15878.    receives the data or runs out of format choices.
  15879.  
  15880.    If the clipboard contains one of the requested formats, the
  15881.    WinQueryClipbrdData function returns a 32-bit integer, the meaning of
  15882.    which depends on the particular format. For text data, the return value is
  15883.    a selector (in the lower 16 bits of the long integer) to a shareable
  15884.    segment containing the text. For bitmap data, the return value is a bitmap
  15885.    handle. For metafile data, the return value is a metafile handle.
  15886.  
  15887.    Whatever the format, the handle or selector returned is valid only while
  15888.    the clipboard remains open. An application can use the data while the
  15889.    clipboard is open or copy the data to its own memory and use it after the
  15890.    clipboard is closed.
  15891.  
  15892.    It is important that an application close the clipboard as soon as
  15893.    possible so that other applications can access it.
  15894.  
  15895.    The following code fragment shows how to open the clipboard, retrieve data
  15896.    in the requested format, copy the data to a local segment, and close the
  15897.    clipboard:
  15898.  
  15899.    if (WinOpenClipbrd(hab)) {
  15900.       if (hText = WinQueryClipbrdData(hab, CF_TEXT)) {
  15901.  
  15902.          /* Turn the selector into a pointer. */
  15903.  
  15904.          pszClipText = MAKEP((SEL) hText, 0);
  15905.  
  15906.          /* Copy text from the selector segment to a local segment. */
  15907.  
  15908.          while (*pszLocalText++ = *pszClipText++);
  15909.       }
  15910.       WinCloseClipbrd(hab);
  15911.    }
  15912.  
  15913.  26.3.3  Becoming the Clipboard Viewer
  15914.  
  15915.    A window can become a clipboard viewer and display the current contents of
  15916.    the clipboard. The clipboard viewer is informed whenever the clipboard
  15917.    contents change. Typically, the clipboard viewer is a window that can draw
  15918.    the standard clipboard formats. The clipboard viewer is a convenience for
  15919.    the user; it does not have any effect on the data-transaction functions of
  15920.    the clipboard.
  15921.  
  15922.    To create a clipboard viewer, an application calls the WinSetClipbrdViewer
  15923.    function, specifying the window in which the clipboard data will be
  15924.    displayed. This is usually the client window of an application. There can
  15925.    only be one clipboard viewer at any time in the system, so setting a
  15926.    clipboard viewer replaces any previous clipboard viewer. The
  15927.    WinQueryClipbrdViewer function receives the handle to the current
  15928.    clipboard viewer so that the application can reset it when finished with
  15929.    the clipboard viewer.
  15930.  
  15931.    Once a window becomes the clipboard viewer, it receives WM_DRAWCLIPBOARD
  15932.    messages whenever the contents of the clipboard change. The window should
  15933.    respond to these messages by drawing the contents of the clipboard.
  15934.  
  15935.    The clipboard viewer displays all the standard formats and should process
  15936.    CFI_OWNERDISPLAY items by sending the appropriate clipboard message to the
  15937.    clipboard owner.
  15938.  
  15939.    Three special formats exist for of the clipboard viewer: CF_DSPTEXT,
  15940.    CF_DSPBITMAP, and CF_DSPMETAFILE. Applications that write data to the
  15941.    clipboard in private formats should also write the data in one of these
  15942.    formats. These DSP formats should be a representation of the private
  15943.    formats. If the clipboard viewer does not find one of the standard formats
  15944.    (CF_TEXT, CF_BITMAP, or CF_METAFILE), it can search for one of the DSP
  15945.    formats. Display strategies for these formats are the same as for the
  15946.    corresponding standard formats.
  15947.  
  15948.    The following code fragment shows how a sample clipboard viewer responds
  15949.    to the WM_DRAWCLIPBOARD message, drawing text and bitmap data in its
  15950.    window. Note that the code uses the data retrieved from the clipboard
  15951.    before closing the clipboard. An alternate strategy would be to copy the
  15952.    data to a local segment and then close the clipboard. In any case, the
  15953.    original data from the clipboard cannot be used after the clipboard is
  15954.    closed.
  15955.  
  15956.    case WM_DRAWCLIPBOARD:
  15957.        if (!WinOpenClipbrd(hab))
  15958.            return 0L;
  15959.  
  15960.        if (hText = WinQueryClipbrdData(hab, CF_TEXT)) {
  15961.            pszText = MAKEP((SEL) hText, 0);
  15962.  
  15963.            hps = WinGetPS(hwnd);
  15964.            WinQueryWindowRect(hwnd, &rect);
  15965.  
  15966.            WinDrawText(hps,
  15967.                0xFFFF,                      /* null-terminated string  */
  15968.                pszText,                     /* the string              */
  15969.                &rect,                       /* where to put the string */
  15970.                CLR_BLACK,                   /* foreground color        */
  15971.                CLR_WHITE,                   /* background color        */
  15972.                DT_CENTER | DT_VCENTER | DT_ERASERECT);
  15973.            WinValidateRect(hwnd, (PRECTL) NULL, FALSE);
  15974.            WinReleasePS(hps);
  15975.        }
  15976.        else if (hBitmap = WinQueryClipbrdData(hab, CF_BITMAP)) {
  15977.            hps = WinGetPS(hwnd);
  15978.            ptlDest.x = ptlDest.y = 0;
  15979.            WinQueryWindowRect(hwnd, &rect);
  15980.            WinFillRect(hps, &rect, CLR_WHITE);
  15981.            WinDrawBitmap(hps,
  15982.                hBitmap,
  15983.                (PRECTL) NULL,               /* draws entire bitmap     */
  15984.                &ptlDest,                    /* destination             */
  15985.                CLR_BLACK,                   /* foreground color        */
  15986.                CLR_WHITE,                   /* background color        */
  15987.                DBM_NORMAL);                 /* bitmap flags            */
  15988.            WinValidateRect(hwnd, (PRECTL) NULL, FALSE);
  15989.            WinReleasePS(hps);
  15990.        }
  15991.  
  15992.        WinCloseClipbrd(hab);                /* closes the clipboard    */
  15993.        return 0L;
  15994.  
  15995.    The clipboard viewer uses a similar sequence of calls to get clipboard
  15996.    data when responding to a WM_PAINT message.
  15997.  
  15998.    The clipboard viewer is also responsible for sending messages to the
  15999.    clipboard owner when clipboard data has the attribute CFI_OWNERDISPLAY.
  16000.    Typically, an application sets the attribute CFI_OWNERDISPLAY only for
  16001.    private clipboard formats and not for any standard formats. The clipboard
  16002.    viewer must send messages to the clipboard owner when the clipboard owner
  16003.    does not provide a standard clipboard format in addition to its private
  16004.    formats. In this case, the viewer sends messages to the clipboard owner of
  16005.    a CFI_OWNERDISPLAY format to draw, scroll, and resize the clipboard-image
  16006.    data.
  16007.  
  16008.    The clipboard viewer determines the attributes of a particular clipboard
  16009.    format by calling the WinQueryClipbrdFmtInfo function. The identity of the
  16010.    current owner can be found by calling the WinQueryClipbrdOwner function.
  16011.  
  16012.  26.3.4  Becoming the Clipboard Owner
  16013.  
  16014.    The clipboard owner is any application window that is connected to the
  16015.    clipboard data. To become the clipboard owner, an application must call
  16016.    the WinSetClipbrdOwner function. The following are situations in which an
  16017.    application should call the WinSetClipbrdOwner function to become the
  16018.    clipboard owner:
  16019.  
  16020.    ■  The application calling the WinSetClipbrdData function passes a NULL
  16021.       selector or handle to the clipboard, indicating that the application
  16022.       renders the data in a particular format on request. As a result, the
  16023.       system sends rendering requests to the current clipboard owner.
  16024.  
  16025.    ■  The application calling the WinSetClipbrdData function passes data with
  16026.       the attribute CFI_OWNERFREE, indicating that the application frees
  16027.       memory for data when the clipboard is emptied. As a result, the system
  16028.       sends owner-free requests to the current clipboard owner.
  16029.  
  16030.    ■  The application calling the WinSetClipbrdData function passes data with
  16031.       the attribute CFI_OWNERDISPLAY, indicating that the owner application
  16032.       draws the data in the clipboard viewer. As a result, the clipboard
  16033.       viewer sends drawing-related requests to the current clipboard owner.
  16034.  
  16035.    The window specified in the call to the WinSetClipbrdOwner function should
  16036.    respond to the following messages:
  16037.  
  16038. ╓┌─┌───────────────────────┌─────────────────────────────────────────────────╖
  16039.    Message                 Description
  16040.    ──────────────────────────────────────────────────────────────────────────
  16041.    WM_RENDERFMT            Sent by the system to the clipboard owner when a
  16042.                            particular format with delayed rendering must be
  16043.                            rendered. The receiver should render the data in
  16044.                            the specified format and pass it to the clipboard
  16045.                            by calling the WinSetClipbrdData function. For
  16046.    Message                 Description
  16047.    ──────────────────────────────────────────────────────────────────────────
  16048.                           by calling the WinSetClipbrdData function. For
  16049.                            more information, see Section 26.3.6.
  16050.  
  16051.    WM_RENDERALLFMTS        Sent by the system to the clipboard owner just
  16052.                            before the owner application terminates. The
  16053.                            receiver should render the clipboard data in all
  16054.                            formats on the clipboard with delayed rendering.
  16055.                            It should pass the data for each format to the
  16056.                            clipboard by calling the WinSetClipbrdData
  16057.                            function. For more information, see Section
  16058.                            26.3.6.
  16059.  
  16060.    DESTROYCLIPBOARD        Sent by the system to the clipboard owner when the
  16061.                            clipboard is cleared by another application
  16062.                            calling the WinEmptyClipbrd function. The receiver
  16063.                            should free the memory occupied by any clipboard
  16064.                            formats using the attribute CFI_OWNERFREE.
  16065.  
  16066.    WM_SIZECLIPBOARD        Sent by the clipboard viewer to the clipboard
  16067.    Message                 Description
  16068.    ──────────────────────────────────────────────────────────────────────────
  16069.   WM_SIZECLIPBOARD        Sent by the clipboard viewer to the clipboard
  16070.                            owner when the clipboard contains the data handle
  16071.                            with the attribute CFI_OWNERDISPLAY and when the
  16072.                            clipboard-viewer changes size. When the clipboard
  16073.                            viewer is being destroyed or reduced to an icon,
  16074.                            this message is sent with the coordinates of the
  16075.                            opposite corners set to (0,0), which permits the
  16076.                            owner to free its display resources.
  16077.  
  16078.    WM_VSCROLLCLIPBOARD     Sent by the clipboard viewer to the clipboard
  16079.                            owner when the clipboard contains data with the
  16080.                            attribute CFI_OWNERDISPLAY and when an event
  16081.                            occurs in the clipboard-viewer scroll bars. The
  16082.                            receiver should respond to this message by
  16083.                            scrolling the image, invalidating the appropriate
  16084.                            area of the clipboard viewer, and updating the
  16085.                            scroll-bar position.
  16086.  
  16087.    WM_HSCROLLCLIPBOARD     Sent by the clipboard viewer to the clipboard
  16088.    Message                 Description
  16089.    ──────────────────────────────────────────────────────────────────────────
  16090.   WM_HSCROLLCLIPBOARD     Sent by the clipboard viewer to the clipboard
  16091.                            owner when the clipboard contains data with the
  16092.                            attribute CFI_OWNERDISPLAY and when an event
  16093.                            occurs in the scroll bars of the clipboard viewer.
  16094.                            The receiver should respond to this message by
  16095.                            scrolling the image, invalidating the appropriate
  16096.                            area of the clipboard viewer, and updating the
  16097.                            scroll-bar position.
  16098.  
  16099.    WM_PAINTCLIPBOARD       Sent by the clipboard viewer to the clipboard
  16100.                            owner when the clipboard contains data with the
  16101.                            attribute CFI_OWNERDISPLAY and when the
  16102.                            clipboard-viewer client area needs repainting. The
  16103.                            receiver should respond to this message by
  16104.                            painting the requested format (by calling WinGetPS
  16105.                            for the window handle of the clipboard viewer).
  16106.    ──────────────────────────────────────────────────────────────────────────
  16107.  
  16108.  
  16109.    An application automatically loses ownership of the clipboard when the
  16110.    clipboard data is cleared by the WinEmptyClipbrd function. Ownership is
  16111.    necessary only when data is present on the clipboard. Typically, an
  16112.    application loses ownership when another application places data on the
  16113.    clipboard.
  16114.  
  16115.  26.3.5  Custom Clipboard Formats
  16116.  
  16117.    Applications often use custom clipboard formats when standard formats are
  16118.    insufficient for representing clipboard data. For example, a word
  16119.    processor might have a rich-text format that contains font and style
  16120.    information in addition to the usual text characters. Clearly, if the word
  16121.    processor uses the clipboard to support cut, copy, and paste operations
  16122.    for moving data in its documents, a standard text format would be
  16123.    inadequate.
  16124.  
  16125.    Such a word processor should write at least two formats to the clipboard
  16126.    for each cut or copy operation: a standard text format representing the
  16127.    text of the current selection, and a private rich-text format representing
  16128.    the true state of the selection. If the word processor performs a paste
  16129.    operation using clipboard data, it can use the rich-text format to retain
  16130.    all formatting. If another application requests the same data, it can use
  16131.    the standard-text format if it does not recognize the private format. The
  16132.    word processor should also be able to render data in CF_BITMAP and
  16133.    CF_METAFILE formats for painting or drawing applications.
  16134.  
  16135.    26.3.5.1  Assigning a Unique Format ID
  16136.  
  16137.    Each private format must have an identification number when it is written
  16138.    to the clipboard. To obtain a unique ID number for a private clipboard
  16139.    format, the application should register the name of the format in the
  16140.    system atom table. The system assigns a unique ID number for the format
  16141.    name. Other applications that know the format name can query the system
  16142.    atom table for the format ID. An application can interpret its own private
  16143.    formats and can request them from the clipboard for cutting and pasting
  16144.    its own data. Other applications that know the private format ID can also
  16145.    interpret the formatted data. The following code fragment illustrates how
  16146.    an application obtains a unique identification number for a clipboard
  16147.    format. This technique can be used either by the application that creates
  16148.    the format or by another application.
  16149.  
  16150.    hatomtbl = WinQuerySystemAtomTable();
  16151.    formatID = WinAddAtom(hatomtbl, "SuperCAD_Format");
  16152.  
  16153.    26.3.5.2  Display Formats
  16154.  
  16155.    Three standard display formats exist for applications that use private
  16156.    formats: CF_DSPTEXT, CF_DSPBITMAP, and CF_DSPMETAFILE. These three formats
  16157.    correspond to the standard text, bitmap, and metafile formats with the
  16158.    exception that they are intended only for use by the clipboard viewer. An
  16159.    application that uses a private format should write one of the DSP formats
  16160.    that approximates the appearance of the private data so that the clipboard
  16161.    viewer can display the data regardless of the format. For example, a word
  16162.    processor using the rich-text format should also write a CF_DSPBITMAP
  16163.    formatted picture of the selected text that contains all the type fonts
  16164.    and styles. Note that you might choose delayed rendering for DSP formats
  16165.    because there may not always be a clipboard viewer active on the screen.
  16166.    With delayed rendering, an application does not actually render the format
  16167.    unless it is requested to do so.
  16168.  
  16169.  26.3.6  Delayed Rendering
  16170.  
  16171.    An application can pass NULL instead of a selector or a handle, indicating
  16172.    that the data is rendered only when another application requests it from
  16173.    the clipboard. This is useful if an application supports several clipboard
  16174.    formats that are time-consuming to render. With delayed rendering, an
  16175.    application can send NULL handles for each clipboard format that it
  16176.    supports, and render individual formats only when the format is actually
  16177.    requested from the clipboard. An application can either write data for
  16178.    standard formats or choose delayed rendering for more complex formats.
  16179.  
  16180.    When an application uses delayed rendering for one or more of its
  16181.    clipboard formats, it must become the clipboard owner. As long as the
  16182.    application is the clipboard owner, it receives a WM_RENDERFMT message
  16183.    whenever a request is received by the clipboard for a format using delayed
  16184.    rendering. When the application receives such a message, it should render
  16185.    the data and pass the selector or handle to the clipboard by calling the
  16186.    WinSetClipbrdData function. The rules for shared-memory access for
  16187.    rendered data are the same as those for standard clipboard data. This is
  16188.    simply a delayed execution of the operation that occurs if the data does
  16189.    not have delayed rendering.
  16190.  
  16191.    The clipboard owner with one or more delayed-rendering formats on the
  16192.    clipboard receives a WM_RENDERALLFMTS message just before the clipboard
  16193.    owner application terminates. This insures that the application renders
  16194.    all of its data before terminating.
  16195.  
  16196.  
  16197.  26.4  Summary
  16198.  
  16199.    The following sections summarize the standard clipboard data formats, the
  16200.    functions that control the clipboard, and the window messages associated
  16201.    with the clipboard.
  16202.  
  16203.  26.4.1  Standard Clipboard Formats
  16204.  
  16205.    The following are the standard clipboard-data formats used in MS OS/2:
  16206.  
  16207.    CF_BITMAP  The handle returned by the WinQueryClipbrdData function is a
  16208.    bitmap handle.
  16209.  
  16210.    CF_DSPBITMAP  A bitmap representation of a private-data format. The
  16211.    clipboard viewer uses this format to display a private format.
  16212.  
  16213.    CF_DSPMETAFILE  A metafile representation of a private-data format. The
  16214.    clipboard viewer uses this format to display a private format.
  16215.  
  16216.    CF_DSPTEXT  A text representation of a private-data format. The clipboard
  16217.    viewer uses this format to display a private format.
  16218.  
  16219.    CF_METAFILE  The handle returned by the WinQueryClipbrdData function.
  16220.  
  16221.    CF_TEXT  The handle returned by the WinQueryClipbrdData function has a
  16222.    selector (in the low word) to an array of text characters that can include
  16223.    newline characters indicating line breaks. The null character indicates
  16224.    the end of the text data.
  16225.  
  16226.  26.4.2  Clipboard Functions
  16227.  
  16228.    The following are the MS OS/2 functions that control the clipboard:
  16229.  
  16230.    WinCloseClipbrd  Closes the clipboard, allowing other applications to open
  16231.    and use it. This function sends a WM_DRAWCLIPBOARD message, causing the
  16232.    clipboard contents to be drawn in the clipboard viewer (if any). The
  16233.    clipboard must be open before this function is used.
  16234.  
  16235.    WinEmptyClipbrd  Empties the clipboard, removing and freeing all handles
  16236.    to clipboard data.
  16237.  
  16238.    WinEnumClipbrdFmts  Enumerates the available clipboard data formats. The
  16239.    fmtPrev argument specifies the index of the last clipboard-data format
  16240.    enumerated using this function. This index should start at zero, in which
  16241.    case the first available format is obtained. Subsequently, it should be
  16242.    set to the last format index value returned by this function. The return
  16243.    value is the index of the next available clipboard-data format on the
  16244.    clipboard. Enumeration is complete (no further formats are available) when
  16245.    zero is returned.
  16246.  
  16247.    WinOpenClipbrd  Opens the clipboard and prevents other threads and
  16248.    processes from examining or changing the clipboard contents. If another
  16249.    thread or process already has the clipboard open, this function does not
  16250.    return until the clipboard is available. However, it passes messages to
  16251.    the application while it waits for the clipboard.
  16252.  
  16253.    WinQueryClipbrdData  Retrieves data with a specified format from the
  16254.    clipboard. This function returns zero if no data with that format exists
  16255.    on the clipboard.
  16256.  
  16257.    WinQueryClipbrdFmtInfo  Determines whether a particular data format is
  16258.    present on the clipboard. If it is, this function provides information to
  16259.    the caller about that format.
  16260.  
  16261.    WinQueryClipbrdOwner  Returns the current clipboard owner (if any). The
  16262.    fLock argument specifies whether the clipboard-owner window should be
  16263.    locked. If the window is locked, the calling application must unlock the
  16264.    window. This window handle should be locked while being used because it
  16265.    may belong to another process. Locking prevents other processes from
  16266.    destroying the window.
  16267.  
  16268.    WinQueryClipbrdViewer  Returns the current clipboard viewer (if any). The
  16269.    fLock argument specifies whether the clipboard viewer is locked. If the
  16270.    window is locked, the calling application must unlock the window. This
  16271.    window handle should be locked while being used because it may belong to
  16272.    another process. Locking prevents other processes from destroying the
  16273.    window.
  16274.  
  16275.    WinSetClipbrdData  Puts data in a specified format on the clipboard.
  16276.  
  16277.    WinSetClipbrdOwner  Sets the current clipboard owner. An application
  16278.    should become the clipboard owner when it sends delayed-rendering data to
  16279.    the clipboard or when it has data it must draw in the clipboard viewer.
  16280.  
  16281.    WinSetClipbrdViewer  Sets the current clipboard viewer to a specified
  16282.    window. The clipboard viewer receives the WM_DRAWCLIPBOARD message when
  16283.    the clipboard contents change. This allows the clipboard viewer to display
  16284.    an up-to-date version of the clipboard contents. The clipboard must be
  16285.    open before this function is called.
  16286.  
  16287.  26.4.3  Clipboard Messages
  16288.  
  16289.    The following are the window messages used with the clipboard:
  16290.  
  16291.    WM_DESTROYCLIPBOARD  Sent by the system to the clipboard owner when the
  16292.    clipboard is emptied by the WinEmptyClipbrd function. If any of the
  16293.    formats have the CFI_OWNERFREE flag set, the clipboard owner must free the
  16294.    data when it receives the WM_DESTROYCLIPBOARD message.
  16295.  
  16296.    WM_DRAWCLIPBOARD  Sent by the system to the clipboard viewer when the
  16297.    clipboard contents change. The clipboard viewer draws the contents of the
  16298.    clipboard.
  16299.  
  16300.    WM_HSCROLLCLIPBOARD  Sent by the clipboard viewer to the clipboard owner
  16301.    when the clipboard data has the CFI_OWNERDISPLAY attribute and an event
  16302.    occurs in the clipboard-viewer scroll bars. The clipboard owner scrolls
  16303.    the clipboard image, invalidating the appropriate sections, and updates
  16304.    the scroll-bar values.
  16305.  
  16306.    WM_PAINTCLIPBOARD  Sent by the clipboard viewer to the clipboard owner
  16307.    when a clipboard format with the CFI_OWNERDISPLAY flag set must be drawn
  16308.    in the clipboard viewer. The owner receives a window handle for the
  16309.    clipboard viewer and uses it as the destination window for drawing the
  16310.    clipboard data.
  16311.  
  16312.    WM_RENDERALLFMTS  Sent by the system to the clipboard owner when the owner
  16313.    application is being destroyed. The clipboard owner should render all
  16314.    formats that it can generate and pass a handle or selector for each format
  16315.    to the clipboard by calling the WinSetClipbrdData function. This ensures
  16316.    that the clipboard contains valid data even though the application that
  16317.    rendered the data is destroyed.
  16318.  
  16319.    WM_RENDERFMT  Sent by the system to the clipboard owner when clipboard
  16320.    data must be rendered. The receiver of this message renders the data and
  16321.    sends it to the clipboard by calling the WinSetClipbrdData function.
  16322.  
  16323.    WM_SIZECLIPBOARD  Sent by the clipboard viewer to the clipboard owner when
  16324.    the clipboard viewer is resized and contains data with the attribute
  16325.    CFI_OWNERDISPLAY.
  16326.  
  16327.    WM_VSCROLLCLIPBOARD  Same as the WM_HSCROLLCLIPBOARD message.
  16328.  
  16329.  
  16330.  
  16331.  ────────────────────────────────────────────────────────────────────────────
  16332.  Chapter 27  Dynamic Data Exchange
  16333.  
  16334.         27.1    Introduction
  16335.         27.2    About Dynamic Data Exchange
  16336.             27.2.1    Client and Server Interaction
  16337.             27.2.2    Sample DDE Relationship
  16338.         27.3    Using Dynamic Data Exchange
  16339.             27.3.1    Detailed DDE Example
  16340.             27.3.2    DDE Message Contents
  16341.             27.3.3    Unique Data Formats
  16342.             27.3.4    Sample DDE Transactions
  16343.                 27.3.4.1   Initiating an Exchange Between Two Applications
  16344.                 27.3.4.2   Positive WM_DDE_ACK Response
  16345.                 27.3.4.3   Negative WM_DDE_ACK Response
  16346.                 27.3.4.4   One-Time Data Transfer Between Two Applications
  16347.                 27.3.4.5   Permanent Data Link Between Two Applications
  16348.                 27.3.4.6   Executing Commands in a Remote Application
  16349.                 27.3.4.7   Terminating an Exchange Between Two Applications
  16350.             27.3.5    Synchronization Rules
  16351.         27.4    Summary
  16352.             27.4.1    Functions
  16353.             27.4.2    Messages
  16354.             27.4.3    DDE Status Flags
  16355.  
  16356.  27.1  Introduction
  16357.  
  16358.    This chapter describes how to use dynamic data exchange (DDE) messages to
  16359.    transfer data between applications. You should also be familiar with the
  16360.    following topics:
  16361.  
  16362.    ■  Standard user-interface guidelines
  16363.  
  16364.    ■  Window messages and message queues
  16365.  
  16366.    ■  MS OS/2 memory management and shared memory
  16367.  
  16368.    ■  Clipboard data-exchange model
  16369.  
  16370.  
  16371.  27.2  About Dynamic Data Exchange
  16372.  
  16373.    The dynamic data exchange (DDE) protocol is a set of messages and
  16374.    guidelines that allow MS OS/2 Presentation Manager applications to share
  16375.    data freely, using either one-time data transfers or ongoing exchanges, in
  16376.    which applications send updates to one another as new data becomes
  16377.    available.
  16378.  
  16379.    The DDE protocol uses messages for signaling between applications that
  16380.    share data. The DDE protocol uses shared memory as the means of
  16381.    transferring data from application to application. DDE defines some
  16382.    structures to store the shared memory objects.
  16383.  
  16384.    DDE is different from the clipboard data-transfer mechanism that is also
  16385.    part of MS OS/2. One difference is that the clipboard is almost always
  16386.    used as a one-time response to a specific action by the user (such as
  16387.    choosing Paste from a menu). DDE, on the other hand, is often initiated by
  16388.    a user but typically continues without the user's further involvement.
  16389.  
  16390.  27.2.1  Client and Server Interaction
  16391.  
  16392.    DDE transactions always consist of a client application and a server
  16393.    application. The client initiates the exchange by requesting data from the
  16394.    server. The server responds to the data requests by providing data to the
  16395.    client. A server can have many clients at the same time, and a client can
  16396.    request data from multiple servers.
  16397.  
  16398.    An application can be both a client and a server. For instance, an
  16399.    application might receive data from another application as a client, and
  16400.    then act as a server by passing the data to another application.
  16401.  
  16402.    The important distinction between a client and a server is that the client
  16403.    initiates the DDE transaction.
  16404.  
  16405.  27.2.2  Sample DDE Relationship
  16406.  
  16407.    There are many potential uses of DDE in real-time data-acquisition
  16408.    applications. This section discusses an example of one such use: a
  16409.    DDE-based real-time system for tracking portfolios. Two hypothetical
  16410.    Presentation Manager applications cooperate in this example. One
  16411.    application, named "Collector," is a specialized interface that draws data
  16412.    from an on-line data service. The other application is a spreadsheet. Both
  16413.    applications use the DDE protocol. In the described transactions the
  16414.    spreadsheet application is the client──that is, the application that
  16415.    initiates DDE transactions──and the on-line data-collection application is
  16416.    the server.
  16417.  
  16418.    The sample spreadsheet has the following layout:
  16419.  
  16420.               A         B         C         D
  16421.  
  16422.          1    Stock     Shares    Price     Extension
  16423.  
  16424.          2    BTRX      1000      148       148000
  16425.  
  16426.          3    HLOW      2000      26        52000
  16427.  
  16428.          4    WRLD      200       24        4800
  16429.  
  16430.          5    ZMXI      2000      93        186000
  16431.  
  16432.          6                                  390800
  16433.  
  16434.    Without DDE, this spreadsheet could be updated by using the clipboard to
  16435.    manually copy numbers from the screen display of the Collector application
  16436.    into the spreadsheet. This would require screen sharing or switching
  16437.    between applications, and would also require that the user pay attention
  16438.    to the price data and personally undertake the data exchange.
  16439.  
  16440.    With DDE, this system could be much more automatic, providing the
  16441.    spreadsheet with the current values for multiple data items without
  16442.    intervention by the user. DDE would allow the user to set up an exchange
  16443.    between the server and client applications that would keep the spreadsheet
  16444.    up-to-date whenever a change occurred in the value of specified stocks.
  16445.    Once this connection was established, the cell values in the spreadsheet
  16446.    would always reflect the most current data available from the server. This
  16447.    system would facilitate the timely analysis of real-time data.
  16448.  
  16449.    The usefulness of the DDE protocol is not restricted to specialized
  16450.    real-time data-acquisition applications. Productivity software in general
  16451.    can benefit significantly from the protocol. For example, suppose a
  16452.    monthly report is prepared using a graphics-and-text word processor, and
  16453.    that the report includes graphs generated in a separate business-graphics
  16454.    package. Without DDE, it would be necessary to manually copy and paste
  16455.    each month's new graphs into each month's report. With DDE, the word
  16456.    processor can establish a permanent link to the charting application, so
  16457.    that any changes made by the user to the charting document are reflected
  16458.    in the word-processing document, either automatically or on request. This
  16459.    makes the routine of document preparation much simpler for the user.
  16460.  
  16461.  
  16462.  27.3  Using Dynamic Data Exchange
  16463.  
  16464.    A DDE transaction between two applications actually takes place between
  16465.    two windows, one for each of the participating applications. Applications
  16466.    open a window for each conversation they engage in. (Note that such
  16467.    windows are typically not visible.) A window is identified by its handle.
  16468.    The window belonging to the server application is the server window; the
  16469.    window belonging to the client application is the client window.
  16470.  
  16471.    After a conversation has been initiated by the client, the client
  16472.    interacts with the server by issuing transactions. When issuing a
  16473.    transaction, the client requests that the server perform a particular
  16474.    action. There are six types of transactions: request, advise, unadvise,
  16475.    poke, execute, and terminate. These transactions are permitted only within
  16476.    an exchange begun by using the WM_DDE_INITIATE message. DDE transactions
  16477.    are one-way: The client application always issues the transactions. If the
  16478.    server issues a transaction to the client, the server must initiate a new
  16479.    exchange for that purpose. The server becomes the client in this new
  16480.    exchange. (The only exception to the one-way rule is the terminate
  16481.    transaction, which can be issued by either the client or the server.)
  16482.  
  16483.  27.3.1  Detailed DDE Example
  16484.  
  16485.    This section presents a more detailed view of the workings of the DDE
  16486.    protocol. It discusses the example of the Collector and spreadsheet
  16487.    interaction and illustrates forwarding stock quotes from the Collector
  16488.    application to the spreadsheet. For the sake of simplicity, this example
  16489.    will be limited to the exchange of quotes for a single stock, BTRX.
  16490.  
  16491.    The Collector DDE server application is started first. Typically,
  16492.    applications designed to operate as dedicated DDE servers have some user
  16493.    interface for initialization and then run as icons at the bottom of the
  16494.    Presentation Manager screen. As part of the initialization process, the
  16495.    Collector DDE server application goes through whatever steps are necessary
  16496.    (entering passwords, testing, etc.) to ensure that data can be provided to
  16497.    clients.
  16498.  
  16499.    The spreadsheet is started next, and the stock-portfolio document is
  16500.    loaded. At this time, the spreadsheet calls the WinDdeInitiate function,
  16501.    which sends a WM_DDE_INITIATE message to all current top-level frame
  16502.    windows.
  16503.  
  16504.    The WM_DDE_INITIATE message is a request to initiate an exchange with an
  16505.    application on a specified topic──in this case, NYSE. An application can
  16506.    accept this message by responding with a positive WM_DDE_INITIATEACK
  16507.    message, or can decline it by passing the message on to the
  16508.    WinDefWindowProc function. If no application accepts the request, the
  16509.    spreadsheet assigns an error value to the external reference and its DDE
  16510.    activity concludes.
  16511.  
  16512.    If the Collector application acknowledges the request, the spreadsheet can
  16513.    use the newly established exchange to request the Collector application to
  16514.    provide continuous updates on a specified data item. To make this request,
  16515.    the spreadsheet posts a WM_DDE_ADVISE message to the Collector application
  16516.    (actually, to a window within the Collector application that is acting as
  16517.    the message recipient for DDE messages), indicating that updates should be
  16518.    sent every time there is a new value available for the data item named
  16519.    "BTRX," and that the updates should be in a particular format──for
  16520.    example, DDEFMT_TEXT. Upon receiving this message, the Collector
  16521.    application records the request in its database and posts a WM_DDE_ACK
  16522.    message to the spreadsheet. From then on, the Collector application posts
  16523.    a WM_DDE_DATA message to the spreadsheet application (actually, to the
  16524.    window in the spreadsheet that initiated the exchange) whenever it
  16525.    receives a new BTRX stock quote from the server. Each of these messages
  16526.    carries a selector for a shared memory object. The object itself contains
  16527.    the data, rendered in the requested format. Whenever the spreadsheet
  16528.    receives such a message, it retrieves the data from the referenced memory
  16529.    object and uses the data to update the value of the cell containing the
  16530.    external reference.
  16531.  
  16532.    The periodic updates continue until the spreadsheet document is closed. At
  16533.    that point the spreadsheet application posts a WM_DDE_UNADVISE message to
  16534.    the Collector application, indicating that further updating is not
  16535.    necessary. Upon receipt of this message, the Collector application removes
  16536.    the corresponding data request from its database and posts a positive
  16537.    WM_DDE_ACK message back to the spreadsheet.
  16538.  
  16539.    Finally, unless the spreadsheet initiates other data exchanges under this
  16540.    same topic, it posts a WM_DDE_TERMINATE message to the Collector
  16541.    application, indicating the end of the DDE transaction. The Collector
  16542.    application responds with a WM_DDE_TERMINATE message.
  16543.  
  16544.  27.3.2  DDE Message Contents
  16545.  
  16546.    DDE uses the three-level hierarchy──application, topic, and item──to
  16547.    uniquely identify a unit of data. An item is a data object that can be
  16548.    passed in a DDE transaction. For example, an item might be a single
  16549.    integer, a string, several paragraphs of text, or a bitmap. A topic is a
  16550.    logical data context. For applications that operate on file-based
  16551.    documents, topics are usually filenames; for other applications they are
  16552.    other application-specific strings. Using the Collector and spreadsheet
  16553.    model described earlier, the application name is collector, the topic name
  16554.    is NYSE, and the item name is BTRX.
  16555.  
  16556.    There are two data structures used for DDE transactions: the DDEINIT
  16557.    structure and the DDESTRUCT structure. The DDEINIT structure is used for
  16558.    the WM_DDE_INITIATE and WM_DDE_INITIATEACK messages. DDEINIT contains
  16559.    pointers to the application-name and topic-name strings. The DDEINIT
  16560.    structure has the following form:
  16561.  
  16562.    typedef struct _DDEINIT {
  16563.        USHORT cb;
  16564.        PSZ    pszAppName;
  16565.        PSZ    pszTopic;
  16566.    } DDEINIT;
  16567.  
  16568.    An application typically does not need to fill in a DDEINIT structure,
  16569.    since the operating system fills it in automatically when the application
  16570.    calls the WinDdeInitiate or WinDdeRespond function. It is important,
  16571.    however, to understand the organization of the DDEINIT structure when
  16572.    receiving a WM_DDE_INITIATE or WM_DDE_INITIATEACK message, so that you can
  16573.    extract the application name and the topic name. The DDESTRUCT structure
  16574.    is passed with all DDE messages except WM_DDE_INITIATE and
  16575.    WM_DDE_INITIATEACK. It contains a byte count of the data, the format of
  16576.    the data, the item name, a status word, and the data being transferred.
  16577.    The DDESTRUCT structure has the following form:
  16578.  
  16579.    typedef struct _DDESTRUCT {
  16580.        ULONG  cbData;
  16581.        USHORT fsStatus;
  16582.        USHORT usFormat;
  16583.        USHORT offszItemName;
  16584.        USHORT offabData;
  16585.    } DDESTRUCT;
  16586.  
  16587.    The data in a DDE message is contained in a shared memory segment. The
  16588.    sender allocates a segment large enough to hold one of the two data
  16589.    structures described above and the actual data to be transferred, and
  16590.    passes the selector for the memory as part of the message. The layout of a
  16591.    typical DDE segment is shown in Figure 27.1. The first part of the DDE
  16592.    segment is occupied by the DDESTRUCT structure. Next comes the item-name
  16593.    string. Following the name string is the actual data to be transferred.
  16594.    The offset fields of the DDESTRUCT structure must be set to point to the
  16595.    name string and the beginning of the data. The cbData field must also be
  16596.    set to indicate the number of bytes of data.
  16597.  
  16598.    ┌────────────────────────────────────────────────────────────────────────┐
  16599.    │ Figure 27.1 can be found in Section 27.3.2 of the printed manual.      │
  16600.    └────────────────────────────────────────────────────────────────────────┘
  16601.  
  16602.    Figure 27.1  Typical DDE Segment
  16603.  
  16604.    The sender must allocate the segment as SEG_GIVEABLE and call the
  16605.    DosGiveSeg function to share the segment with the receiving application.
  16606.    To share a segment, the sender needs to know the process identifier of the
  16607.    recipient. The process identifier can be obtained by calling the
  16608.    WinQueryWindowProcess function for the recipient's window handle.
  16609.  
  16610.    The sender should call the DosFreeSeg function to free its copy of the
  16611.    segment selector as soon as it has given the shared segment selector to
  16612.    the recipient. The recipient should call DosFreeSeg when it is finished
  16613.    using the segment. The sender should not try to access the segment once it
  16614.    has been sent to the recipient in a DDE message. The following code
  16615.    fragment shows a function that creates a shared segment for a DDE
  16616.    transaction. The function parameters include the destination window for
  16617.    the DDE message, the item name for the transaction, the status word, the
  16618.    format of the data, the actual data to be transferred (if any), and the
  16619.    length of the data. The segment allocated by this function must be big
  16620.    enough to hold the DDESTRUCT structure, the item name, and the actual data
  16621.    to be transferred. The function returns a pointer (PDDESTRUCT) to a shared
  16622.    segment that is ready to post as part of a DDE message.
  16623.  
  16624.    PDDESTRUCT MakeDDESegment(hwndDest, pszItemName, fsStatus, usFormat,
  16625.        pabData, usDataLen)
  16626.    HWND   hwndDest;
  16627.    PSZ    pszItemName;
  16628.    USHORT fsStatus;
  16629.    USHORT usFormat;
  16630.    PVOID  pabData;
  16631.    USHORT usDataLen;
  16632.  
  16633.    {
  16634.        PDDESTRUCT pddes;            /* pointer to DDESTRUCT        */
  16635.        USHORT     usItemLen;        /* length of item name         */
  16636.        USHORT     usTotalLen;       /* total length of segment     */
  16637.        SEL        selBuf;           /* local selector for segment  */
  16638.        SEL        selShared;        /* shared selector for segment */
  16639.        USHORT     receiverPID;      /* process ID of server        */
  16640.        USHORT     receiverTID;      /* thread ID of server         */
  16641.  
  16642.        usItemLen = FarStrLen(pszItemName) + 1;
  16643.  
  16644.        usTotalLen = sizeof(DDESTRUCT) + usItemLen + usDataLen;
  16645.  
  16646.        if (! DosAllocSeg(usTotalLen, &selBuf, SEG_GIVEABLE)) {
  16647.  
  16648.            /* Initialize DDESTRUCT. */
  16649.  
  16650.            pddes = SELTOPDDES(selBuf);
  16651.            pddes->cbData = usTotalLen;
  16652.            pddes->fsStatus = fsStatus;
  16653.            pddes->usFormat = usFormat;
  16654.            pddes->offszItemName = sizeof(DDESTRUCT);
  16655.            if ((usDataLen) && (pabData))
  16656.                pddes->offabData = sizeof(DDESTRUCT) + usItemLen;
  16657.            else
  16658.                pddes->offabData = 0;
  16659.  
  16660.            /* Copy item name immediately following DDESTRUCT. */
  16661.  
  16662.            FarStrCopy(DDES_PSZITEMNAME(pddes), pszItemName);
  16663.  
  16664.            /* Copy data immediately following item name. */
  16665.  
  16666.            FarStructCopy(DDES_PABDATA(pddes), pabData, usDataLen);
  16667.  
  16668.            /* Get process identifier of server. */
  16669.  
  16670.            WinQueryWindowProcess(hwndDest, &receiverPID, &receiverTID);
  16671.  
  16672.            /* Give the segment away. */
  16673.  
  16674.            if (!DosGiveSeg(selBuf, receiverPID, &selShared)) {
  16675.                pddes = SELTOPDDES(selShared);
  16676.                return (pddes);
  16677.            }
  16678.        }
  16679.  
  16680.        /* Else could not allocate or share segment. */
  16681.  
  16682.        return (NULL);
  16683.    }
  16684.  
  16685.    This function is used in many examples in the following sections to
  16686.    demonstrate the creation of DDE shared segments. You may want to define a
  16687.    similar function in your own programs as well.
  16688.  
  16689.  27.3.3  Unique Data Formats
  16690.  
  16691.    Whenever you exchange data by using the DDE protocols you must specify the
  16692.    format of the data in the usFormat field of the DDESTRUCT structure. The
  16693.    system-defined standard format is DDEFMT_TEXT, which indicates text data.
  16694.  
  16695.    Applications can define their own data formats. Each nonstandard DDE
  16696.    format must have a unique identification number. The application should
  16697.    register the name of the format in the system atom table, receiving an
  16698.    identification number for that format name. Other applications that have
  16699.    the name of the format can also query the system atom table for the
  16700.    format's identification number. This method ensures that all applications
  16701.    use the same atom to identify a format.
  16702.  
  16703.    The following code fragment shows how an application can obtain a unique
  16704.    identification number for a DDE format. This technique can be used by the
  16705.    application that creates the format and by an application that is able to
  16706.    use the format.
  16707.  
  16708.    hatomtbl = WinQuerySystemAtomTable();
  16709.    formatID = WinAddAtom(hatomtbl, "SuperCAD_Format");
  16710.  
  16711.  27.3.4  Sample DDE Transactions
  16712.  
  16713.    This section discusses beginning and ending a DDE transaction and the five
  16714.    basic types of interchange supported by DDE. Each of the following
  16715.    subsections provides a detailed description of the message protocols that
  16716.    are associated with the transactions it discusses.
  16717.  
  16718.    27.3.4.1  Initiating an Exchange Between Two Applications
  16719.  
  16720.    To initiate a DDE transaction, the client calls the WinDdeInitiate
  16721.    function, specifying the server application-name and topic-name strings.
  16722.    This function sends a WM_DDE_INITIATE message to all frame windows whose
  16723.    parent is HWND_DESKTOP. Because the message is sent rather than posted,
  16724.    WinDdeInitiate requires all of the message's recipients to respond to the
  16725.    message before control is returned. Either the application name or the
  16726.    topic name can be a null string, in which case the server ignores that
  16727.    name. For example, a client could send a valid application name with a
  16728.    null topic name to request an exchange on all available topics for that
  16729.    application.
  16730.  
  16731.    The server applications that respond to the WM_DDE_INITIATE message will
  16732.    call the WinDdeRespond function, as shown in the following pseudocode:
  16733.  
  16734.    If ((specific app requested and server is instance of app) or
  16735.        (specific app not requested){
  16736.  
  16737.         If (specific topic requested)
  16738.              If (server can support topic)
  16739.  
  16740.                   acknowledge the requested topic
  16741.  
  16742.         Else
  16743.              acknowledge each supported topic
  16744.    }
  16745.  
  16746.    To acknowledge a specific topic, the server responds with the following
  16747.    code fragment:
  16748.  
  16749.    WinDdeRespond(hwndClient, hwndServer, pszAppName, pszTopicName);
  16750.  
  16751.    To acknowledge more than one topic, the server makes one such response for
  16752.    each topic. This initiates an exchange on each topic. The client should
  16753.    post a WM_DDE_TERMINATE message for all unneeded transactions.
  16754.  
  16755.    The System Topic
  16756.  
  16757.    Applications are encouraged to support the "System" topic at all times.
  16758.    This topic provides a context for information that may be of general
  16759.    interest to any partners in a DDE transaction. DDE applications should
  16760.    request an exchange on the System topic with a NULL application name when
  16761.    they start up, to find out what kinds of information other DDE-capable
  16762.    programs can provide.
  16763.  
  16764.    The System topic should support the following terms, as well as any other
  16765.    items the application may use:
  16766.  
  16767.    Item            Description
  16768.    ──────────────────────────────────────────────────────────────────────────
  16769.    SysItems        A list of the items supported under the System topic by
  16770.                    this application.
  16771.  
  16772.    Topics          A list of the topics supported by the application at the
  16773.                    current time (this may vary from moment to moment).
  16774.  
  16775.    ReturnMessage   Supporting detail for the most recently issued WM_DDE_ACK
  16776.                    message. (This is useful when more than eight bits of
  16777.                    application-specific return code are required.)
  16778.  
  16779.    Status          An indication of the current status of the application.
  16780.  
  16781.    Formats         A list of DDE format numbers that the application can
  16782.                    render.
  16783.    ──────────────────────────────────────────────────────────────────────────
  16784.  
  16785.    Individual elements of lists should be delimited by tabs (the DDEFMT_TEXT
  16786.    format).
  16787.  
  16788.    27.3.4.2  Positive WM_DDE_ACK Response
  16789.  
  16790.    A client or server often must positively acknowledge a DDE message that it
  16791.    receives by posting a WM_DDE_ACK message with the DDE_FRESPONSE flag set
  16792.    in the status word of the DDESTRUCT structure. Sending a positive
  16793.    WM_DDE_ACK message means that the sender will respond to the previous
  16794.    message. The following code fragment is an example of a positive
  16795.    acknowledgment message:
  16796.  
  16797.    pddeStruct = MakeDDESegment(hwndDest,   /* handle of destination  */
  16798.        "BTRX",                             /* item name              */
  16799.        DDE_FACKREQ,                        /* status flags           */
  16800.        DDEFMT_TEXT,                        /* data format            */
  16801.        NULL,                               /* no data for request    */
  16802.        0);                                 /* data length            */
  16803.  
  16804.    WinDdePostMsg(hwndDest,                 /* handle of destination  */
  16805.        hwndSource,                         /* handle of source       */
  16806.        WM_DDE_ACK,                         /* message                */
  16807.        pddeStruct,                         /* shared-segment pointer */
  16808.        1);                                 /* retry                  */
  16809.  
  16810.    27.3.4.3  Negative WM_DDE_ACK Response
  16811.  
  16812.    When an application receives a DDE message that it cannot respond to (such
  16813.    as a request for data in a format that it does not support), the
  16814.    application must post a WM_DDE_ACK message with the DDE_NOTPROCESSED flag
  16815.    set in the status word of the DDESTRUCT structure. The following code
  16816.    fragment is an example of a negative acknowledgment message:
  16817.  
  16818.    pddeStruct = MakeDDESegment(hwndDest,   /* handle of destination  */
  16819.        "BTRX",                             /* item name              */
  16820.        DDE_NOTPROCESSED,                   /* status flags           */
  16821.        DDEFMT_TEXT,                        /* data format            */
  16822.        NULL,                               /* no data for request    */
  16823.        0);                                 /* data length            */
  16824.  
  16825.    WinDdePostMsg(hwndDest,                 /* handle of destination  */
  16826.        hwndSource,                         /* handle of source       */
  16827.        WM_DDE_ACK,                         /* message                */
  16828.        pddeStruct,                         /* shared-segment pointer */
  16829.        1);                                 /* retry                  */
  16830.  
  16831.    If an application is busy when it receives a DDE message, it can post a
  16832.    WM_DDE_ACK message with the DDE_FBUSY flag set.
  16833.  
  16834.    27.3.4.4  One-Time Data Transfer Between Two Applications
  16835.  
  16836.    A client application can use the DDE protocol to obtain a data item from a
  16837.    server (WM_DDE_REQUEST), or to submit a data item to a server
  16838.    (WM_DDE_POKE). In either case, the client must have already initiated an
  16839.    exchange with the server, as described earlier.
  16840.  
  16841.    The client posts a WM_DDE_REQUEST message to the server, specifying an
  16842.    item and format by allocating a shared segment and filling in a DDESTRUCT
  16843.    structure and passing the structure to the WinDdePostMsg function. For
  16844.    example, if a DDE exchange has been started on the NYSE topic, the client
  16845.    could request data for the BTRX item by using the following code fragment.
  16846.    (For an example of how to allocate and initialize a shared memory segment,
  16847.    see Section 27.3.2.)
  16848.  
  16849.    pddeStruct = MakeDDESegment(hwndServer, /* handle of server       */
  16850.        "BTRX",                             /* item name              */
  16851.        0,                                  /* status flags           */
  16852.        DDEFMT_TEXT,                        /* data format            */
  16853.        NULL,                               /* no data for request    */
  16854.        0);                                 /* data length            */
  16855.  
  16856.    WinDdePostMsg(hwndServer,               /* handle of server       */
  16857.        hwndClient,                         /* handle of client       */
  16858.        WM_DDE_REQUEST,                     /* message                */
  16859.        pddeStruct,                         /* shared-segment pointer */
  16860.        1);                                 /* retry                  */
  16861.  
  16862.    If the server is unable to satisfy the request, it sends the client a
  16863.    negative WM_DDE_ACK message. If the server can satisfy the request, it
  16864.    renders the item in the requested format and includes it with a DDESTRUCT
  16865.    structure in a shared memory object and posts a WM_DDE_DATA message to the
  16866.    client, as shown in the following code fragment:
  16867.  
  16868.    pddeStruct = MakeDDESegment(hwndClient, /* handle of client       */
  16869.        "BTRX",                             /* item name              */
  16870.        0,                                  /* status flags           */
  16871.        DDEFMT_TEXT,                        /* data format            */
  16872.        pabData,                            /* pointer to data        */
  16873.        usDataLen);                         /* data length            */
  16874.  
  16875.    WinDdePostMsg(hwndClient,               /* handle of client       */
  16876.        hwndServer,                         /* handle of server       */
  16877.        WM_DDE_DATA,                        /* message                */
  16878.        pddeStruct,                         /* shared-segment pointer */
  16879.        1);                                 /* retry                  */
  16880.  
  16881.    Upon receiving a WM_DDE_DATA message, the client processes the data item.
  16882.    The DDESTRUCT structure at the beginning of the shareable segment contains
  16883.    a status word indicating whether the sender has requested an
  16884.    acknowledgment message. If the DDE_FACKREQ bit of the status word is set,
  16885.    the client should send the server a positive WM_DDE_ACK message.
  16886.  
  16887.    Upon receiving a negative WM_DDE_ACK message, the client can ask for the
  16888.    same item again, specifying a different DDE format. Typically, a client
  16889.    will first ask for the most complex format it can support, then step down,
  16890.    if necessary, through progressively simpler formats until it finds one the
  16891.    server can provide.
  16892.  
  16893.    27.3.4.5  Permanent Data Link Between Two Applications
  16894.  
  16895.    A client application can use DDE to establish a link to an item in a
  16896.    server application. When such a link is established, the server sends
  16897.    periodic updates about the linked item to the client (typically, whenever
  16898.    the data that is associated with the item in the server application has
  16899.    changed). A permanent "data stream" is established between the two
  16900.    applications and remains in place until it is explicitly disconnected.
  16901.  
  16902.    The client sends the server a WM_DDE_ADVISE message to set up the data
  16903.    link. (Of course, the client must have first initiated an exchange by
  16904.    using the WM_DDE_INITIATE message, as described previously.) The advise
  16905.    message contains a shared-memory pointer containing a DDESTRUCT structure
  16906.    with the item name, format information, and status information, as shown
  16907.    in the following code fragment:
  16908.  
  16909.    pddeStruct = MakeDDESegment(hwndServer, /* handle of server       */
  16910.        "BTRX",                             /* item name              */
  16911.        DDE_FACKREQ,                        /* status flags           */
  16912.        DDEFMT_TEXT,                        /* data format            */
  16913.        NULL,                               /* no data for advise     */
  16914.        0);                                 /* data length            */
  16915.  
  16916.    WinDdePostMsg(hwndServer,               /* handle of server       */
  16917.        hwndClient,                         /* handle of client       */
  16918.        WM_DDE_ADVISE,                      /* message                */
  16919.        pddeStruct,                         /* shared-segment pointer */
  16920.        1);                                 /* retry                  */
  16921.  
  16922.    If the server has access to the requested item and can render it in the
  16923.    desired format, the server records the new link and then sends the client
  16924.    a positive WM_DDE_ACK message. Until the client issues a WM_DDE_UNADVISE
  16925.    message, the server sends data messages to the client every time the
  16926.    source data changes that is associated with the item in the server
  16927.    application.
  16928.  
  16929.    If the server is unable to satisfy the request, it sends the client a
  16930.    negative WM_DDE_ACK message.
  16931.  
  16932.    When a link is established with the DDE_FNODATA status bit cleared, the
  16933.    client is sent the data each time the data changes. In such cases, the
  16934.    server renders the new version of the item in the previously specified
  16935.    format and posts a WM_DDE_DATA message to the client, as shown in Section
  16936.    27.3.4.4.
  16937.  
  16938.    When the client receives a WM_DDE_DATA message, it extracts data from the
  16939.    shared memory segment by using the DDESTRUCT structure at the beginning of
  16940.    the segment. If the DDE_FACK status bit is set in the status word of the
  16941.    DDESTRUCT structure, the client must post a positive WM_DDE_ACK message to
  16942.    the server.
  16943.  
  16944.    When a link is established with the DDE_FNODATA status flag set, a
  16945.    notification, not the data itself, is posted to the client each time the
  16946.    data changes. In this case, the server does not render the new version of
  16947.    the item when the source data changes, but simply posts a WM_DDE_DATA
  16948.    message with zero bytes of data and the DDE_FNODATA status flag set, as
  16949.    shown in the following code fragment:
  16950.  
  16951.    pddeStruct = MakeDDESegment(hwndClient, /* handle of client       */
  16952.        "BTRX",                             /* item name              */
  16953.        DDE_FNODATA,                        /* status flags           */
  16954.        DDEFMT_TEXT,                        /* data format            */
  16955.        NULL,                               /* no data                */
  16956.        0);                                 /* data length            */
  16957.  
  16958.    WinDdePostMsg(hwndClient,               /* handle of client       */
  16959.        hwndServer,                         /* handle of server       */
  16960.        WM_DDE_DATA,                        /* message                */
  16961.        pddeStruct,                         /* shared-segment pointer */
  16962.        1);                                 /* retry                  */
  16963.  
  16964.    The client can request the latest version of the data by performing a
  16965.    regular one-time WM_DDE_REQUEST transaction, or it can simply ignore the
  16966.    data-change notice from the server. In either case, if the DDE_FACK status
  16967.    bit is set, the client should send a positive WM_DDE_ACK message to the
  16968.    server.
  16969.  
  16970.    To terminate a specific item link, the client posts a WM_DDE_UNADVISE
  16971.    message to the server, as shown in the following code fragment:
  16972.  
  16973.    pddeStruct = MakeDDESegment(hwndServer, /* handle of server       */
  16974.        "BTRX",                             /* item name              */
  16975.        DDE_FACKREQ,                        /* status flags           */
  16976.        DDEFMT_TEXT,                        /* data format            */
  16977.        NULL,                               /* no data for unadvise   */
  16978.        0);                                 /* data length            */
  16979.  
  16980.    WinDdePostMsg(hwndServer,               /* handle of server       */
  16981.        hwndClient,                         /* handle of client       */
  16982.        WM_DDE_UNADVISE,                    /* message                */
  16983.        pddeStruct,                         /* shared-segment pointer */
  16984.        1);                                 /* retry                  */
  16985.  
  16986.    The server checks that the client currently has a link to the specified
  16987.    item in this exchange. If the link exists, the server sends a positive
  16988.    WM_DDE_ACK message to the client and no longer sends updates on the item
  16989.    in this exchange. If the server has no such link, it sends a negative
  16990.    WM_DDE_ACK message.
  16991.  
  16992.    To terminate all links for a particular exchange, the client application
  16993.    posts a WM_DDE_UNADVISE message with a null item name to the server. The
  16994.    server checks that the exchange has at least one link currently
  16995.    established. If so, the server posts a positive WM_DDE_ACK message to the
  16996.    client, and no longer sends any updates in the exchange. If the server has
  16997.    no links in the exchange, it posts a negative WM_DDE_ACK message.
  16998.  
  16999.    27.3.4.6  Executing Commands in a Remote Application
  17000.  
  17001.    A Presentation Manager application can use the DDE protocol to cause a
  17002.    command or series of commands to be executed in another application. Such
  17003.    remote executions are performed by means of the WM_DDE_EXECUTE
  17004.    transaction.
  17005.  
  17006.    To execute a remote command, the client application posts to the server a
  17007.    WM_DDE_EXECUTE message containing a selector for a shared-memory object
  17008.    that contains a DDESTRUCT structure and a command string, as shown in the
  17009.    following code fragment:
  17010.  
  17011.    pddeStruct = MakeDDESegment(hwndServer,   /* handle of server     */
  17012.        "BTRX",                          /* item name                 */
  17013.        DDE_FACKREQ,                     /* status flags              */
  17014.        DDEFMT_TEXT,                     /* data format               */
  17015.        pabData,                         /* pointer to command string */
  17016.        usDataLen);                      /* data length               */
  17017.  
  17018.    WinDdePostMsg(hwndServer,            /* handle of server          */
  17019.        hwndClient,                      /* handle of client          */
  17020.        WM_DDE_EXECUTE,                  /* message                   */
  17021.        pddeStruct,                      /* shared-segment pointer    */
  17022.        1);                              /* retry                     */
  17023.  
  17024.    The server attempts to execute the specified string according to some
  17025.    agreed-upon protocol. If successful, the server posts a positive
  17026.    WM_DDE_ACK message to the client; if unsuccessful, a negative WM_DDE_ACK
  17027.    message is posted.
  17028.  
  17029.    27.3.4.7  Terminating an Exchange Between Two Applications
  17030.  
  17031.    At any time, either the client or the server may terminate an exchange by
  17032.    using the following procedure to issue a WM_DDE_TERMINATE message.
  17033.    Similarly, both the client application and server application should be
  17034.    able to receive a WM_DDE_TERMINATE message at any time.
  17035.  
  17036.    An application must end its exchanges before terminating. The application
  17037.    posts a WM_DDE_TERMINATE message with a NULL shared-segment pointer, as
  17038.    shown in the following code fragment. A WM_DDE_TERMINATE message stops all
  17039.    transactions for a given exchange.
  17040.  
  17041.    WinDdePostMsg(hwndDest,      /* handle of destination     */
  17042.        hwndSource,              /* handle of source          */
  17043.        WM_DDE_TERMINATE,        /* message                   */
  17044.        NULL,                    /* no shared-segment pointer */
  17045.        1);                      /* retry                     */
  17046.  
  17047.    The WM_DDE_TERMINATE message means that the sender will send no further
  17048.    messages in that exchange and that the recipient may destroy its DDE
  17049.    window. The recipient must always send a WM_DDE_TERMINATE message promptly
  17050.    in response; it is not permissible to send a negative, busy, or positive
  17051.    WM_DDE_ACK message instead.
  17052.  
  17053.    If the sender of the original termination request receives any other
  17054.    message before the WM_DDE_TERMINATE message arrives from the recipient of
  17055.    the request, no response should be sent to this other message; the sender
  17056.    of the other message may already have destroyed the window to which the
  17057.    response would be sent.
  17058.  
  17059.  27.3.5  Synchronization Rules
  17060.  
  17061.    A window processing DDE requests from another window must process them
  17062.    strictly in the order in which the requests were received.
  17063.  
  17064.    A window does not need to apply this first-in, first-out rule between
  17065.    requests from different windows──that is, it may provide asynchronous
  17066.    support for multiple processes. For example, a window might have the
  17067.    following requests in its queue:
  17068.  
  17069.    ■  1: Request Message from window x
  17070.  
  17071.    ■  2: Request Message from window y
  17072.  
  17073.    ■  3: Request Message from window x
  17074.  
  17075.    The window must process request 1 before 3, but it does not need to
  17076.    process 2 before 3. If y has a lower priority than x, the window follows
  17077.    the order 1, 3, 2.
  17078.  
  17079.    If a server is unable to process an incoming request because it is waiting
  17080.    for an external process, it must post a busy WM_DDE_ACK message to the
  17081.    client, to prevent deadlock. A busy WM_DDE_ACK message can also be sent if
  17082.    the server is unable to process an incoming request quickly.
  17083.  
  17084.  
  17085.  27.4  Summary
  17086.  
  17087.    This section describes the functions, messages, and status flags
  17088.    associated with the DDE protocol.
  17089.  
  17090.  27.4.1  Functions
  17091.  
  17092.    Three functions simplify the use of DDE messages:
  17093.  
  17094.    WinDdeInitiate  Sends a WM_DDE_INITIATE message containing the specified
  17095.    application name and topic name to all top-level frame windows in the
  17096.    system.
  17097.  
  17098.    WinDdePostMsg  Posts a DDE message to the specified recipient window.
  17099.  
  17100.    WinDdeRespond  Sends a WM_DDE_INITIATEACK message in response to a
  17101.    WM_DDE_INITIATE message.
  17102.  
  17103.  27.4.2  Messages
  17104.  
  17105.    The predefined DDE messages are summarized below:
  17106.  
  17107.    WM_DDE_ACK  Sent as acknowledgment to many DDE messages.
  17108.  
  17109.    WM_DDE_ADVISE  Sent from the client to the server, requesting the server
  17110.    to provide a data update whenever the specified data item changes.
  17111.  
  17112.    WM_DDE_DATA  Sent from the server to the client to notify the client that
  17113.    the data is available.
  17114.  
  17115.    WM_DDE_EXECUTE  Sent from the client to the server, containing a text
  17116.    string that the server should execute as a command or series of commands.
  17117.  
  17118.    WM_DDE_INITIATE  Sent by a client application to initiate an exchange with
  17119.    one or more server applications. This message is often sent to all current
  17120.    applications by calling the WinBroadcastMsg function.
  17121.  
  17122.    WM_DDE_INITIATEACK  Sent by a server application as a positive response to
  17123.    a WM_DDE_INITIATE message. This message specifies the server application
  17124.    name and the topic on which the server will open a DDE transaction.
  17125.  
  17126.    WM_DDE_POKE  Sent as an unsolicited data message for the recipient, which
  17127.    should reply with a WM_DDE_ACK message to indicate whether or
  17128.    not it accepted the data.
  17129.  
  17130.    WM_DDE_REQUEST  Sent from the client to the server to request that a data
  17131.    item be sent to the client.
  17132.  
  17133.    WM_DDE_TERMINATE  Sent by either the client or the server to terminate the
  17134.    exchange.
  17135.  
  17136.    WM_DDE_UNADVISE  Sent from the client to the server to indicate that the
  17137.    specified item should no longer be updated. This message requests the
  17138.    server to remove the link to the data item set up by the WM_DDE_ADVISE
  17139.    message.
  17140.  
  17141.  27.4.3  DDE Status Flags
  17142.  
  17143.    The following constant values control various aspects of a DDE
  17144.    transaction. They can be combined in the fsStatus word of the DDESTRUCT
  17145.    structure by using the OR operator.
  17146.  
  17147.    DDE_FACK  Set for positive acknowledgment.
  17148.  
  17149.    DDE_FACKREQ  Set to acknowledge DDE messages for the application.
  17150.  
  17151.    DDE_FAPPSTATUS  Upper eight bits of status word are reserved for the
  17152.    application-specific data.
  17153.  
  17154.    DDE_FBUSY  Set if application is busy.
  17155.  
  17156.    DDE_FNODATA  Set if there is no data transfer for the WM_DDE_ADVISE
  17157.    message.
  17158.  
  17159.    DDE_FRESERVED  Reserved; must be zero.
  17160.  
  17161.    DDE_FRESPONSE  Set if there is a response to a WM_DDE_REQUEST message.
  17162.  
  17163.    DDE_NOTPROCESSED  Set if the message is not supported.
  17164.  
  17165.  
  17166.  
  17167.  ────────────────────────────────────────────────────────────────────────────
  17168.  Chapter 28  Hooks
  17169.  
  17170.         28.1    Introduction
  17171.         28.2    About Hooks
  17172.         28.3    Types of Hooks
  17173.             28.3.1    Input Hook
  17174.             28.3.2    Send-Message Hook
  17175.             28.3.3    Message-Filter Hook
  17176.             28.3.4    Journal-Record Hook
  17177.             28.3.5    Journal-Playback Hook
  17178.             28.3.6    Help Hook
  17179.         28.4    Using Hooks
  17180.         28.5    Hook Example
  17181.             28.5.1    Installing a System Hook
  17182.             28.5.2    System-Hook Code
  17183.         28.6    Summary
  17184.             28.6.1    Functions
  17185.             28.6.2    Hook Types
  17186.  
  17187.  28.1  Introduction
  17188.  
  17189.    This chapter describes how to use hooks in your applications. You should
  17190.    also be familiar with the following topics:
  17191.  
  17192.    ■  Standard user-interface guidelines
  17193.  
  17194.    ■  Window messages and message queues
  17195.  
  17196.    ■  Focus window and input guidelines
  17197.  
  17198.  
  17199.  28.2  About Hooks
  17200.  
  17201.    MS OS/2 is based on a message-passing model. The behavior of most programs
  17202.    depends on the messages that the program receives. Messages can be
  17203.    generated by input devices, such as the keyboard and mouse, or they can
  17204.    originate within the system as a way of managing and communicating between
  17205.    system resources.
  17206.  
  17207.    MS OS/2 provides hooks to allow applications to monitor and modify the
  17208.    message stream. Hooks can be installed in either the system queue, so that
  17209.    they affect all applications, or in an individual thread's message queue,
  17210.    so that only messages for that queue are affected.
  17211.  
  17212.    Because many applications may install hooks at the same time, most hooks
  17213.    are arranged in chains. The system passes a message to the first hook in
  17214.    the chain, and then to the next hook in the chain, and so on until the
  17215.    message is delivered to the destination application. Each hook may modify
  17216.    the message or stop its progress through the chain, preventing it from
  17217.    reaching the application. Hooks in a chain are called in last-installed,
  17218.    first-called order.
  17219.  
  17220.  
  17221.  28.3  Types of Hooks
  17222.  
  17223.    There are six different types of hooks. You can install the different
  17224.    types of hooks in any combination, although some of the hook types can be
  17225.    installed only in the system queue.
  17226.  
  17227.    The following sections describe the available types of hooks. Each type of
  17228.    hook is expressed as a function with a unique syntax.
  17229.  
  17230.  28.3.1  Input Hook
  17231.  
  17232.    This hook monitors the input queue and is called whenever a message is
  17233.    about to be returned by the WinGetMsg or WinPeekMsg function. Typically,
  17234.    the input hook is used to monitor mouse and keyboard input and other
  17235.    messages that are posted to a queue.
  17236.  
  17237.    The syntax for the input hook is as follows:
  17238.  
  17239.      BOOL CALLBACK InputHook(HAB hab, PQMSG pQmsg, USHORT fs)
  17240.  
  17241.    The pQmsg parameter is a far pointer to a QMSG structure that contains
  17242.    information about the message. The QMSG structure has the following form:
  17243.  
  17244.    typedef struct _QMSG {
  17245.        HWND   hwnd;
  17246.        USHORT msg;
  17247.        MPARAM mp1;
  17248.        MPARAM mp2;
  17249.        ULONG  time;
  17250.        POINTL ptl;
  17251.    } QMSG;
  17252.  
  17253.    The fs parameter of the InputHook function can contain the following flags
  17254.    from the WinPeekMsg function, indicating whether or not the message is
  17255.    removed from the queue:
  17256.  
  17257.          PM_NOREMOVE
  17258.          PM_REMOVE
  17259.  
  17260.    If this hook function returns TRUE, the message is not passed to the rest
  17261.    of the hook chain or to the application──effectively ending the message.
  17262.    If the function returns FALSE, the message is passed to the next hook in
  17263.    the chain, or to the application if no other hooks exist.
  17264.  
  17265.    The input hook can modify a message by changing the contents of the QMSG
  17266.    structure, then return FALSE to pass the modified message to the rest of
  17267.    the chain. The following problems may occur when a hook modifies a
  17268.    message:
  17269.  
  17270.    ■  If the caller uses the WinPeekMsg or WinGetMsg function with a message
  17271.       filter range (msgFilterFirst through msgFilterLast), the message is
  17272.       checked before the hooks are called, not after the hooks are called.
  17273.       This means the caller may receive messages that are not in the range of
  17274.       the caller's message filter.
  17275.  
  17276.    ■  If the hook changes a WM_CHAR message from one character into
  17277.       another──for example, if the hook modifies all TAB messages into F6
  17278.       messages──a program that depends on the key state will be unable to
  17279.       interpret the result. (When the TAB key is translated into the F6 key,
  17280.       the application receives the F6 keystroke and enters a process loop,
  17281.       waiting for the F6 key to be released; the application calls the
  17282.       WinGetKeyState function with the HWND_DESKTOP and VK_F6 arguments).
  17283.  
  17284.  28.3.2  Send-Message Hook
  17285.  
  17286.    This hook is called whenever a message is sent by using the WinSendMsg
  17287.    function. The hook chain is called before the message is delivered to the
  17288.    recipient window. Typically, the send-message hook is used to monitor
  17289.    messages that are not posted to a queue. By installing an input hook and a
  17290.    send-message hook, you can effectively monitor all window messages.
  17291.  
  17292.    The syntax for the send-message hook is as follows:
  17293.  
  17294.      VOID CALLBACK SendMsgHook(HAB hab, PSMHSTRUCT psmh,
  17295.          BOOL fInterTask)
  17296.  
  17297.    The psmh parameter is a far pointer to an SMHSTRUCT structure that
  17298.    contains information about the message. The SMHSTRUCT structure has the
  17299.    following form:
  17300.  
  17301.    typedef struct _SMHSTRUCT {
  17302.        MPARAM mp2;
  17303.        MPARAM mp1;
  17304.        USHORT msg;
  17305.        HWND   hwnd;
  17306.    } SMHSTRUCT;
  17307.  
  17308.    The fInterTask parameter of the SendMsgHook function is TRUE if the
  17309.    message is sent between two threads, or FALSE if the message is sent
  17310.    within a thread.
  17311.  
  17312.    The send-message hook does not return a value, and the next hook in the
  17313.    chain is always called. This hook can modify values in the SMHSTRUCT
  17314.    structure before returning.
  17315.  
  17316.  28.3.3  Message-Filter Hook
  17317.  
  17318.    This hook is called during system modal loops, which include tracking the
  17319.    window size and window movement, displaying a dialog box or message box,
  17320.    scroll-bar tracking, menu-selection tracking, and window-enumeration
  17321.    operations. The message-filter hook is typically used to provide
  17322.    input-message filtering (such as monitoring hot keys) during modal dialog
  17323.    processing.
  17324.  
  17325.    The syntax of the message-filter hook is as follows:
  17326.  
  17327.      BOOL CALLBACK MsgFilterHook(HAB hab, USHORT msgf, PQMSG pQmsg)
  17328.  
  17329.    The msgf parameter has the following three values:
  17330.  
  17331.    Value                  Meaning
  17332.    ──────────────────────────────────────────────────────────────────────────
  17333.    MSGF_DIALOGBOX         Message originated while processing a modal dialog
  17334.                           window.
  17335.  
  17336.    MSGF_MESSAGEBOX        Message originated while processing a message box.
  17337.  
  17338.    MSGF_TRACK             Message originated while tracking a control (such
  17339.                           as a scroll bar).
  17340.    ──────────────────────────────────────────────────────────────────────────
  17341.  
  17342.    The pQmsg parameter of the MsgFilterHook function is a far pointer to a
  17343.    QMSG structure containing information about the message.
  17344.  
  17345.    If this hook returns TRUE, the message is not passed to the rest of the
  17346.    hook chain or to the application. If it returns FALSE, the message is
  17347.    passed to the next hook in the chain, or to the application if no other
  17348.    hooks exist.
  17349.  
  17350.    This hook allows applications to perform message filtering during modal
  17351.    loops that is equivalent to the typical filtering for the main message
  17352.    loop. For example, applications often examine a new message in the main
  17353.    event loop between the time they retrieve the message from the queue and
  17354.    the time they dispatch it, performing special processing as appropriate.
  17355.    The following code fragment shows a main message loop that tests for the
  17356.    ENTER key and the ESC key before dispatching an event:
  17357.  
  17358.    while (WinGetMsg(hab, (PQMSG) &qmsg, (HWND) NULL, 0, 0)) {
  17359.  
  17360.       if ((qmsg.msg == WM_CHAR) && !(LOUSHORT(qmsg.mp1) & KC_KEYUP)
  17361.                && !hwndQueue) {
  17362.            switch (HIUSHORT(qmsg.mp2)) {
  17363.                case VK_ESC:
  17364.  
  17365.                    /* Use the ESC key.       */
  17366.  
  17367.                    continue;
  17368.  
  17369.                case VK_NEWLINE:
  17370.  
  17371.                    /* Use the newline event. */
  17372.  
  17373.                    continue;
  17374.  
  17375.                default:
  17376.                    break;
  17377.            }
  17378.        }
  17379.        WinDispatchMsg(hab, (PQMSG) &qmsg);
  17380.    }
  17381.  
  17382.    You cannot usually do this sort of filtering during a modal loop, since
  17383.    the loop created by the WinGetMsg and WinDispatchMsg functions is executed
  17384.    by the system. If you install a message-filter hook, the hook is called by
  17385.    the system between WinGetMsg and WinDispatchMsg in the modal processing
  17386.    loop.
  17387.  
  17388.    Your application can also call the message-filter loop directly by calling
  17389.    the WinCallMsgFilter function. By using this function, you can use the
  17390.    same code to filter messages in your main message loop and during modal
  17391.    loops. In the example shown previously for processing main message loops,
  17392.    you would encapsulate the filtering operations in a message-filter hook
  17393.    and call WinCallMsgFilter between the calls to the WinGetMsg and
  17394.    WinDispatchMsg functions, as shown in the following code fragment:
  17395.  
  17396.    while (WinGetMsg(hab, (PQMSG) &qmsg, (HWND) NULL, 0, 0)) {
  17397.        if (!WinCallMsgFilter(hab, (PQMSG) &qmsg, 0))
  17398.            WinDispatchMsg(hab, (PQMSG) &qmsg);
  17399.    }
  17400.  
  17401.    The last argument of the WinCallMsgFilter function is simply passed to the
  17402.    hook; the application can enter any value. This value can be used by the
  17403.    hook to determine where the hook was called from, by defining a constant
  17404.    such as MSGF_MAINLOOP.
  17405.  
  17406.  28.3.4  Journal-Record Hook
  17407.  
  17408.    This hook monitors the system queue and allows the application to record
  17409.    input events. Typically, it is used to record a set of mouse and keyboard
  17410.    events that can be played back later by using the journal-playback hook.
  17411.    The journal-record hook can be installed only in the system queue.
  17412.  
  17413.    The syntax for the journal-record hook is as follows:
  17414.  
  17415.      VOID CALLBACK JournalRecordHook(HAB hab, PQMSG pQmsg)
  17416.  
  17417.    The pQmsg parameter is a far pointer to a QMSG structure containing
  17418.    information about the message. The hook is called after the raw input has
  17419.    been processed enough to create valid WM_CHAR or double-click mouse
  17420.    messages and the window-handle field of the QMSG structure has been set.
  17421.  
  17422.    The journal-record hook does not return a value, and the next hook in the
  17423.    chain is always called. Typically, this hook saves the input event to the
  17424.    disk, to be played back later. The hwnd field of the QMSG structure is not
  17425.    important and is ignored when the message is read back.
  17426.  
  17427.    Character messages are passed to the journal-record hook as WM_VIOCHAR
  17428.    messages. The format of the WM_VIOCHAR message is as follows:
  17429.  
  17430.    fsKeyFlags = (USHORT) SHORT1FROMMP(mp1);    /* key flags    */
  17431.    uchRepeat = (UCHAR) CHAR3FROMMP(mp1);       /* repeat count */
  17432.    uchScanCode = (UCHAR) CHAR4FROMMP(mp1);     /* scan code    */
  17433.    usChr = LOBYTE(LOWORD(mp2));                /* character    */
  17434.    uschKbdScan = HIBYTE(LOWORD(mp2));          /* virtual key  */
  17435.  
  17436.    The WM_VIOCHAR message was chosen over the WM_CHAR message because it
  17437.    preserves that raw information from the keyboard driver that is needed for
  17438.    video input and output.
  17439.  
  17440.    The following mouse messages are passed to the journal-record hook:
  17441.  
  17442.          WM_MOUSEMOVE
  17443.          WM_BUTTON1DOWN
  17444.          WM_BUTTON1UP
  17445.          WM_BUTTON2DOWN
  17446.          WM_BUTTON2UP
  17447.          WM_BUTTON3DOWN
  17448.          WM_BUTTON3UP
  17449.  
  17450.    The positions stored in the mouse messages are in screen coordinates. The
  17451.    system does not combine mouse clicks into double clicks before calling the
  17452.    hook, since there is no guarantee that both clicks will be in the same
  17453.    window when they are read back.
  17454.  
  17455.    A WM_JOURNALNOTIFY message is passed to the journal-record hook whenever a
  17456.    program calls the WinGetPhysKeyState or WinQueryQueueStatus function. This
  17457.    message is necessary because the system is reduced to a queue that is only
  17458.    one message deep while a playback hook is active. For example, the user
  17459.    might press the A, B, and C keys while in record mode. While the program
  17460.    is processing the "A" character message, the B key might be down;
  17461.    WinGetPhysKeyState will return this information. However, during playback
  17462.    mode, the system only knows that it is currently processing the A key.
  17463.  
  17464.    The format of the WM_JOURNALNOTIFY message is as follows:
  17465.  
  17466.      For the WinGetPhysKeyState function:
  17467.  
  17468.    ulCmd = LONGFROMMP(mp1);            /* calling function   */
  17469.    sc = SHORT1FROMMP(mp2);             /* virtual key        */
  17470.    fsPhysKeyState = SHORT2FROMMP(mp2); /* physical-key state */
  17471.  
  17472.      For the WinQueryQueueStatus function:
  17473.  
  17474.    ulCmd = LONGFROMMP(mp1);            /* calling function   */
  17475.    ulQueStatus = LONGFROMMP(mp2);      /* queue status       */
  17476.  
  17477.  28.3.5  Journal-Playback Hook
  17478.  
  17479.    The journal-playback hook allows an application to insert messages into
  17480.    the system queue. Typically, this hook is used to play back a series of
  17481.    mouse and keyboard events that were recorded earlier by using the
  17482.    journal-record hook. This hook can be installed only in the system queue.
  17483.  
  17484.    Regular mouse and keyboard input is disabled as long as a journal-playback
  17485.    hook is installed. It is important to note that, since mouse and keyboard
  17486.    input are disabled, this hook can easily hang the system.
  17487.  
  17488.    The syntax for the journal-playback hook is as follows:
  17489.  
  17490.      ULONG CALLBACK JournalPlaybackHook(HAB hab, PQMSG pQmsg,
  17491.          BOOL fSkip)
  17492.  
  17493.    The pQmsg parameter is a far pointer to a QMSG structure that the hook
  17494.    fills in with the message to be played back. If the fSkip parameter is
  17495.    FALSE, the hook should fill in the QMSG structure with the current
  17496.    recorded message. The same message should be returned each time the hook
  17497.    is called, until fSkip is TRUE. The same message may be returned many
  17498.    times if an application is examining the queue but not removing the
  17499.    message. If fSkip is TRUE, the hook should advance to the next message
  17500.    without attempting to fill in the QMSG structure, since the pQmsg
  17501.    parameter is NULL when fSkip is TRUE.
  17502.  
  17503.    The journal-playback hook returns a ULONG time-out value. This value tells
  17504.    the system how many milliseconds to wait before processing the current
  17505.    message from the playback hook. This allows the hook to control the timing
  17506.    of the events it plays back.
  17507.  
  17508.    The time field of the QMSG structure is filled in with the current time
  17509.    before the playback hook is called. The hook should use the time stored in
  17510.    this field instead of the system clock to set up the delays.
  17511.  
  17512.    The discussion of different types of messages in Section 28.3.4 is also
  17513.    applicable to the journal-playback hook. The only exception has to do with
  17514.    character processing. The journal-record hook is always passed a
  17515.    WM_VIOCHAR message for each character processed by the system. The
  17516.    journal-playback hook, on the other hand, has the option of playing back
  17517.    either WM_VIOCHAR or WM_CHAR messages. The preferred method is to play
  17518.    back WM_VIOCHAR messages, since they contain the information required to
  17519.    function in a video-input-and-output window. If WM_CHAR messages are
  17520.    returned, the appropriate KC bits must be set or cleared.
  17521.  
  17522.  28.3.6  Help Hook
  17523.  
  17524.    The help hook is called during the default processing of the WM_HELP
  17525.    message. Help processing is done in two stages: creating the WM_HELP
  17526.    message and calling the help hook. The WM_HELP message can come from the
  17527.    following sources:
  17528.  
  17529.    ■  From a WM_CHAR message, after translation by an ACCEL structure with
  17530.       the AF_HELP style. The default system accelerator table translates the
  17531.       F1 key into a help message. The WM_HELP message is posted to the
  17532.       current focus window, which can be a menu, a button, a frame, or your
  17533.       client window.
  17534.  
  17535.    ■  From a menu-bar selection, when the MIS_HELP style is specified for the
  17536.       menu-bar item. The WM_HELP message is posted to the current focus
  17537.       window.
  17538.  
  17539.    ■  From a dialog-box push button, when the BS_HELP style is specified for
  17540.       the push button. The WM_HELP message is posted to the button's owner
  17541.       window, which is normally the dialog window.
  17542.  
  17543.    ■  From a message box, when the MB_HELP style is specified for the message
  17544.       box. The WM_HELP message is posted to the message-box dialog window.
  17545.  
  17546.    The WM_HELP message is posted to the current focus window. The default
  17547.    processing in the WinDefWindowProc function is to pass the message up to
  17548.    the parent window. If the message reaches the client window, it can be
  17549.    processed there. If the message reaches a frame window, the default
  17550.    frame-window procedure calls the help hook. The help hook is also called
  17551.    if a WM_HELP message is generated while the application is in menu
  17552.    mode──that is, while a selection is being made from a menu.
  17553.  
  17554.    The syntax for the help hook is as follows:
  17555.  
  17556.      BOOL CALLBACK HelpHook(HAB hab, USHORT usMode, USHORT idTopic,
  17557.          USHORT idSubTopic, PRECTL prcPosition)
  17558.  
  17559.    If this hook function returns TRUE, the message is not passed to the rest
  17560.    of the hook chain or to the application. If it returns FALSE, the message
  17561.    is passed to the next hook in the chain. The arguments of the help hook
  17562.    provide context information, such as the screen coordinates of the focus
  17563.    window and whether the message originated in a message box or a menu.
  17564.  
  17565.    The WM_HELP message often goes to a frame window instead of to the client
  17566.    window. The frame window (including dialog boxes and message boxes)
  17567.    processes a WM_HELP message as follows:
  17568.  
  17569.    ■  If the window with the focus is the FID_CLIENT window, the frame window
  17570.       passes the WM_HELP message to the FID_CLIENT window.
  17571.  
  17572.    ■  If the parent of the window with the focus is the FID_CLIENT
  17573.       frame-control window, the frame window calls the help hook, specifying
  17574.       the following:
  17575.  
  17576.             Mode = HLPM_FRAME
  17577.             Topic = frame-window identifier
  17578.             Subtopic = focus-window identifier
  17579.             Position = screen coordinates of focus window
  17580.  
  17581.    ■  If the parent of the focus window is not an FID_CLIENT window (it could
  17582.       be the frame window or a second-level dialog window), the frame window
  17583.       calls the help hook, specifying the following:
  17584.  
  17585.             Mode = HLPM_WINDOW
  17586.             Topic = identifier of parent of focus window
  17587.             Subtopic = focus-window identifier
  17588.             Position = screen coordinates of focus window
  17589.  
  17590.    An application receives the WM_HELP message in its dialog-window
  17591.    procedure. The application can ignore the message, in which case the
  17592.    frame-manager action occurs as described, or the application can handle
  17593.    the WM_HELP message directly.
  17594.  
  17595.    Menu windows receive a WM_HELP message when the user presses the help
  17596.    accelerator key (F1 by default) while a menu is displayed. Menu windows
  17597.    process WM_HELP messages by calling the help hook, specifying the
  17598.    following:
  17599.  
  17600.          Mode = HLPM_MENU
  17601.          Topic = identifier of pull-down menu
  17602.          Subtopic = identifier of selected item in pull-down menu
  17603.          Position = screen coordinates of selected item
  17604.  
  17605.    The help hook should respond to the help message by displaying information
  17606.    about the selected menu item.
  17607.  
  17608.    The WinDefWindowProc function processes WM_HELP messages by passing the
  17609.    message to the parent window. The message typically moves up the parent
  17610.    chain until it arrives at a frame window.
  17611.  
  17612.  
  17613.  28.4  Using Hooks
  17614.  
  17615.    Applications install hooks by calling the WinSetHook function, specifying
  17616.    the type of hook, whether it should go into the system queue or into the
  17617.    queue of a particular thread, and a far pointer to a function entry point.
  17618.  
  17619.    Procedures installed as hooks in a thread's queue are called only in the
  17620.    context of that thread. This kind of hook is typically a locally defined
  17621.    function.
  17622.  
  17623.    Procedures installed as hooks in the system queue can be called in the
  17624.    context of any application. System-queue hooks must be defined in separate
  17625.    dynamic-link-library (DLL) modules, because it is not possible to call
  17626.    application-module procedures from other applications. For a sample
  17627.    system-queue DLL module, see Section 28.5.
  17628.  
  17629.    A hook can be released by calling the WinReleaseHook function with the
  17630.    same arguments used when installing the hook. All hooks should be released
  17631.    before the application terminates, although the system automatically
  17632.    releases them if the application does not.
  17633.  
  17634.    A system hook can be released by using the WinReleaseHook function, but
  17635.    the DLL function containing the hook procedure is not freed. This is
  17636.    because system hooks are called in the process context of every
  17637.    Presentation Manager application in the system, causing an implicit call
  17638.    to the DosLoadModule function for all of those processes. Since a call to
  17639.    the DosFreeModule function cannot be made for another process, there is no
  17640.    way to free the dynamic-link libraries. (However, since the hook procedure
  17641.    is no longer called, the DLL segments may be discarded or swapped.)
  17642.  
  17643.  
  17644.  28.5  Hook Example
  17645.  
  17646.    This section shows the main elements of installing and using a
  17647.    system-input-queue hook, although many of the details of the hook are
  17648.    omitted. The example code comes from a larger program that uses a hook to
  17649.    monitor the input queue and display all input messages in an application
  17650.    window on the screen. This example has two main parts: the installing
  17651.    application and the hook DLL. The installing application identifies a hook
  17652.    procedure in the DLL and installs it in the system-queue hook chain. The
  17653.    application then controls the hook through other function calls to the
  17654.    DLL, performing such actions as turning the hook on and off and asking it
  17655.    for the most recent messages.
  17656.  
  17657.    The system hook is more than a single hook procedure; it is typically a
  17658.    DLL with several support procedures and entry points. This allows the
  17659.    installing application to control and communicate with the hook procedure.
  17660.  
  17661.  28.5.1  Installing a System Hook
  17662.  
  17663.    Since this example is a system hook, the hook procedure must be in a
  17664.    separate DLL from the application that installs it. The installing
  17665.    application needs the module handle of the DLL before it can install the
  17666.    hook. The DosLoadModule function, given the name of the DLL, returns the
  17667.    handle of the module. Once the module handle is known, the application
  17668.    calls the WinSetHook function, passing the module handle, a far pointer to
  17669.    the hook-procedure entry point, and NULL for the message-queue argument,
  17670.    indicating that the hook should go into the system queue. This sequence is
  17671.    shown in the following code fragment:
  17672.  
  17673.    CHAR      achFailName[128];
  17674.    HMODULE   hmodSpy;
  17675.    BOOL      fRet;
  17676.  
  17677.    /*
  17678.     * This example assumes that there is a hook procedure named
  17679.     * "SpyInputHook" that resides in a DLL file named "spyhook.dll,"
  17680.     * and that "spyhook.dll" is in a directory defined by the LIBPATH
  17681.     * command in the config.sys file.
  17682.     */
  17683.  
  17684.    if (DosLoadModule(achFailName,         /* failure-name buffer     */
  17685.                      sizeof(achFailName), /* size of failure buffer  */
  17686.                      "spyhook",           /* module name             */
  17687.                      &hmodSpy) == 0) {    /* address of handle       */
  17688.  
  17689.        fRet = WinSetHook(hab,             /* anchor-block handle     */
  17690.                      (HMQ) NULL,          /* system queue            */
  17691.                      HK_INPUT,            /* hook type               */
  17692.                      (PFN) SpyInputHook,  /* far pointer to function */
  17693.                      hmodSpy);            /* module handle for DLL   */
  17694.    }
  17695.  
  17696.    An alternative method for installing a system queue is to provide an
  17697.    installation function in the DLL along with the hook procedure. With this
  17698.    method, the installing application does not need the module handle for the
  17699.    DLL. By linking with the DLL, the application gains access to the
  17700.    installation function. The installation function can supply the module
  17701.    handle and other details in the call to the WinSetHook function. The DLL
  17702.    can also contain a function that removes the system-hook procedure; the
  17703.    application can call this function when it terminates.
  17704.  
  17705.  28.5.2  System-Hook Code
  17706.  
  17707.    The hook procedure is part of the DLL module. As such, it has access to
  17708.    the resources of the module: its global variables, other support
  17709.    procedures, and any memory allocated by the module. The following code
  17710.    template shows the structure of a typical input-hook procedure. It uses a
  17711.    static variable to control whether or not it should examine the input
  17712.    messages. Although it is not required, the DLL would typically provide
  17713.    another procedure to toggle the state of the variable, so that an
  17714.    application that installs the hook can turn the hook on and off.
  17715.  
  17716.    This example could save each message in a buffer allocated during the
  17717.    initialization of the DLL module. The DLL module would also provide a
  17718.    calling interface, so that the installing application could periodically
  17719.    request the messages from the buffers.
  17720.  
  17721.    BOOL CALLBACK PASCAL SpyInputHook(hab, lpqmsg)
  17722.    HAB hab;
  17723.    PQMSG lpqmsg;
  17724.    {
  17725.        static BOOL fRecording;
  17726.  
  17727.        /*
  17728.         * The lpqmsg parameter points to a queue-message structure.
  17729.         * Returns FALSE to let the message through to the rest of the
  17730.         * hook chain. Returns TRUE to prevent further message processing.
  17731.         */
  17732.  
  17733.        if (!fRecording)
  17734.            return FALSE; /* pass message to rest of chain  */
  17735.  
  17736.        /* Else examine message and process as appropriate. */
  17737.  
  17738.        return FALSE;
  17739.  
  17740.    }
  17741.  
  17742.  
  17743.  28.6  Summary
  17744.  
  17745.    This section summarizes the six types of hooks and the functions related
  17746.    to hooks.
  17747.  
  17748.  28.6.1  Functions
  17749.  
  17750.    The following functions are used with hooks:
  17751.  
  17752.    WinCallMsgFilter  Calls the currently installed message-filter chain of
  17753.    hooks. This call is useful if the same message filtering is used in the
  17754.    main message loop and the modal system-message loops.
  17755.  
  17756.    WinReleaseHook  Removes a specified procedure from the input-hook chain.
  17757.  
  17758.    WinSetHook  Installs a specified procedure in either the system or queue
  17759.    chain of hooks.
  17760.  
  17761.  28.6.2  Hook Types
  17762.  
  17763.    The following constants are used to identify the type of hook being
  17764.    installed or released by the WinSetHook or WinReleaseHook function:
  17765.  
  17766.    HK_HELP  Monitors the WM_HELP message. Returns BOOL. If FALSE, the next
  17767.    hook in the chain is called. If TRUE, the next hook in the chain is not
  17768.    called.
  17769.  
  17770.    HK_INPUT  Monitors messages in the specified message queue. Returns BOOL.
  17771.    If FALSE, the next hook in the chain is called. If TRUE, the message is
  17772.    not passed to the next hook in the chain.
  17773.  
  17774.    HK_JOURNALPLAYBACK  Allows applications to insert events into the
  17775.    system-input queue. Returns a LONG time-out value. This value is the
  17776.    number of milliseconds to wait before processing the current message. This
  17777.    type never calls the next hook in the chain.
  17778.  
  17779.    HK_JOURNALRECORD  Allows applications to record system-input-queue events.
  17780.    Returns VOID. The next hook in the chain is always called.
  17781.  
  17782.    HK_MSGFILTER  Monitors input events during system modal loops. Returns
  17783.    BOOL. If FALSE, the next hook in the chain is called. If TRUE, the message
  17784.    is not passed to the next hook in the chain.
  17785.  
  17786.    HK_SENDMSG  Monitors messages sent by using the WinSendMsg function.
  17787.    Returns VOID. The next hook in the chain is always called.
  17788.  
  17789.  
  17790.  
  17791.  ────────────────────────────────────────────────────────────────────────────
  17792.  Chapter 29  Help
  17793.  
  17794.         29.1    Introduction
  17795.         29.2    About Help
  17796.         29.3    Using Help in an Application
  17797.             29.3.1    Help Menu Item
  17798.             29.3.2    Help in a Dialog Box
  17799.             29.3.3    Help in a Message Box
  17800.             29.3.4    Help for a Menu Item
  17801.             29.3.5    The Help Hook
  17802.                 29.3.5.1   Installing a Help Hook
  17803.                 29.3.5.2   Help Hook for a Menu Item
  17804.         29.4    Summary
  17805.             29.4.1    Functions
  17806.             29.4.2    Messages
  17807.             29.4.3    Syntax of the Help Hook
  17808.  
  17809.  29.1  Introduction
  17810.  
  17811.    This chapter describes how to use the WM_HELP message in your
  17812.    applications. You should also be familiar with the following topics:
  17813.  
  17814.    ■  Standard user-interface guidelines
  17815.  
  17816.    ■  Window messages and message queues
  17817.  
  17818.    ■  Focus window and input guidelines
  17819.  
  17820.    ■  Help hook
  17821.  
  17822.  
  17823.  29.2  About Help
  17824.  
  17825.    One of the key elements of user-friendly software is readily available
  17826.    on-line help. MS OS/2 provides functions and messages to support the
  17827.    implementation of a help system in your application. This chapter
  17828.    discusses the features of MS OS/2 that support on-line help and suggests
  17829.    techniques for implementing a help system. The two main components of the
  17830.    system support for help are the WM_HELP message and the help hook.
  17831.  
  17832.    The WM_HELP message is defined by the system to notify an application when
  17833.    the user wants help. The WM_HELP message contains context information that
  17834.    allows the application to respond with information appropriate to current
  17835.    conditions. The system posts a WM_HELP message in the following
  17836.    situations:
  17837.  
  17838.    ■  During accelerator-table translation for a keyboard event, if the
  17839.       keystroke corresponds to an accelerator-table entry with the AF_HELP
  17840.       attribute. The system default accelerator table translates the F1 key
  17841.       into a WM_HELP message. The WM_HELP message is posted to the focus
  17842.       window. If the F1 key is pressed while a menu has the focus, the help
  17843.       message goes to the menu, which calls the help hook.
  17844.  
  17845.    ■  When a menu item with the MIS_HELP style is chosen. All applications
  17846.       should define at least one menu item with the MIS_HELP style in the
  17847.       menu bar. This menu item is typically labeled "F1=Help," as shown in
  17848.       Figure 29.1. The WM_HELP message is posted to the focus window.
  17849.  
  17850.    ■  When a push button with the BS_HELP style is pressed. (Note that this
  17851.       includes the case in which the Help button is pressed in a message box
  17852.       that has the MB_HELP style.) The WM_HELP message is posted to the
  17853.       button's owner window, which is typically a dialog frame window.
  17854.  
  17855.    ┌────────────────────────────────────────────────────────────────────────┐
  17856.    │ Figure 29.1 can be found in Section 29.2 of the printed manual.        │
  17857.    └────────────────────────────────────────────────────────────────────────┘
  17858.  
  17859.    Figure 29.1  Help Menu Item
  17860.  
  17861.    The Help menu item and the F1 accelerator key provide a standard
  17862.    user-interface to the help system. They allow the user to get general help
  17863.    about the application. The BS_HELP push button style allows applications
  17864.    to provide help within dialog boxes. You should provide a Help push button
  17865.    in every dialog box; the help message should explain the purpose and
  17866.    consequence of any action that could be taken by using that dialog box.
  17867.  
  17868.    Your application should process the WM_HELP message to provide
  17869.    context-appropriate help to the user. In the case of the Help menu item or
  17870.    the F1 accelerator key, the WM_HELP message is posted to the focus window.
  17871.    The focus window can process the message or it can pass it to the
  17872.    WinDefWindowProc function, which sends the message to the parent window.
  17873.    If you have a client window with several child windows that can accept the
  17874.    focus, you can intercept the WM_HELP message in the client window
  17875.    procedure as the message is passed up from the child window with the
  17876.    focus. The state of the application when the help message is received
  17877.    determines the appropriate help, which may be a list of help topics or
  17878.    information about the window that has the focus.
  17879.  
  17880.    There are limits to what can be accomplished by intercepting the WM_HELP
  17881.    message. In particular, the application does not receive WM_HELP messages
  17882.    generated while a menu item is selected. For example, if the user presses
  17883.    the F1 key while selecting a menu item, the WM_HELP message goes to the
  17884.    menu window. The menu window does not pass the message on; instead, it
  17885.    calls the help hook.
  17886.  
  17887.    The help hook allows you to install code that is called by menu windows
  17888.    and frame windows when they receive WM_HELP messages. You must install a
  17889.    help hook for your application if you want to provide help for selected
  17890.    menu items, since there is no way to intercept the WM_HELP message that
  17891.    originates while a menu item is selected. In addition, if you don't
  17892.    process a WM_HELP messages in your client window, the message is passed to
  17893.    the frame window, which calls the help hook.
  17894.  
  17895.    The following sections describe in more detail how to handle WM_HELP
  17896.    messages and when to install a help hook.
  17897.  
  17898.  
  17899.  29.3  Using Help in an Application
  17900.  
  17901.    There are two methods of providing help in an application. The simplest
  17902.    method provides general information to the user by processing the WM_HELP
  17903.    message in the client window. The second method, installing a help hook,
  17904.    provides help in situations in which the WM_HELP message is not available
  17905.    to the client window. Since installing a help hook is not difficult, most
  17906.    applications use both methods.
  17907.  
  17908.  29.3.1  Help Menu Item
  17909.  
  17910.    Every application should have a Help menu item in the menu bar of its main
  17911.    window. The text of the Help item should be "F1=Help" and it should have a
  17912.    menu-item identifier of zero. The Help menu item should have the MIS_HELP
  17913.    and MIS_BUTTONSEPARATOR styles. The following resource-definition file
  17914.    shows how to place a Help item in the menu bar.
  17915.  
  17916.    MENU ID_MENU_RSRC
  17917.    BEGIN
  17918.        SUBMENU "~File", IDM_FILE
  17919.            BEGIN
  17920.                MENUITEM "~Quit",      IDM_FI_QUIT
  17921.                MENUITEM "",           IDM_FI_SEP3,      MIS_SEPARATOR
  17922.                MENUITEM "~About Sample...", IDM_FI_ABOUT
  17923.            END
  17924.        SUBMENU "~Edit", IDM_EDIT
  17925.            BEGIN
  17926.                MENUITEM "~Undo",      IDM_ED_UNDO,      0,MIA_DISABLED
  17927.                MENUITEM "",           IDM_ED_SEP1,      MIS_SEPARATOR
  17928.                MENUITEM "~Cut",       IDM_ED_CUT,       0,MIA_DISABLED
  17929.                MENUITEM "C~opy",      IDM_ED_COPY,      0,MIA_DISABLED
  17930.                MENUITEM "~Paste",     IDM_ED_PASTE,     0,MIA_DISABLED
  17931.                MENUITEM "C~lear",     IDM_ED_CLEAR,     0,MIA_DISABLED
  17932.            END
  17933.        MENUITEM "F1=Help", 0x00, MIS_HELP | MIS_BUTTONSEPARATOR
  17934.    END
  17935.  
  17936.    If the user clicks the Help item in the menu bar, the system posts a
  17937.    WM_HELP message to the current focus window. If the client window has the
  17938.    focus, it can process the WM_HELP message to provide general help
  17939.    information for the user. If a child window of the client has the focus,
  17940.    the child window passes the message up the parent-window chain to the
  17941.    client window (by default). In this case, the client window can process
  17942.    the WM_HELP message appropriately for the child window that has the focus.
  17943.  
  17944.    If the client window passes the WM_HELP message on to the WinDefWindowProc
  17945.    function, this function passes the message up the parent-window chain
  17946.    until it finds a frame window. The default frame window processes the
  17947.    WM_HELP message by calling the help hook.
  17948.  
  17949.  29.3.2  Help in a Dialog Box
  17950.  
  17951.    You should provide a Help button in each dialog box that your application
  17952.    displays. The Help button should have the BS_HELP style. When the user
  17953.    presses the Help button, a WM_HELP message is posted to the button's
  17954.    owner, which is usually the dialog window. The dialog procedure can
  17955.    process the message and give the user help pertaining to the dialog box.
  17956.    Alternatively, if you pass the WM_HELP message on to the WinDefDlgProc
  17957.    function, it will call the help hook; this means you can choose whether to
  17958.    process dialog help in the dialog procedure or in the help hook.
  17959.  
  17960.  29.3.3  Help in a Message Box
  17961.  
  17962.    A message box can be given a Help button by specifying MB_HELP when
  17963.    creating the message box. Message boxes are like dialog boxes, except that
  17964.    you do not specify your own dialog procedure. If a message box contains a
  17965.    Help button, the program does not process the WM_HELP message. The default
  17966.    window procedure for the message box responds to the WM_HELP message by
  17967.    calling the help hook. To provide help for message boxes, you must install
  17968.    a help hook. Because the window identifier that you specify for the
  17969.    message box is passed to the help hook, you must use unique identifiers if
  17970.    you want to provide help for multiple message boxes.
  17971.  
  17972.  29.3.4  Help for a Menu Item
  17973.  
  17974.    One of the most important functions of a help system is to provide
  17975.    information about individual menu items. The user requests help for a menu
  17976.    item by pressing the F1 key while the menu item is selected. The menu
  17977.    receives the WM_HELP message, since the menu has the focus while the item
  17978.    is selected. The menu responds to the message by calling the help hook,
  17979.    supplying the identifier of the selected item.
  17980.  
  17981.    You must install a help hook to provide this kind of help for individual
  17982.    menu items. For an example of a help hook that supplies information about
  17983.    menu items, see Section 29.3.5.2.
  17984.  
  17985.    A method of supplying less comprehensive help for menu items is to use the
  17986.    WM_MENUSELECT message. The menu system sends a WM_MENUSELECT message every
  17987.    time the menu selection changes. The low word of the mp1 parameter of this
  17988.    message contains the identifier of the item that is changing state, and
  17989.    the high word is a 16-bit Boolean value that describes whether or not the
  17990.    item is chosen; the mp2 parameter contains the handle of the menu.
  17991.  
  17992.    If the Boolean value is FALSE, the menu item is selected but not
  17993.    chosen──for example, if the user moves the cursor or mouse pointer over
  17994.    the item while the button is down. An application can use this message to
  17995.    display brief help information at the bottom of the application window.
  17996.  
  17997.  29.3.5  The Help Hook
  17998.  
  17999.    You must install a help hook if you want to provide help for message boxes
  18000.    or menu items. You can also use the help hook to provide help when WM_HELP
  18001.    messages are passed up to a frame window. You can install more than one
  18002.    help hook; the system will call them in last-installed, first-called
  18003.    order.
  18004.  
  18005.    The parameters for a sample help hook are shown in this code fragment:
  18006.  
  18007.    BOOL CALLBACK HelpHook(HAB hab,
  18008.        USHORT usMode,
  18009.        USHORT idTopic,
  18010.        USHORT idSubTopic,
  18011.        PRECTL prcPosition);
  18012.  
  18013.    The usMode parameter has three possible values:
  18014.  
  18015.    Value             Description
  18016.    ──────────────────────────────────────────────────────────────────────────
  18017.    HLPM_MENU         The help message originated in a menu window when the
  18018.                      user pressed the F1 key while a menu item was selected.
  18019.  
  18020.    HLPM_FRAME        The frame window received a WM_HELP message, and the
  18021.                      parent of the focus window is the client window of the
  18022.                      frame window.
  18023.  
  18024.    HLPM_WINDOW       The frame window received a WM_HELP message, and the
  18025.                      parent of the focus window is not the client window of
  18026.                      the frame window.
  18027.    ──────────────────────────────────────────────────────────────────────────
  18028.  
  18029.    The value of the idTopic parameter depends on the value of the usMode
  18030.    parameter. The following list shows the values of the idTopic parameter:
  18031.  
  18032.    Value             Description
  18033.    ──────────────────────────────────────────────────────────────────────────
  18034.    HLPM_MENU         Identifier of submenu containing selected item.
  18035.  
  18036.    HLPM_FRAME        Identifier of frame window that called the help hook.
  18037.  
  18038.    HLPM_WINDOW       Identifier of parent of focus window.
  18039.    ──────────────────────────────────────────────────────────────────────────
  18040.  
  18041.    The value of the idSubTopic parameter depends on the value of the usMode
  18042.    parameter. The following list shows the values of the idSubTopic
  18043.    parameter:
  18044.  
  18045.    Value             Description
  18046.    ──────────────────────────────────────────────────────────────────────────
  18047.    HLPM_MENU         Identifier of selected menu item (-1 if menu-bar item is
  18048.                      selected).
  18049.  
  18050.    HLPM_FRAME        Identifier of focus window.
  18051.  
  18052.    HLPM_WINDOW       Identifier of focus window.
  18053.    ──────────────────────────────────────────────────────────────────────────
  18054.  
  18055.    The prcPosition parameter of the help hook indicates the screen area from
  18056.    which the help was requested. This argument may be the bounding rectangle
  18057.    of a menu item or the bounding rectangle of the focus window. You should
  18058.    use this information when displaying your help window to avoid covering up
  18059.    the corresponding screen area.
  18060.  
  18061.    The following code fragment shows a template for a help hook that handles
  18062.    the three possible calling modes:
  18063.  
  18064.    BOOL CALLBACK HelpHook(HAB hab,
  18065.        USHORT usMode,
  18066.        USHORT idTopic,
  18067.        USHORT idSubTopic,
  18068.        PRECTL prcPosition);
  18069.    {
  18070.        CHAR szMessage[256];
  18071.        switch(usMode){
  18072.            case HLPM_MENU:
  18073.                 /*
  18074.                  * idTopic: submenu identifier
  18075.                  * idSubTopic: item identifier
  18076.                  * prcPosition: boundary of item
  18077.                  */
  18078.  
  18079.                break;
  18080.  
  18081.            case HLPM_FRAME:
  18082.                 /*
  18083.                  * idTopic: frame identifier
  18084.                  * idSubTopic: focus-window identifier
  18085.                  * prcPosition: boundary of focus window
  18086.                  */
  18087.  
  18088.                break;
  18089.  
  18090.            case HLPM_WINDOW:
  18091.                 /*
  18092.                  * idTopic: identifier of parent of focus window
  18093.                  * idSubTopic: focus-window identifier
  18094.                  * prcPosition: boundary of focus window
  18095.                  */
  18096.  
  18097.                break;
  18098.        }
  18099.    }
  18100.  
  18101.    29.3.5.1  Installing a Help Hook
  18102.  
  18103.    Typically, you define a help hook as a function in your program's source
  18104.    code. At run time you install the help hook by calling the WinSetHook
  18105.    function, specifying the message queue and a pointer to the help function,
  18106.    as shown in the following code fragment:
  18107.  
  18108.    /* Install the help hook. */
  18109.  
  18110.    WinSetHook(hab,     /* anchor block                 */
  18111.        hmq,            /* message queue                */
  18112.        HK_HELP,        /* hook type                    */
  18113.        (PFN) HelpHook, /* function pointer             */
  18114.        NULL);          /* module = NULL => in our .exe */
  18115.  
  18116.    If you install a help hook you must release it by using the WinReleaseHook
  18117.    function before your program terminates. The following code fragment shows
  18118.    how to release a help hook:
  18119.  
  18120.    /* Release the help hook. */
  18121.  
  18122.    WinReleaseHook(hab, /* anchor block                 */
  18123.        hmq,            /* message queue                */
  18124.        HK_HELP,        /* hook type                    */
  18125.        (PFN) HelpHook, /* function pointer             */
  18126.        NULL);          /* module = NULL => in our .exe */
  18127.  
  18128.    29.3.5.2  Help Hook for a Menu Item
  18129.  
  18130.    If the user presses the F1 key while a menu item is selected, the menu
  18131.    receives a WM_HELP message. The menu responds to the help message by
  18132.    calling the help hook with the HLPM_MENU argument to the usMode parameter
  18133.    of the HelpHook function. The idTopic parameter contains the identifier of
  18134.    the submenu containing the selected item. The idSubTopic parameter
  18135.    contains the identifier of the selected item. If the selected item is in
  18136.    the menu bar instead of a submenu, idTopic contains the identifier of the
  18137.    menu-bar item and idSubTopic contains 0xFFFF.
  18138.  
  18139.    Your help hook can use this information to determine which menu item was
  18140.    selected when the F1 key was pressed. Using this information, the help
  18141.    hook should display information that explains the function of the menu
  18142.    item. The following code fragment shows a help hook that is capable of
  18143.    giving information about a file menu with two items and an edit menu with
  18144.    five items:
  18145.  
  18146.    BOOL CALLBACK HelpHook(HAB hab,
  18147.        USHORT usMode,
  18148.        USHORT idTopic,
  18149.        USHORT idSubTopic,
  18150.        PRECTL prcPosition);
  18151.    {
  18152.        /*
  18153.         * idTopic: submenu identifier
  18154.         * idSubTopic: item identifier
  18155.         */
  18156.        switch(usMode){
  18157.  
  18158.            case HLPM_MENU:
  18159.  
  18160.                switch(idTopic){
  18161.  
  18162.                    case IDM_FILE:
  18163.                        /* One of the File menu items is selected.   */
  18164.                        switch(idSubTopic){
  18165.                             case 0xFFFF:
  18166.                               /*
  18167.                                * A menu-bar item is selected; display
  18168.                                * information on all items in File menu.
  18169.                                */
  18170.                               break;
  18171.  
  18172.                             case IDM_FI_QUIT:
  18173.                               /* Display information on Quit item.  */
  18174.                               break;
  18175.  
  18176.                             case IDM_FI_ABOUT:
  18177.                               /* Display information on About item. */
  18178.                               break;
  18179.  
  18180.                        }      /* ends idSubTopic switch             */
  18181.                        break;
  18182.  
  18183.                    case IDM_EDIT:
  18184.                        /* One of the Edit menu items is selected.   */
  18185.                        switch(idSubTopic) {
  18186.                             case 0xFFFF:
  18187.                               /*
  18188.                                * A menu-bar item is selected; display
  18189.                                * information on all items in Edit menu.
  18190.                                */
  18191.                               break;
  18192.  
  18193.                             case IDM_ED_UNDO:
  18194.                               /* Display information on Undo item.  */
  18195.                               break;
  18196.  
  18197.                             case IDM_ED_CUT:
  18198.                               /* Display information on Cut item.   */
  18199.                               break;
  18200.  
  18201.                             case IDM_ED_COPY:
  18202.                               /* Display information on Copy item.  */
  18203.                               break;
  18204.  
  18205.                             case IDM_ED_PASTE:
  18206.                               /* Display information on Paste item. */
  18207.                               break;
  18208.                             case IDM_ED_CLEAR:
  18209.                               /* Display information on Clear item. */
  18210.                               break;
  18211.  
  18212.                        }      /* ends idSubTopic switch             */
  18213.  
  18214.                        break; /* ends IDM_EDIT case                 */
  18215.  
  18216.                }              /* ends idTopic switch                */
  18217.  
  18218.                break;         /* ends HLPM_MENU case                */
  18219.        }
  18220.    }
  18221.  
  18222.  
  18223.  29.4  Summary
  18224.  
  18225.    This section lists the functions and messages associated with providing
  18226.    help to the user, as well as a syntax description of the help hook.
  18227.  
  18228.  29.4.1  Functions
  18229.  
  18230.    The following functions work with the help hooks:
  18231.  
  18232.    WinSetHook  Installs a help hook in an application's message queue.
  18233.  
  18234.    WinReleaseHook  Releases a hook installed by using the WinSetHook
  18235.    function.
  18236.  
  18237.  29.4.2  Messages
  18238.  
  18239.    The following message is sent to notify an application that the user wants
  18240.    help:
  18241.  
  18242.    WM_HELP  Sent when a user requests help by pressing the F1 key or choosing
  18243.    a menu item or button with the help style.
  18244.  
  18245.  29.4.3  Syntax of the Help Hook
  18246.  
  18247.    The following syntax description is for the help hook, which is used to
  18248.    provide help for message boxes and menu items:
  18249.  
  18250.    BOOL CALLBACK HelpHook (HAB hab, USHORT usMode, USHORT idTopic, USHORT
  18251.    idSubTopic, PRECTL iprcPosition)
  18252.  
  18253.  
  18254.  
  18255.  ────────────────────────────────────────────────────────────────────────────
  18256.  PART 3  GRAPHICS PROGRAMMING INTERFACE
  18257.  ────────────────────────────────────────────────────────────────────────────
  18258.    Chapter 30  Presentation Spaces and Device Contexts
  18259.    Chapter 31  Coordinate Spaces and Transformations
  18260.    Chapter 32  Line and Arc Primitives
  18261.    Chapter 33  Fonts and Character Primitives
  18262.    Chapter 34  Color and Mix Modes
  18263.    Chapter 35  Paths
  18264.    Chapter 36  Area Primitives
  18265.    Chapter 37  Marker Primitives
  18266.    Chapter 38  Bitmaps
  18267.    Chapter 39  Regions
  18268.    Chapter 40  Clipping
  18269.    Chapter 41  Metafiles
  18270.    Chapter 42  Segments and Retained Graphics
  18271.  
  18272.  
  18273.  
  18274.  ────────────────────────────────────────────────────────────────────────────
  18275.  Chapter 30  Presentation Spaces and Device Contexts
  18276.  
  18277.         30.1    Introduction
  18278.         30.2    About Presentation Spaces and Device Contexts
  18279.             30.2.1    Presentation Spaces
  18280.                 30.2.1.1   Normal Presentation Spaces
  18281.                 30.2.1.2   Micro Presentation Spaces
  18282.                 30.2.1.3   Saving and Restoring Presentation Spaces
  18283.                 30.2.1.4   Destroying Presentation Spaces
  18284.             30.2.2    Device Contexts
  18285.                 30.2.2.1   Normal Device Contexts
  18286.                 30.2.2.2   Cached Device Contexts
  18287.                 30.2.2.3   Closing Device Contexts
  18288.             30.2.3    Linking Presentation Spaces with Devices
  18289.             30.2.4    The Presentation Page
  18290.             30.2.5    Determining Device Capabilities
  18291.         30.3    Using Presentation Spaces and Device Contexts
  18292.             30.3.1    Creating a Normal Presentation Space
  18293.             30.3.2    Creating a Standard Device Context for a Printer
  18294.             30.3.3    Creating a Standard Device Context for a Metafile
  18295.             30.3.4    Reassociating a Normal Presentation Space
  18296.             30.3.5    Associating a Device Context with a Presentation Space
  18297.         30.4    Summary
  18298.  
  18299.  
  18300.  30.1  Introduction
  18301.  
  18302.    This chapter describes Microsoft Operating System/2 presentation spaces
  18303.    and device contexts. You should also be familiar with the following
  18304.    topics:
  18305.  
  18306.    ■  Coordinate spaces and transformations
  18307.  
  18308.    ■  Segments
  18309.  
  18310.  
  18311.  30.2  About Presentation Spaces and Device Contexts
  18312.  
  18313.    A presentation space is a data structure maintained by MS OS/2 that
  18314.    describes an application's device-independent drawing environment. A
  18315.    device context links a presentation space to a device and gives an
  18316.    application access to important device information.
  18317.  
  18318.  30.2.1  Presentation Spaces
  18319.  
  18320.    There are two kinds of presentation spaces: normal and micro. You must use
  18321.    a normal presentation space to display and print output on multiple
  18322.    devices (a video display and a printer, for instance) or if your
  18323.    application uses the segment and retained-drawing functions to generate
  18324.    complex drawings. You should use a micro presentation space only to
  18325.    display and print output on a single device or if your application's
  18326.    output is a simple drawing. For a list of the segment and retained-drawing
  18327.    functions that are not supported by a micro presentation space, see
  18328.    Section 30.2.1.2.
  18329.  
  18330.    There are two kinds of micro presentation spaces: standard and cached. Use
  18331.    a standard micro presentation space to send output to a printer, a
  18332.    plotter, or any device; use a cached-micro presentation space to send
  18333.    output to a window on the display device.
  18334.  
  18335.    Table 30.1 summarizes the features and restrictions of each type of
  18336.    presentation space:
  18337.  
  18338.    Table 30.1
  18339.    Presentation-Space Features and Restrictions
  18340.    ──────────────────────────────────────────────────────────────────────────
  18341.    Presentation-space Retained-drawing   Multiple-device support
  18342.    type               support
  18343.    ──────────────────────────────────────────────────────────────────────────
  18344.    Normal             Yes                Yes
  18345.  
  18346.    Micro              No                 No
  18347.  
  18348.    Cached-micro       No                 No (restricted to a video-display
  18349.                                          window)
  18350.    ──────────────────────────────────────────────────────────────────────────
  18351.  
  18352.    30.2.1.1  Normal Presentation Spaces
  18353.  
  18354.    Because normal presentation spaces use more memory than micro presentation
  18355.    spaces, you should use them only when they are required. To create a
  18356.    normal presentation space, use the GpiCreatePS function. You can then
  18357.    associate the normal presentation space with a device and reassociate it
  18358.    later with a new device when you need to direct output to that second
  18359.    device. To associate a normal presentation space with a device when you
  18360.    create the presentation space, use the GPIA_ASSOC flag when you call
  18361.    GpiCreatePS. To associate a normal presentation space with a second or a
  18362.    third device later while your application is running, call the
  18363.    GpiAssociate function.
  18364.  
  18365.    30.2.1.2  Micro Presentation Spaces
  18366.  
  18367.    You can create a standard micro presentation space by calling the
  18368.    GpiCreatePS function and specifying the GPIT_MICRO flag. You must
  18369.    associate a standard micro presentation space with a device when you
  18370.    create the presentation space by specifying the GPIA_ASSOC flag as one of
  18371.    the options to GpiCreatePS and by supplying a handle that identifies a
  18372.    device context. You cannot reassociate a micro presentation space with
  18373.    another device.
  18374.  
  18375.    The window manager maintains a cache of micro presentation spaces for
  18376.    windows on a video display. You can access a cached-micro presentation
  18377.    space by calling the WinGetPS or WinBeginPaint function. You need not
  18378.    associate a cached-micro presentation space with the display; the window
  18379.    manager takes care of this for you.
  18380.  
  18381.    The following functions are not allowed in a micro presentation space:
  18382.  
  18383.    ■  GpiAssociate
  18384.  
  18385.    ■  GpiBeginElement
  18386.  
  18387.    ■  GpiCallSegmentMatrix
  18388.  
  18389.    ■  GpiCloseSegment
  18390.  
  18391.    ■  GpiCorrelateChain
  18392.  
  18393.    ■  GpiCorrelateFrom
  18394.  
  18395.    ■  GpiCorrelateSegment
  18396.  
  18397.    ■  GpiDeleteElement
  18398.  
  18399.    ■  GpiDeleteElementRange
  18400.  
  18401.    ■  GpiDeleteElementsBetweenLabels
  18402.  
  18403.    ■  GpiDeleteSegment
  18404.  
  18405.    ■  GpiDeleteSegments
  18406.  
  18407.    ■  GpiDrawChain
  18408.  
  18409.    ■  GpiDrawDynamics
  18410.  
  18411.    ■  GpiDrawFrom
  18412.  
  18413.    ■  GpiDrawSegment
  18414.  
  18415.    ■  GpiErase
  18416.  
  18417.    ■  GpiElement
  18418.  
  18419.    ■  GpiEndElement
  18420.  
  18421.    ■  GpiErrorSegmentData
  18422.  
  18423.    ■  GpiGetData
  18424.  
  18425.    ■  GpiLabel
  18426.  
  18427.    ■  GpiOffsetElementPointer
  18428.  
  18429.    ■  GpiOpenSegment
  18430.  
  18431.    ■  GpiPutData
  18432.  
  18433.    ■  GpiQueryBoundaryData
  18434.  
  18435.    ■  GpiQueryDrawControl
  18436.  
  18437.    ■  GpiQueryDrawingMode
  18438.  
  18439.    ■  GpiQueryEditMode
  18440.  
  18441.    ■  GpiQueryElement
  18442.  
  18443.    ■  GpiQueryElementPointer
  18444.  
  18445.    ■  GpiQueryElementType
  18446.  
  18447.    ■  GpiQueryInitialSegmentAttrs
  18448.  
  18449.    ■  GpiQueryPickAperturePosition
  18450.  
  18451.    ■  GpiQueryPickApertureSize
  18452.  
  18453.    ■  GpiQuerySegmentAttrs
  18454.  
  18455.    ■  GpiQuerySegmentNames
  18456.  
  18457.    ■  GpiQuerySegmentPriority
  18458.  
  18459.    ■  GpiQueryStopDraw
  18460.  
  18461.    ■  GpiQueryTag
  18462.  
  18463.    ■  GpiRemoveDynamics
  18464.  
  18465.    ■  GpiResetBoundaryData
  18466.  
  18467.    ■  GpiSetDrawControl
  18468.  
  18469.    ■  GpiSetDrawingMode
  18470.  
  18471.    ■  GpiSetEditMode
  18472.  
  18473.    ■  GpiSetElementPointer
  18474.  
  18475.    ■  GpiSetElementPointerAtLabel
  18476.  
  18477.    ■  GpiSetInitialSegmentAttrs
  18478.  
  18479.    ■  GpiSetPickAperturePosition
  18480.  
  18481.    ■  GpiSetPickApertureSize
  18482.  
  18483.    ■  GpiSetSegmentAttrs
  18484.  
  18485.    ■  GpiSetSegmentPriority
  18486.  
  18487.    ■  GpiSetStopDraw
  18488.  
  18489.    ■  GpiSetTag
  18490.  
  18491.    30.2.1.3  Saving and Restoring Presentation Spaces
  18492.  
  18493.    You can save the contents of a presentation space, modify its fields, draw
  18494.    in the modified presentation space, and then restore it to its original
  18495.    state. The GpiSavePS function saves the contents of a presentation space
  18496.    and the GpiRestorePS function restores them. When you call GpiSavePS, MS
  18497.    OS/2 copies the following items from the current presentation space onto a
  18498.    special stack:
  18499.  
  18500.    ■  Primitive attributes
  18501.  
  18502.    ■  Transformation matrices
  18503.  
  18504.    ■  Viewing limit
  18505.  
  18506.    ■  Clip path
  18507.  
  18508.    ■  Clip region
  18509.  
  18510.    ■  Current position
  18511.  
  18512.    ■  Loaded logical color table
  18513.  
  18514.    ■  Loaded logical font
  18515.  
  18516.    You can push the contents of a presentation space on the stack, and you
  18517.    can do so as many times as is necessary. The GpiRestorePS function pops
  18518.    the contents of a presentation space off the stack.
  18519.  
  18520.    30.2.1.4  Destroying Presentation Spaces
  18521.  
  18522.    Because presentation spaces consume a considerable amount of memory, you
  18523.    should destroy them whenever your application no longer needs them. To
  18524.    destroy a normal or micro presentation space, call the GpiDestroyPS
  18525.    function. Once you finish using a cached-micro presentation space that was
  18526.    accessed by using the WinGetPS function, you can release it by calling the
  18527.    WinReleasePS function. You need not destroy a presentation space that you
  18528.    accessed by using the WinBeginPaint function; MS OS/2 does this for you
  18529.    when you call the WinEndPaint function.
  18530.  
  18531.  30.2.2  Device Contexts
  18532.  
  18533.    Device contexts link presentation spaces to devices by converting
  18534.    device-independent presentation-space information into device-dependent
  18535.    information. (This conversion occurs in the device driver, a low-level
  18536.    program that is transparent at the API level.) Device contexts also give
  18537.    applications access to important device information such as screen
  18538.    dimensions or printer capabilities.
  18539.  
  18540.    There are two kinds of device contexts: normal and cached. A normal device
  18541.    context links a presentation space with any type of device. A cached
  18542.    device context can link a presentation space only with a window on a video
  18543.    display.
  18544.  
  18545.    30.2.2.1  Normal Device Contexts
  18546.  
  18547.    There are five types of normal device contexts:
  18548.  
  18549.    ■  Queued
  18550.  
  18551.    ■  Direct
  18552.  
  18553.    ■  Information
  18554.  
  18555.    ■  Memory
  18556.  
  18557.    ■  Metafile
  18558.  
  18559.    Each of these device contexts serves a specific purpose. A queued device
  18560.    context links a presentation space with a printer or plotter shared by
  18561.    multiple users. Queued devices store print jobs by using a program called
  18562.    a print spooler that keeps track of the order in which jobs arrive at the
  18563.    printer and the order in which they are printed. A direct device context
  18564.    links a presentation space with a printer or a plotter controlled by a
  18565.    single user and does not queue print jobs or other output. An information
  18566.    device context is a special device context that forms a one-way link to a
  18567.    device. An application can use an information device context to query a
  18568.    device but cannot send output to the device. A memory device links a
  18569.    presentation space with system memory. Memory device contexts are useful
  18570.    in applications that keep a "shadow" bitmap of the client area in a
  18571.    window. A metafile device context links a presentation space with a
  18572.    metafile. Applications that create complex drawings use metafiles to store
  18573.    the drawings.
  18574.  
  18575.    You can create a normal device context by calling the DevOpenDC function.
  18576.    This function requires you to specify one of the five types. It also
  18577.    requires that you pass important device-initialization data, including a
  18578.    logical address, the device-driver name, device-driver data, a description
  18579.    of the device type, and information about the queue (if the device is a
  18580.    queued device). The device-initialization data is passed in a DEVOPENSTRUC
  18581.    structure. This structure has the following form:
  18582.  
  18583.    typedef struct _DEVOPENSTRUC {      /* dop                          */
  18584.        PSZ        pszLogAddress;       /* logical-device address       */
  18585.        PSZ        pszDriverName;       /* device-driver name           */
  18586.        PDRIVDATA  pdriv;               /* pointer to add'l driver data */
  18587.        PSZ        pszDataType;         /* type of queued data          */
  18588.        PSZ        pszComment;          /* optional spooler info        */
  18589.        PSZ        pszQueueProcName;    /* queue-processor name         */
  18590.        PSZ        pszQueueProcParams;  /* queue-processor arguments    */
  18591.        PSZ        pszSpoolerParams;    /* spooler arguments            */
  18592.        PSZ        pszNetworkParams;    /* network arguments            */
  18593.    } DEVOPENSTRUC;
  18594.  
  18595.    The last six fields in this structure apply only to queued devices. For
  18596.    more information about the DEVOPENSTRUC structure, see the Microsoft
  18597.    Operating System/2 Programmer's Reference, Volume 2.
  18598.  
  18599.    30.2.2.2  Cached Device Contexts
  18600.  
  18601.    You can obtain a handle to one of the cached device contexts by calling
  18602.    the WinOpenWindowDC function. A cached device context is a direct device
  18603.    context that links a presentation space with a window in a video display.
  18604.    You should use a cached device context whenever a task will send output
  18605.    only to a window.
  18606.  
  18607.    30.2.2.3  Closing Device Contexts
  18608.  
  18609.    To close a device context that your application opened by calling the
  18610.    DevOpenDC function, you can call the DevCloseDC function. However, you
  18611.    should not try to close a device context that you opened by using the
  18612.    WinOpenWindowDC function; MS OS/2 will do this for you automatically when
  18613.    you destroy the associated window.
  18614.  
  18615.  30.2.3  Linking Presentation Spaces with Devices
  18616.  
  18617.    When you call the GpiCreatePS function and pass it the GPIA_ASSOC flag or
  18618.    when you call the GpiAssociate function, MS OS/2 requires that you pass
  18619.    the device-context handle returned by the DevOpenDC or WinOpenWindowDC
  18620.    function. This handle identifies the device context that links a
  18621.    presentation space to a device. Once you have established this link, any
  18622.    drawing operations performed using the presentation-space handle will also
  18623.    be performed on the associated device. Once an application is through
  18624.    using a particular device, it should disassociate the presentation space
  18625.    and the device by calling GpiAssociate and passing NULL as the second
  18626.    argument. A presentation space can be associated with a new device only
  18627.    after it has been disassociated from the original device, since it is not
  18628.    possible to associate a presentation space with more than one device at a
  18629.    time.
  18630.  
  18631.  30.2.4  The Presentation Page
  18632.  
  18633.    One of the arguments to the GpiCreatePS function is a SIZEL structure that
  18634.    specifies the dimensions of the presentation space's presentation page. A
  18635.    presentation page is a representation of a page on a printer or a plotter
  18636.    or a representation of a maximized window on a video display. MS OS/2 uses
  18637.    presentation pages to scale and position output on a device. For more
  18638.    information about presentation pages, see Chapter 31, "Coordinate Spaces
  18639.    and Transformations."
  18640.  
  18641.    The page-unit constant PS_UNITS, which is another argument to GpiCreatePS,
  18642.    is related to the SIZEL structure. This constant can be one of seven
  18643.    values:
  18644.  
  18645.    ■  PU_ARBITRARY
  18646.  
  18647.    ■  PU_PELS
  18648.  
  18649.    ■  PU_LOMETRIC
  18650.  
  18651.    ■  PU_HIMETRIC
  18652.  
  18653.    ■  PU_LOENGLISH
  18654.  
  18655.    ■  PU_HIENGLISH
  18656.  
  18657.    ■  PU_TWIPS
  18658.  
  18659.    The page-unit constant defines the dimensions of each unit on the
  18660.    presentation page. For example, if you specify PU_PELS, the length of each
  18661.    page unit in the x-direction will be identical to the width of a pel, and
  18662.    the length of each page unit in the y-direction will be identical to the
  18663.    height of a pel on the selected output device. If you specify
  18664.    PU_LOENGLISH, each page unit will measure 0.01 inches in the x- and
  18665.    y-directions.
  18666.  
  18667.    If you link a presentation space to a device when you call GpiCreatePS, MS
  18668.    OS/2 automatically assigns page dimensions to your presentation page. If
  18669.    you do not link a presentation space to a device when you call
  18670.    GpiCreatePS, you must assign the page dimensions.
  18671.  
  18672.  30.2.5  Determining Device Capabilities
  18673.  
  18674.    Once you have created a device context for a particular output device, you
  18675.    can determine the capabilities of that device by calling the DevQueryCaps
  18676.    function. This function retrieves the following information:
  18677.  
  18678.    ■  Device technology (whether the device is a raster or vector device)
  18679.  
  18680.    ■  Maximized window dimensions (if the device is a video display)
  18681.  
  18682.    ■  Page dimensions (if the device is a printer or plotter)
  18683.  
  18684.    ■  Character-box dimensions
  18685.  
  18686.    ■  Marker-box dimensions
  18687.  
  18688.    ■  Pel resolution
  18689.  
  18690.    ■  Color capabilities
  18691.  
  18692.    ■  Mix-mode capabilities
  18693.  
  18694.    You can use this information to, for example, select fonts, set up the
  18695.    presentation page, or create a new logical color table.
  18696.  
  18697.  
  18698.  30.3  Using Presentation Spaces and Device Contexts
  18699.  
  18700.    You can use presentation-space and device-context functions to perform the
  18701.    following tasks:
  18702.  
  18703.    ■  Create a normal, micro, or cached-micro presentation space.
  18704.  
  18705.    ■  Delete, save, or restore a presentation space.
  18706.  
  18707.    ■  Create a standard or cached device context.
  18708.  
  18709.    ■  Associate a presentation space or device context.
  18710.  
  18711.    ■  Destroy a device context.
  18712.  
  18713.    ■  Retrieve information about a device's capabilities.
  18714.  
  18715.  30.3.1  Creating a Normal Presentation Space
  18716.  
  18717.    The following code fragment shows how to create a presentation space with
  18718.    page units of 0.01 inches and associate it with a printer device context:
  18719.  
  18720.    HAB hab;          /* anchor-block handle       */
  18721.    HPS hpsNormal;    /* presentation-space handle */
  18722.    HDC hdcPrinter;   /* device-context handle     */
  18723.    SIZEL sizlPage;   /* page structure            */
  18724.        .
  18725.        .
  18726.        .
  18727.    hpsNormal = GpiCreatePS(hab, hdcPrinter, &sizlPage,
  18728.       PU_LOENGLISH | GPIA_ASSOC);
  18729.  
  18730.  30.3.2  Creating a Standard Device Context for a Printer
  18731.  
  18732.    The following code fragment shows how to create a printer device context:
  18733.  
  18734.    HDC hdcPrinter;              /* handle of printer device context */
  18735.    HAB hab;                     /* anchor-block handle              */
  18736.    DEVOPENSTRUC dop;            /* device information               */
  18737.  
  18738.    dop.pszLogAddress = "lpt1";      /* logical-device address */
  18739.    dop.pszDriverName = "PSCRIPT";   /* device-driver name     */
  18740.    dop.pdriv = NULL;                /* pointer to driver data */
  18741.    dop.pszDataType = "PM_Q_STD";    /* standard queued data   */
  18742.  
  18743.    hdcPrinter = DevOpenDC(hab,
  18744.        OD_DIRECT,                       /* direct device type */
  18745.        "*",                             /* no data in os2.ini */
  18746.        4L,
  18747.        (PDEVOPENDATA) &dop,
  18748.        (HDC) NULL);
  18749.  
  18750.  30.3.3  Creating a Standard Device Context for a Metafile
  18751.  
  18752.    The following code fragment shows how to create a standard device context:
  18753.  
  18754.    HDC hdcMeta, hdcWin; /* handles of metafile and window DC */
  18755.    HAB hab;             /* anchor-block handle               */
  18756.    DEVOPENSTRUC dop;    /* device information                */
  18757.  
  18758.    dop.pszLogAddress = NULL;          /* logical-device address */
  18759.    dop.pszDriverName = "DISPLAY";     /* device-driver name     */
  18760.    dop.pdriv = NULL;                  /* pointer to driver data */
  18761.    dop.pszDataType = NULL;            /* no queued data         */
  18762.  
  18763.    hdcMeta = DevOpenDC(hab,
  18764.        OD_METAFILE,           /* metafile DC                */
  18765.        "*",                   /* ignores os2.ini            */
  18766.        4L,                    /* uses first 4 fields in dop */
  18767.        (PDEVOPENDATA) &dop,   /* structure for system info  */
  18768.        NULL);                 /* compatible with screen     */
  18769.  
  18770.  30.3.4  Reassociating a Normal Presentation Space
  18771.  
  18772.    The following code fragment shows how to break the link between a normal
  18773.    presentation space and a device context and reassociate the presentation
  18774.    space with a metafile device context:
  18775.  
  18776.    if (!GpiAssociate(hps, NULL))    /* breaks link between PS and DC   */
  18777.        ReportError(...);
  18778.    if (!GpiAssociate(hps, hdcMeta)) /* reassociates PS and metafile DC */
  18779.        ReportError(...);
  18780.  
  18781.  30.3.5  Associating a Device Context with a Presentation Space
  18782.  
  18783.    The following code fragment shows how to open a cached device context and
  18784.    associate it with a normal presentation space:
  18785.  
  18786.    HDC hdcWin;         /* cached-device-context handle     */
  18787.    HPS hpsWin;         /* normal-presentation-space handle */
  18788.    HWND hwndClient;    /* client-window handle             */
  18789.    HAB hab;            /* anchor-block handle              */
  18790.    SIZEL sizlPage;     /* presentation page                */
  18791.  
  18792.    hdcWin = WinOpenWindowDC(hwndClient);
  18793.    hpsWin = GpiCreatePS(hab, hdcWin, &sizlPage,
  18794.        PU_LOENGLISH | GPIA_ASSOC);
  18795.  
  18796.  
  18797.  30.4  Summary
  18798.  
  18799.    The following list summarizes the MS OS/2 presentation-space and
  18800.    device-context functions:
  18801.  
  18802.    DevCloseDC  Closes a device context opened by the DevOpenDC function.
  18803.  
  18804.    DevOpenDC  Opens a device context for a printer or plotter.
  18805.  
  18806.    DevQueryCaps  Retrieves information about an output device.
  18807.  
  18808.    GpiAssociate  Associates a presentation space with a device context. This
  18809.    function is only valid if the presentation-space type is normal; it is
  18810.    invalid for micro and cached-micro presentation spaces. Remember that a
  18811.    presentation space can be associated with only one device at a time. To
  18812.    associate a presentation space with a second device, you should do the
  18813.    following:
  18814.  
  18815.    ■  Disassociate the presentation space and the original device by calling
  18816.       GpiAssociate and passing it NULL as the second argument.
  18817.  
  18818.    ■  Associate the presentation space with the second device by calling
  18819.       GpiAssociate, passing it a handle that identifies the device context of
  18820.       the new device.
  18821.  
  18822.    GpiCreatePS  Creates a normal or a micro presentation space. A normal
  18823.    presentation space is required if your application's output is sent to
  18824.    more than one device or if your application's output is complex. A micro
  18825.    presentation space is more useful if your application's output is sent to
  18826.    a single device and if the output is not complex.
  18827.  
  18828.    GpiDestroyPS  Destroys a presentation space created by the GpiCreatePS
  18829.    function. Do not use this function to destroy a presentation space that
  18830.    was retrieved by calling the WinGetPS or WinBeginPaint function.
  18831.  
  18832.    GpiQueryPS  Retrieves the dimensions of the presentation page.
  18833.  
  18834.    GpiResetPS  Resets the attributes in a presentation space to one of the
  18835.    following states:
  18836.  
  18837.    ■  The original state of the presentation space.
  18838.  
  18839.    ■  The original state with one exception: Any resources such as regions,
  18840.       loaded color tables, or loaded fonts are saved and will not be
  18841.       destroyed.
  18842.  
  18843.    ■  The state of the presentation space prior to the creation of any
  18844.       retained segments.
  18845.  
  18846.    GpiRestorePS  Restores the attributes of a presentation space that were
  18847.    saved by calling the GpiSavePS function.
  18848.  
  18849.    GpiSavePS  Saves the attributes of a presentation space onto a special
  18850.    stack.
  18851.  
  18852.  
  18853.  
  18854.  ────────────────────────────────────────────────────────────────────────────
  18855.  Chapter 31  Coordinate Spaces and Transformations
  18856.  
  18857.         31.1    Introduction
  18858.         31.2    About Coordinate Spaces and Transformations
  18859.             31.2.1    Single-Coordinate-Space Systems
  18860.             31.2.2    Multiple-Coordinate-Space Systems
  18861.             31.2.3    Transformations
  18862.                 31.2.3.1   The MATRIXLF Structure and Fixed Values
  18863.                 31.2.3.2   Scaling Transformations
  18864.                 31.2.3.3   Rotation Transformations
  18865.                 31.2.3.4   Translation Transformations
  18866.                 31.2.3.5   Shear Transformations
  18867.                 31.2.3.6   Reflection Transformations
  18868.                 31.2.3.7   Combining Transformations
  18869.                 31.2.3.8   Round-off Error
  18870.             31.2.4    World Coordinate Space
  18871.             31.2.5    Model Coordinate Space
  18872.                 31.2.5.1   World-to-Model-Space Transformations
  18873.             31.2.6    Page Coordinate Space
  18874.                 31.2.6.1   Model-to-Page-Space Transformations
  18875.             31.2.7    Device Coordinate Space
  18876.                 31.2.7.1   Page-to-Device-Space Transformations
  18877.         31.3    Using Coordinate Spaces and Transformations
  18878.             31.3.1    Setting Convenient Drawing Units
  18879.             31.3.2    Zooming a Picture
  18880.             31.3.3    Rotating an Object in a Picture
  18881.         31.4    Summary
  18882.  
  18883.  
  18884.  
  18885.  31.1  Introduction
  18886.  
  18887.    This chapter describes coordinate spaces and transformations. You should
  18888.    also be familiar with the following topics:
  18889.  
  18890.    ■  Presentation spaces
  18891.  
  18892.    ■  Device contexts
  18893.  
  18894.    ■  Retained drawing
  18895.  
  18896.    ■  Clipping
  18897.  
  18898.  
  18899.  31.2  About Coordinate Spaces and Transformations
  18900.  
  18901.    A coordinate space is a two-dimensional set of points. A point is the
  18902.    smallest definable location in a coordinate space. There are four
  18903.    coordinate spaces in Microsoft Operating System/2 Presentation Manager:
  18904.  
  18905.    ■  World coordinate space
  18906.  
  18907.    ■  Model coordinate space
  18908.  
  18909.    ■  Page coordinate space
  18910.  
  18911.    ■  Device coordinate space
  18912.  
  18913.    A coordinate system is a means of specifying the location of a point in a
  18914.    coordinate space. For each of the four coordinate spaces in MS OS/2, there
  18915.    is a corresponding coordinate system. The four coordinate systems for MS
  18916.    OS/2 are two-dimensional systems with x- and y-axes, an origin, and
  18917.    dimensions. The x-axis extends horizontally across the system; the y-axis,
  18918.    vertically across the system. The origin is located at the intersection of
  18919.    the x- and y-axes and lies at the center of the system. The world, model,
  18920.    and page coordinate systems' x- and y-axes extend from 0 to 134,217,727 in
  18921.    the positive direction and from 0 to -134,217,728 in the negative
  18922.    direction. The device coordinate system's x- and y-axes extend from 0 to
  18923.    32,767 in the positive direction and from 0 to -32,768 in the negative
  18924.    direction. Figure 31.1 shows the device coordinate system, with its
  18925.    origin, axes, and dimensions:
  18926.  
  18927.    ┌────────────────────────────────────────────────────────────────────────┐
  18928.    │ Figure 31.1 can be found in Section 31.2 of the printed manual.        │
  18929.    └────────────────────────────────────────────────────────────────────────┘
  18930.  
  18931.    Figure 31.1  Device Coordinate System
  18932.  
  18933.    When you specify a coordinate in MS OS/2, the values you use are long
  18934.    integers (32-bits).
  18935.  
  18936.  31.2.1  Single-Coordinate-Space Systems
  18937.  
  18938.    All graphics systems use at least one coordinate space and system to
  18939.    generate output on a video display or printer. The simplest systems use a
  18940.    single coordinate space, whose points are the pels on the display. In
  18941.    single-coordinate-space, or single-space, systems, one corner of the
  18942.    display (usually the lower-left) corresponds to the origin of the
  18943.    coordinate system; the positive x-axis extends from the origin to the
  18944.    lower-right corner of the display; and the positive y-axis extends from
  18945.    the origin to the upper-left corner of the display. Figure 31.2 shows how
  18946.    the axes correspond to the display:
  18947.  
  18948.    ┌────────────────────────────────────────────────────────────────────────┐
  18949.    │ Figure 31.2 can be found in Section 31.2.1 of the printed manual.      │
  18950.    └────────────────────────────────────────────────────────────────────────┘
  18951.  
  18952.    Figure 31.2  Video Display and Single-Coordinate-Space System
  18953.  
  18954.    When drawing, applications written for single-coordinate-space systems
  18955.    must specify distances and locations in pels. For example, when the
  18956.    application draws a straight line, it specifies starting and ending points
  18957.    in pels. So if the display measures 100 pels by 100 pels and the
  18958.    application supplies a line-drawing command with a starting point of (0,0)
  18959.    and an ending point of (50,50), the line shown in Figure 31.3 would
  18960.    appear on the display:
  18961.  
  18962.    ┌────────────────────────────────────────────────────────────────────────┐
  18963.    │ Figure 31.3 can be found in Section 31.2.1 of the printed manual.      │
  18964.    └────────────────────────────────────────────────────────────────────────┘
  18965.  
  18966.    Figure 31.3  Diagonal Line in a Single-Coordinate-Space System
  18967.  
  18968.    There are two fundamental drawbacks to a graphics system with a single
  18969.    coordinate space:
  18970.  
  18971.    ■  Any application written for the graphics system is device dependent.
  18972.  
  18973.    ■  It is difficult to draw output in convenient units like centimeters,
  18974.       feet, inches, or twips.
  18975.  
  18976.    Since the coordinate space in a simple system is made up of pels, and
  18977.    since the shape of pels varies from device to device, the output from an
  18978.    application written for one device may look different on another device.
  18979.    Figure 31.4 demonstrates this principle: The display on the left measures
  18980.    100 pels by 100 pels, the display on the right 640 pels by 350 pels. In
  18981.    each case, a rectangle has been drawn with a lower-left corner at (10,10)
  18982.    and an upper-right corner at (90,90). Note the different shapes of each
  18983.    rectangle.
  18984.  
  18985.    ┌────────────────────────────────────────────────────────────────────────┐
  18986.    │ Figure 31.4 can be found in Section 31.2.1 of the printed manual.      │
  18987.    └────────────────────────────────────────────────────────────────────────┘
  18988.  
  18989.    Figure 31.4  One Rectangle Displayed on Two Different Devices
  18990.  
  18991.    Single-coordinate-space systems are difficult to use for drawing or
  18992.    computer-aided-design (CAD) applications since these applications work in
  18993.    units of inches, feet, meters, and so on. For example, to draw a simple
  18994.    horizontal line that is 1 inch long, you must perform the following tasks:
  18995.  
  18996.    1.  Determine the width (in inches) of the video display or printer paper.
  18997.  
  18998.    2.  Determine the width (in pels) of the video display.
  18999.  
  19000.    3.  Divide the width in pels by the width in inches to determine the ratio
  19001.        of pels to inches.
  19002.  
  19003.    4.  Using this ratio, perform the line-drawing command.
  19004.  
  19005.  31.2.2  Multiple-Coordinate-Space Systems
  19006.  
  19007.    Single-coordinate-space systems do not provide the flexibility that most
  19008.    applications and application developers need. An application written for a
  19009.    single-space system will create meaningful output only on a device on
  19010.    which the pels are a certain width and height. Since spreadsheet,
  19011.    word-processing, desktop-publishing, and CAD applications normally draw
  19012.    output on video displays and printers or plotters, it is obvious that a
  19013.    single-space system is impractical. In Presentation Manager, however, you
  19014.    can avoid the limitations of a single-coordinate-space system by using
  19015.    additional coordinate spaces and other operations, called transformations.
  19016.    Transformations require two coordinate spaces──a source coordinate space
  19017.    and a target coordinate space.
  19018.  
  19019.  31.2.3  Transformations
  19020.  
  19021.    When copying objects from one coordinate space to another, MS OS/2 applies
  19022.    one or more of five operations, called transformations, to the points that
  19023.    define the object. These five transformations──scaling, rotation,
  19024.    translation, shear, and reflection──enable you to write applications that
  19025.    can do the following tasks:
  19026.  
  19027.    ■  Run on a variety of video displays, printers, and plotters.
  19028.  
  19029.    ■  Use convenient units of measurement (centimeters, inches, feet,
  19030.       kilometers, miles, etc.).
  19031.  
  19032.    ■  Scroll and zoom pictures.
  19033.  
  19034.    ■  Rotate and scale objects in pictures.
  19035.  
  19036.    ■  Shift the positions of objects in pictures.
  19037.  
  19038.    ■  Display mirror images of objects in pictures.
  19039.  
  19040.    ■  Display sheared objects in pictures.
  19041.  
  19042.    When your application copies an object from the source coordinate space to
  19043.    the target coordinate space, the five transformations work as follows:
  19044.  
  19045.    ■  The scaling transformation makes the object look bigger or smaller.
  19046.  
  19047.    ■  The rotation transformation rotates the object.
  19048.  
  19049.    ■  The translation transformation shifts the object with respect to the
  19050.       origin of the coordinate system.
  19051.  
  19052.    ■  The shear transformation rotates either all the vertical or all the
  19053.       horizontal lines in an object.
  19054.  
  19055.    ■  The reflection transformation creates a mirror image of an object with
  19056.       respect to the x- or y-axis.
  19057.  
  19058.    Presentation Manager uses three-by-three matrices to represent the three
  19059.    transformations. For any point (x,y) in a source coordinate space, you can
  19060.    determine the corresponding point (x',y') in the target coordinate space
  19061.    by using the following matrix multiplication:
  19062.  
  19063.              ┌               ┐
  19064.              │ M11  M12  M13 │
  19065.              │               │
  19066.    [x y 1] X │ M21  M22  M23 │ = [x' y' 1]
  19067.              │               │
  19068.              │ M31  M32  M33 │
  19069.              └               ┘
  19070.  
  19071.    In the following example, the transformations are set to unity
  19072.    (represented by the identity matrix). In such cases, the original point in
  19073.    the source coordinate space is always identical to its corresponding point
  19074.    in the target coordinate space.
  19075.  
  19076.                ┌         ┐
  19077.                │ 1  0  0 │
  19078.                │         │
  19079.    [3 100 1] X │ 0  1  0 │ = [3 100 1]
  19080.                │         │
  19081.                │ 0  0  1 │
  19082.                └         ┘
  19083.  
  19084.    In the next example, the identity matrix is replaced with a new matrix
  19085.    that translates the point when the point is copied from the source
  19086.    coordinate space to the target coordinate space:
  19087.  
  19088.                ┌            ┐
  19089.                │  1   0   0 │
  19090.                │            │
  19091.    [3 100 1] X │  0   1   0 │ = [100 3 1]
  19092.                │            │
  19093.                │ 97  -97  1 │
  19094.                └            ┘
  19095.  
  19096.    In this example, the point (3,100) was translated to (100,3) by exchanging
  19097.    the values of M31 and M32.
  19098.  
  19099.    31.2.3.1  The MATRIXLF Structure and Fixed Values
  19100.  
  19101.    A special data structure called the MATRIXLF structure contains nine
  19102.    fields that correspond to the nine elements in a three-by-three
  19103.    transformation matrix. Five of these fields are 32-bit long integer
  19104.    values; the remaining four are special 32-bit fixed values.
  19105.  
  19106.    A fixed value is a binary representation of a floating-point number. A
  19107.    fixed value has two parts: the high-order 16-bits and the low-order
  19108.    16-bits. The high-order 16-bits contain a signed integer in the range
  19109.    -32,768 through 32,767; the low-order 16-bits contain the numerator of a
  19110.    fraction, in the range 0 through 65,535 (the denominator for this fraction
  19111.    is 65,536). Figure 31.5 shows the two parts of a fixed value:
  19112.  
  19113.    ┌────────────────────────────────────────────────────────────────────────┐
  19114.    │ Figure 31.5 can be found in Section 31.2.3.1 of the printed manual.    │
  19115.    └────────────────────────────────────────────────────────────────────────┘
  19116.  
  19117.    Figure 31.5  Fixed Value
  19118.  
  19119.    You use fixed values to store the sines and cosines of angles for the
  19120.    rotation transformation. You also use fixed values to store scaling
  19121.    factors for the scaling transformation. To store the cosine of 60 degrees
  19122.    in a fixed value, you would multiply 0.5 by 65,536. The result, 32,768, is
  19123.    the value you would assign to a fixed value in the MATRIXLF structure. To
  19124.    store a scaling factor of, for example, 3 in a fixed value, you would
  19125.    multiply 3 by 65,536. Again, the result, 196,608, is the value you would
  19126.    assign to a fixed value in the MATRIXLF structure.
  19127.  
  19128.    The MAKEFIXED macro provides a quick and convenient method for determining
  19129.    fixed values. This macro requires two arguments: The first is the integer
  19130.    part of the fixed value, and the second is the fraction part of the fixed
  19131.    value. In the following example, MAKEFIXED is used to determine the
  19132.    fixed-value equivalent of 1-and-1/8:
  19133.  
  19134.    matlf.fxM11 = MAKEFIXED(1, 8192)
  19135.  
  19136.    The first argument, 1, is the integer part of the fixed value. The second
  19137.    argument, 8192, is the result of multiplying 65,536 by 1/8.
  19138.  
  19139.    The following type definition shows each of the fields in the MATRIXLF
  19140.    structure. Fields with an fx prefix contain fixed values; fields with an l
  19141.    prefix contain long values.
  19142.  
  19143.    typedef struct _MATRIXLF {     /* matlf */
  19144.        FIXED fxM11;      /* M11 */
  19145.        FIXED fxM12;      /* M12 */
  19146.        LONG  lM13;       /* M13 */
  19147.        FIXED fxM21;      /* M21 */
  19148.        FIXED fxM22;      /* M22 */
  19149.        LONG  lM23;       /* M23 */
  19150.        LONG  lM31;       /* M31 */
  19151.        LONG  lM32;       /* M32 */
  19152.        LONG  lM33;       /* M33 */
  19153.    } MATRIXLF;
  19154.  
  19155.    31.2.3.2  Scaling Transformations
  19156.  
  19157.    When you scale an object by using the scaling transformation, the matrix
  19158.    element M11 contains the horizontal scaling component (horz), and the
  19159.    matrix element M22 contains the vertical scaling component (vert):
  19160.  
  19161.    ┌               ┐
  19162.    │ horz   0    0 │
  19163.    │               │
  19164.    │   0  vert   0 │
  19165.    │               │
  19166.    │   0    0    1 │
  19167.    └               ┘
  19168.  
  19169.    31.2.3.3  Rotation Transformations
  19170.  
  19171.    When you rotate an object clockwise by using the rotation transformation,
  19172.    the matrix element M11 contains the cosine of the rotation angle; M12, the
  19173.    negative sine of the rotation angle; M21, the sine of the rotation angle;
  19174.    and M22, the cosine of the rotation angle:
  19175.  
  19176.    ┌               ┐
  19177.    │  cos -sin   0 │
  19178.    │               │
  19179.    │  sin  cos   0 │
  19180.    │               │
  19181.    │   0    0    1 │
  19182.    └               ┘
  19183.  
  19184.    Remember that MS OS/2 applies a transformation to all points in the source
  19185.    coordinate space. This means that unless an object is drawn about the
  19186.    origin of the source coordinate space, translation will occur when the
  19187.    object is rotated or scaled. Figure 31.6 shows a triangle, first in its
  19188.    source coordinate space and then in its target coordinate space, rotated
  19189.    45 degrees clockwise. Note the translation with respect to the origin.
  19190.  
  19191.    ┌────────────────────────────────────────────────────────────────────────┐
  19192.    │ Figure 31.6 can be found in Section 31.2.3.3 of the printed manual.    │
  19193.    └────────────────────────────────────────────────────────────────────────┘
  19194.  
  19195.    Figure 31.6  Rotating an Object
  19196.  
  19197.    31.2.3.4  Translation Transformations
  19198.  
  19199.    When you translate an object by using the translation transformation, the
  19200.    matrix element M31 contains the horizontal translation component, and the
  19201.    matrix element M32 contains the vertical translation component, as
  19202.    follows:
  19203.  
  19204.    ┌               ┐
  19205.    │   1    0    0 │
  19206.    │               │
  19207.    │   0    1    0 │
  19208.    │               │
  19209.    │ horz  vert  1 │
  19210.    └               ┘
  19211.  
  19212.    31.2.3.5  Shear Transformations
  19213.  
  19214.    There are two shear transformations: vertical and horizontal. When an
  19215.    application uses the vertical shear transformation, it affects only the
  19216.    vertical lines in the object. In the matrix of the vertical shear
  19217.    transformation, the element M21 contains a horizontal shear component, and
  19218.    the element M22 contains a vertical shear component, as follows:
  19219.  
  19220.    ┌               ┐
  19221.    │   1    0    0 │
  19222.    │               │
  19223.    │ horz  vert  0 │
  19224.    │               │
  19225.    │   0    0    1 │
  19226.    └               ┘
  19227.  
  19228.    When an application uses the horizontal shear transformation, it affects
  19229.    only the horizontal lines in the object. In the matrix of the horizontal
  19230.    shear transformation, the element M11 contains a horizontal shear
  19231.    component, and the matrix element M12 contains a vertical shear component,
  19232.    as follows:
  19233.  
  19234.    ┌               ┐
  19235.    │ horz   0    0 │
  19236.    │               │
  19237.    │ vert   1    0 │
  19238.    │               │
  19239.    │   0    0    1 │
  19240.    └               ┘
  19241.  
  19242.    If an application shears an object that contains two orthogonal vectors
  19243.    (two perpendicular lines), the vectors will no longer be orthogonal.
  19244.  
  19245.    31.2.3.6  Reflection Transformations
  19246.  
  19247.    The reflection transformation creates a mirror image of an object with
  19248.    respect to the x- or the y-axis. The matrix element M11 contains the
  19249.    horizontal reflection component, which causes reflection about the y-axis.
  19250.    The matrix element M22 contains the vertical reflection component, which
  19251.    causes reflection about the x-axis. The reflection components are always
  19252.    negative.
  19253.  
  19254.    ┌               ┐
  19255.    │ horz   0    0 │
  19256.    │               │
  19257.    │   0   vert  0 │
  19258.    │               │
  19259.    │   0    0    1 │
  19260.    └               ┘
  19261.  
  19262.    31.2.3.7  Combining Transformations
  19263.  
  19264.    Each time you call a Gpi function that sets a transformation, you can
  19265.    specify whether you want to combine it with existing transformations and,
  19266.    if so, whether you want MS OS/2 to apply the existing transformation
  19267.    before or after the new transformation.
  19268.  
  19269.    If you want MS OS/2 to replace any existing transformations with the new
  19270.    transformation, use the TRANSFORM_REPLACE flag when you set the
  19271.    transformation. If you want MS OS/2 to apply the new transformation before
  19272.    it applies the existing transformation, use the TRANSFORM_PREEMPT
  19273.    flag when you set the new transformation. If you want MS OS/2 to apply
  19274.    the new transformation after it applies the existing transformation, use
  19275.    the TRANSFORM_ADD flag when you set the new transformation.
  19276.  
  19277.    31.2.3.8  Round-off Error
  19278.  
  19279.    Whenever you use transformations in your application, you should check for
  19280.    any round-off error that occurs after multiple scaling, rotation, shear,
  19281.    or reflection transformations. For example, if your application uses a
  19282.    rotation transformation to rotate the hands of a clock, the accuracy of
  19283.    the clock will diminish due to rounding off after the transformation. In
  19284.    order to prevent the loss of accuracy, your application should check the
  19285.    results of each transformation.
  19286.  
  19287.  31.2.4  World Coordinate Space
  19288.  
  19289.    A world coordinate space, or world space, is where all Presentation
  19290.    Manager drawing operations begin. Whenever you draw with one of the line,
  19291.    arc, character, area, or image primitives, the coordinates that you
  19292.    specify are world coordinates. World-coordinate units can be inches,
  19293.    fractions of an inch, meters, centimeters, miles, kilometers, yards, and
  19294.    so on.
  19295.  
  19296.    If your application uses the retained-drawing mode to store subpictures in
  19297.    chained segments, MS OS/2 assigns a new world space to each segment. In
  19298.    other words, if the segment attribute is set to ATTR_CHAINED and you call
  19299.    the GpiOpenSegment function, the subpicture associated with that segment
  19300.    is drawn in a new world space. The following illustration shows the
  19301.    subpictures in four chained segments. Each subpicture is drawn in its own
  19302.    world space.
  19303.  
  19304.    ┌────────────────────────────────────────────────────────────────────────┐
  19305.    │ Figure 31.7 can be found in Section 31.2.4 of the printed manual.      │
  19306.    └────────────────────────────────────────────────────────────────────────┘
  19307.  
  19308.    Figure 31.7  Subpictures in Four Chained Segments in World Space
  19309.  
  19310.    There is a special clipping area called a clip path that you can use to
  19311.    define a part of a world space that you want to copy into the next
  19312.    coordinate space (the model space). The advantage of a clip path is that
  19313.    it is the only clipping region that can be nonrectangular. Its edges can
  19314.    include arcs, curves, and straight lines. The coordinates that define the
  19315.    dimensions and shape of a clip path are always world coordinates. You can
  19316.    create a clip path by calling the GpiBeginPath, GpiEndPath, and
  19317.    GpiSetClipPath functions and one or more Gpi primitives that define the
  19318.    dimensions and location of the path. For more information, see Chapter
  19319.    40, "Clipping."
  19320.  
  19321.  31.2.5  Model Coordinate Space
  19322.  
  19323.    A model coordinate space, or model space, is where you build a model, or a
  19324.    complete picture, from subpictures in one or more world spaces. You can
  19325.    have more than one model space, each corresponding to a particular model.
  19326.    Figure 31.8 shows two model spaces that were defined by calls to the
  19327.    GpiSetSegmentTransformMatrix function:
  19328.  
  19329.    ┌────────────────────────────────────────────────────────────────────────┐
  19330.    │ Figure 31.8 can be found in Section 31.2.5 of the printed manual.      │
  19331.    └────────────────────────────────────────────────────────────────────────┘
  19332.  
  19333.    Figure 31.8  Two Model Spaces
  19334.  
  19335.    There is a special clipping area called a viewing limit that you can use
  19336.    to define a part of a model space that you want to copy into the next
  19337.    coordinate space (the page space). A viewing limit is always rectangular,
  19338.    and the coordinates that define its location and dimensions are always
  19339.    model coordinates. You can set the viewing limit by calling the
  19340.    GpiSetViewingLimit function. Figure 31.9 shows a viewing limit set in a
  19341.    model space; the dashed line represents the viewing-limit border:
  19342.  
  19343.    ┌────────────────────────────────────────────────────────────────────────┐
  19344.    │ Figure 31.9 can be found in Section 31.2.5 of the printed manual.      │
  19345.    └────────────────────────────────────────────────────────────────────────┘
  19346.  
  19347.    Figure 31.9  Viewing Limit in Model Space
  19348.  
  19349.    31.2.5.1  World-to-Model-Space Transformations
  19350.  
  19351.    There are three transformations that operate between the world space and
  19352.    the model space:
  19353.  
  19354.    ■  The model transformation
  19355.  
  19356.    ■  The segment transformation
  19357.  
  19358.    ■  The instance transformation
  19359.  
  19360.    Model Transformations
  19361.  
  19362.    Model transformations are used for retained- or nonretained-drawing
  19363.    operations. This means model transformations affect the output from the
  19364.    GpiDrawChain, GpiDrawFrom, and GpiDrawSegment functions and any of the Gpi
  19365.    functions that occur outside of a retained-drawing segment.
  19366.  
  19367.    You can determine the values for the current model transformation by
  19368.    calling the GpiQueryModelTransformMatrix function, which returns the model
  19369.    transformation's scaling, rotation, and translation values in a
  19370.    three-by-three matrix. Similarly, you can set these values by calling the
  19371.    GpiSetModelTransformMatrix function, passing it the scaling, rotation, and
  19372.    translation values in a three-by-three matrix.
  19373.  
  19374.    In a retained-graphics application, you could use a model transformation
  19375.    to rotate, scale, or translate parts of a subpicture. You can set and
  19376.    reset the model transformation any number of times within a
  19377.    retained-drawing segment. Figure 31.10 shows part of a floor plan as a
  19378.    single subpicture stored in a retained segment. Each chair was drawn by
  19379.    setting a new translation component in the model transformation before
  19380.    calling the GpiBox function.
  19381.  
  19382.    ┌────────────────────────────────────────────────────────────────────────┐
  19383.    │ Figure 31.10 can be found in Section 31.2.5.1 of the printed manual.   │
  19384.    └────────────────────────────────────────────────────────────────────────┘
  19385.  
  19386.    Figure 31.10  Retained Subpicture Drawn Using Model Transformations
  19387.  
  19388.    Segment Transformations
  19389.  
  19390.    Segment transformations alter retained-drawing output. Unlike a model
  19391.    transformation, which can be set and reset within a segment bracket, a
  19392.    segment transformation must be set outside of a segment bracket.
  19393.  
  19394.    You can determine the values for the current segment transformation by
  19395.    calling the GpiQuerySegmentTransformMatrix function, which returns the
  19396.    scaling, rotation, and translation values in a three-by-three matrix and
  19397.    passes a segment identifier. Similarly, you can set the values for the
  19398.    segment transformation by calling the GpiSetSegmentTransformMatrix
  19399.    function, passing it the necessary values (in a three-by-three matrix) and
  19400.    a segment identifier.
  19401.  
  19402.    The user of a CAD or drafting application may need to zoom in on part of a
  19403.    subpicture that was clipped in world space by a clip path. The application
  19404.    could perform this operation by setting the segment transformation for
  19405.    that particular subpicture after setting the clip path. Figure 31.11
  19406.    shows a subpicture in world space that contains a clip path; the dashed
  19407.    line represents the outline of the clip path:
  19408.  
  19409.    ┌────────────────────────────────────────────────────────────────────────┐
  19410.    │ Figure 31.11 can be found in Section 31.2.5.1 of the printed manual.   │
  19411.    └────────────────────────────────────────────────────────────────────────┘
  19412.  
  19413.    Figure 31.11  Clip Path in World Space
  19414.  
  19415.    Figure 31.12 shows a zoomed view (in model space) of the clipped part of
  19416.    the subpicture:
  19417.  
  19418.    ┌────────────────────────────────────────────────────────────────────────┐
  19419.    │ Figure 31.12 can be found in Section 31.2.5.1 of the printed manual.   │
  19420.    └────────────────────────────────────────────────────────────────────────┘
  19421.  
  19422.    Figure 31.12  Scaling the Clipped Part of a Subpicture in Model Space
  19423.  
  19424.    Instance Transformations
  19425.  
  19426.    Instance transformations alter the retained-drawing output from special
  19427.    segments referred to as "called" segments. A called segment usually
  19428.    contains a subpicture that is duplicated several times in other
  19429.    subpictures. The instance transformation positions, sizes, and rotates the
  19430.    subpicture each time it is duplicated. You can set the values for the
  19431.    instance transformation by calling the GpiCallSegmentMatrix function,
  19432.    passing it the transformation values (in a three-by-three matrix) and a
  19433.    segment identifier.
  19434.  
  19435.  31.2.6  Page Coordinate Space
  19436.  
  19437.    A page coordinate space, or page space, is where a complete picture is
  19438.    prepared for viewing in a window on a video display, printing on a page of
  19439.    printer paper, or plotting on a page of plotter paper. Page-coordinate
  19440.    units can be increments of an inch, a meter, several pels, a twip, or some
  19441.    arbitrary value. (A twip is a standard unit in the typesetting industry
  19442.    that measures 1/1440 of an inch.) You specify the units used for page
  19443.    coordinates when you call the GpiCreatePS function and create a
  19444.    presentation space.
  19445.  
  19446.    If your application uses retained-drawing mode, the picture in page space
  19447.    will contain parts of models (or pictures) from each of the model spaces
  19448.    that have not been clipped; the picture will also contain any additional
  19449.    graphics-primitive output (that has not been clipped) that the application
  19450.    generated in nonretained-drawing mode. If your application uses
  19451.    nonretained-drawing mode, the picture in page space will contain all of
  19452.    the graphics-primitive output that has not been clipped.
  19453.  
  19454.    In the page space, there is a special clipping area called a graphics
  19455.    field that you can use to define the part of the page space that you want
  19456.    to copy into the next coordinate space (the device space). The graphics
  19457.    field is always rectangular. The coordinates that define the location and
  19458.    dimensions of the graphics field are always page coordinates.
  19459.  
  19460.    31.2.6.1  Model-to-Page-Space Transformations
  19461.  
  19462.    There are two transformations that operate between the model space and the
  19463.    page space:
  19464.  
  19465.    ■  The default viewing transformation
  19466.  
  19467.    ■  The viewing transformation
  19468.  
  19469.    Default Viewing Transformations
  19470.  
  19471.    Default viewing transformations scroll or zoom pictures in a window on a
  19472.    video display or on a page of printer or plotter paper. You can determine
  19473.    the current values for the default viewing transformation by calling the
  19474.    GpiQueryDefaultViewMatrix function, which returns the
  19475.    default-viewing-transformation values in a three-by-three matrix. You can
  19476.    set these values by calling the GpiSetDefaultViewMatrix function and
  19477.    passing it the transformation values (in a three-by-three matrix).
  19478.  
  19479.    Viewing Transformations
  19480.  
  19481.    Viewing transformations create pictures from multiple model spaces. For
  19482.    example, you could copy a picture from a model space to a page space,
  19483.    leaving all parts of the picture intact. Then you could copy a part of
  19484.    another picture from a second model space by using a viewing limit to
  19485.    define the part of the picture that you want to copy and then using the
  19486.    viewing transformation to scale and translate that part. You can determine
  19487.    the current values for the viewing transformation by calling the
  19488.    GpiQueryViewingTransformMatrix function, which returns the values for the
  19489.    viewing transformation in a three-by-three matrix. You can set the values
  19490.    by calling the GpiSetViewingTransformMatrix function and passing it the
  19491.    transformation values (in a three-by-three matrix).
  19492.  
  19493.  31.2.7  Device Coordinate Space
  19494.  
  19495.    A device coordinate space, or device space, is the final space in which a
  19496.    picture is drawn before it appears in a window or on the page of a printer
  19497.    or plotter. Device-coordinate units are pels if the page units are pels,
  19498.    twips, increments of an inch, or increments of a meter. Device-coordinate
  19499.    units are arbitrary if the page units are arbitrary.
  19500.  
  19501.    31.2.7.1  Page-to-Device-Space Transformations
  19502.  
  19503.    There is one transformation between the page space and the device
  19504.    space──it is called the device transformation. Unlike the other
  19505.    transformations that rotate, scale, and translate objects, the device
  19506.    transformation only scales and translates objects; also, instead of a
  19507.    three-by-three matrix, the device transformation uses two rectangles. (The
  19508.    location of the first rectangle is fixed; the location of the second
  19509.    rectangle is movable.) These two rectangles are the presentation page and
  19510.    the page viewport.
  19511.  
  19512.    Presentation Pages
  19513.  
  19514.    A presentation page is a rectangle in a page space. Its lower-left corner
  19515.    is always positioned at the origin of the page space. You can determine
  19516.    the dimensions of the presentation page by calling the GpiQueryPS
  19517.    function, which returns a pointer to a SIZEL structure that contains the
  19518.    page dimensions. If you specify arbitrary page units when you create a
  19519.    presentation space, you must also specify the dimensions of the
  19520.    presentation page. If you specify any other page unit, MS OS/2
  19521.    automatically sets the dimensions of the presentation page for you. Figure
  19522.    31.13 shows a presentation page:
  19523.  
  19524.    ┌────────────────────────────────────────────────────────────────────────┐
  19525.    │ Figure 31.13 can be found in Section 31.2.7.1 of the printed manual.   │
  19526.    └────────────────────────────────────────────────────────────────────────┘
  19527.  
  19528.    Figure 31.13  Presentation Page in Page Space
  19529.  
  19530.    Page Viewports
  19531.  
  19532.    A page viewport is a rectangle in a device space. MS OS/2 always copies
  19533.    the presentation-page rectangle into the page-viewport rectangle. You can
  19534.    determine the current dimensions of the page viewport by calling the
  19535.    GpiQueryPageViewport function, which returns a pointer to a RECTL
  19536.    structure that contains the coordinates of the viewport. You can set the
  19537.    location and dimensions of the page viewport by calling the
  19538.    GpiSetPageViewport function and passing it a pointer to a RECTL structure
  19539.    that contains the new values. Figure 31.14 shows the object from Figure
  19540.    31.13 as it would appear in the page viewport:
  19541.  
  19542.    ┌────────────────────────────────────────────────────────────────────────┐
  19543.    │ Figure 31.14 can be found in Section 31.2.7.1 of the printed manual.   │
  19544.    └────────────────────────────────────────────────────────────────────────┘
  19545.  
  19546.    Figure 31.14  Page Viewport in Device Space
  19547.  
  19548.    The ratio of the page width to the page-viewport width defines a
  19549.    horizontal scaling factor, and the ratio of the page height to the
  19550.    viewport height defines a vertical scaling factor. In Figure 31.15, the
  19551.    presentation page measures 100 centimeters by 200 centimeters, and the
  19552.    page viewport measures 200 pels by 400 pels (where each pel measures 0.25
  19553.    centimeters by 0.5 centimeters):
  19554.  
  19555.    ┌────────────────────────────────────────────────────────────────────────┐
  19556.    │ Figure 31.15 can be found in Section 31.2.7.1 of the printed manual.   │
  19557.    └────────────────────────────────────────────────────────────────────────┘
  19558.  
  19559.    Figure 31.15  Determining Scaling Factors
  19560.  
  19561.    The image in the page space was not scaled in the device space since each
  19562.    centimeter in the page space mapped to a centimeter in the device space.
  19563.  
  19564.    Figure 31.16 shows the effect of shifting the page viewport in the device
  19565.    space. Note the translation that this shift causes.
  19566.  
  19567.    ┌────────────────────────────────────────────────────────────────────────┐
  19568.    │ Figure 31.16 can be found in Section 31.2.7.1 of the printed manual.   │
  19569.    └────────────────────────────────────────────────────────────────────────┘
  19570.  
  19571.    Figure 31.16  Translating the Page Viewport in Device Space
  19572.  
  19573.  
  19574.  31.3  Using Coordinate Spaces and Transformations
  19575.  
  19576.    You can perform the following tasks by using the coordinate-space and
  19577.    transformation functions:
  19578.  
  19579.    ■  Set an application's drawing units to convenient units.
  19580.  
  19581.    ■  Scroll and zoom a picture.
  19582.  
  19583.    ■  Rotate, scale, and shift an object in a picture.
  19584.  
  19585.  31.3.1  Setting Convenient Drawing Units
  19586.  
  19587.    You can use the GpiCreatePS function to set the device transformation so
  19588.    that it uses more convenient page units──for example, centimeters. Follow
  19589.    these steps:
  19590.  
  19591.    1.  If the output device is a screen, open a device context by calling the
  19592.        WinOpenWindowDC function. (If the output device is a printer or
  19593.        plotter, open a printer or plotter device context by calling the
  19594.        DevOpenDC function.)
  19595.  
  19596.    2.  Create a presentation space by calling the GpiCreatePS function,
  19597.        specifying low-metric page units and associating the device context
  19598.        with the presentation space.
  19599.  
  19600.    The following code fragment demonstrates these steps:
  19601.  
  19602.    HDC hdc;         /* device-context handle       */
  19603.    HWND hwndClient; /* client-window handle        */
  19604.    SIZEL sizlPage;  /* presentation-page rectangle */
  19605.    HAB hab;         /* anchor-block handle         */
  19606.    HPS hps;         /* presentation-space handle   */
  19607.        .
  19608.        .
  19609.        .
  19610.    hdc = WinOpenWindowDC(hwndClient);
  19611.    sizlPage.cx = 0;
  19612.    sizlPage.cy = 0;
  19613.    hps = GpiCreatePS(hab,
  19614.        hdc,           /* device-context handle        */
  19615.        &sizlPage,     /* address of SIZEL structure   */
  19616.        PU_LOMETRIC    /* centimeters as page units    */
  19617.        | GPIA_ASSOC); /* associates window DC with PS */
  19618.  
  19619.  31.3.2  Zooming a Picture
  19620.  
  19621.    You can use the GpiSetDefaultViewMatrix function to zoom a picture. The
  19622.    following code fragment shows how to zoom out to 1/4 or 1/8 scale by using
  19623.    the default viewing transformation:
  19624.  
  19625.    /* Zoom 1/8 */
  19626.  
  19627.    matlfTransform.fxM11 = MAKEFIXED(0, 8192);
  19628.    matlfTransform.fxM12 = MAKEFIXED(0, 0);
  19629.    matlfTransform.lM13 = 0L;
  19630.    matlfTransform.fxM21 = MAKEFIXED(0, 0);
  19631.    matlfTransform.fxM22 = MAKEFIXED(0, 8192);
  19632.    matlfTransform.lM23 = 0L;
  19633.    matlfTransform.lM31 = 0L;
  19634.    matlfTransform.lM32 = 0L;
  19635.    matlfTransform.lM33 = 1L;
  19636.    GpiSetDefaultViewMatrix(hps, 9L, &matlfTransform, TRANSFORM_REPLACE);
  19637.    /* Zoom 1/4 */
  19638.  
  19639.    matlfTransform.fxM11 = MAKEFIXED(0, 1634);
  19640.    matlfTransform.fxM12 = MAKEFIXED(0, 0);
  19641.    matlfTransform.lM13 = 0L;
  19642.    matlfTransform.fxM21 = MAKEFIXED(0, 0);
  19643.    matlfTransform.fxM22 = MAKEFIXED(0, 1634);
  19644.    matlfTransform.lM23 = 0L;
  19645.    matlfTransform.lM31 = 0L;
  19646.    matlfTransform.lM32 = 0L;
  19647.    matlfTransform.lM33 = 1L;
  19648.    GpiSetDefaultViewMatrix(hps, 9L, &matlfTransform, TRANSFORM_REPLACE);
  19649.  
  19650.  31.3.3  Rotating an Object in a Picture
  19651.  
  19652.    To rotate an object in a world space by using the model transformation,
  19653.    you must perform the following steps:
  19654.  
  19655.    1.  Translate the object over the coordinate-space origin.
  19656.  
  19657.    2.  Rotate the object.
  19658.  
  19659.    3.  Translate the object back to its original position.
  19660.  
  19661.    4.  Draw the object.
  19662.  
  19663.    The following code fragment rotates a box 45 degrees:
  19664.  
  19665.    /* translates, rotates 45 degrees, translates */
  19666.  
  19667.    matlfTransform.fxM11 = MAKEFIXED(1, 0);
  19668.    matlfTransform.fxM12 = MAKEFIXED(0, 0);
  19669.    matlfTransform.lM13 = 0L;
  19670.    matlfTransform.fxM21 = MAKEFIXED(0, 0);
  19671.    matlfTransform.fxM22 = MAKEFIXED(1, 0);
  19672.    matlfTransform.lM23 = 0L;
  19673.    matlfTransform.lM31 = -150L;      /* translates box 150 units left */
  19674.    matlfTransform.lM32 = -150L;      /* translates box 150 units down */
  19675.    matlfTransform.lM33 = 1L;
  19676.    GpiSetModelTransformMatrix(hps, 9L, &matlfTransform,
  19677.        TRANSFORM_REPLACE);
  19678.  
  19679.    matlfTransform.fxM11 = MAKEFIXED(0, 46340);  /* cos 45 * 65536  */
  19680.    matlfTransform.fxM12 = -MAKEFIXED(0, 46340); /* -sin 45 * 65536 */
  19681.    matlfTransform.lM13 = 0L;
  19682.    matlfTransform.fxM21 = MAKEFIXED(0, 46350);  /* sin 45 * 65536  */
  19683.    matlfTransform.fxM22 = MAKEFIXED(0, 46340);  /* cos 45 * 65536  */
  19684.    matlfTransform.lM23 = 0L;
  19685.    matlfTransform.lM31 = 0L;
  19686.    matlfTransform.lM32 = 0L;
  19687.    matlfTransform.lM33 = 1L;
  19688.    GpiSetModelTransformMatrix(hps, 9L, &matlfTransform, TRANSFORM_ADD);
  19689.  
  19690.    matlfTransform.fxM11 = MAKEFIXED(1, 0);
  19691.    matlfTransform.fxM12 = MAKEFIXED(0, 0);
  19692.    matlfTransform.lM13 = 0L;
  19693.    matlfTransform.fxM21 = MAKEFIXED(0, 0);
  19694.    matlfTransform.fxM22 = MAKEFIXED(1, 0);
  19695.    matlfTransform.lM23 = 0L;
  19696.    matlfTransform.lM31 = 150L;    /* shifts back to original pos. */
  19697.    matlfTransform.lM32 = 150L;    /* shifts back to original pos. */
  19698.    matlfTransform.lM33 = 1L;
  19699.    GpiSetModelTransformMatrix(hps, 9L, &matlfTransform, TRANSFORM_ADD);
  19700.  
  19701.  
  19702.  31.4  Summary
  19703.  
  19704.    The following list summarizes the coordinate-space and transformation
  19705.    functions:
  19706.  
  19707.    GpiConvert  Determines the relationship between coordinates in two
  19708.    coordinate systems when a transformation is in effect. For example, if the
  19709.    page units are low English (0.01 inches) and an application is drawing in
  19710.    world units of feet, the application can call GpiConvert to determine the
  19711.    ratio of world units to page units and use this value to scale a picture
  19712.    down before printing.
  19713.  
  19714.    GpiQueryDefaultViewMatrix  Retrieves the scaling, rotation, and
  19715.    translation values for the default viewing transformation. You can use the
  19716.    default viewing transformation to scroll and zoom a picture in a page
  19717.    space.
  19718.  
  19719.    GpiQueryModelTransformMatrix  Retrieves the scaling, rotation, and
  19720.    translation values for the model transformation. You can use the model
  19721.    transformation to alter retained subpictures and nonretained pictures in a
  19722.    world space.
  19723.  
  19724.    GpiQueryPageViewport  Retrieves the dimensions of the page viewport. You
  19725.    can use the page viewport to shrink and expand pictures so that they fill
  19726.    the client area of a window as it shrinks and expands.
  19727.  
  19728.    GpiQuerySegmentTransformMatrix  Retrieves the scaling, rotation, and
  19729.    translation values for the segment transformation. You can use the segment
  19730.    transformation to alter subpictures stored in retained segments in a world
  19731.    space.
  19732.  
  19733.    GpiQueryViewingTransformMatrix  Retrieves the scaling, rotation, and
  19734.    translation values for the viewing transformation. You can use the viewing
  19735.    transformation with the viewing-limit clipping region to transform part of
  19736.    a picture in a model space and then copy it to a page space. You can also
  19737.    use the viewing transformation to transform a complete picture in a model
  19738.    space before copying it to a page space.
  19739.  
  19740.    GpiSetDefaultViewMatrix  Sets the scaling, rotation, and translation
  19741.    values for the default viewing transformation. You can use the default
  19742.    viewing transformation to scroll and zoom a picture in a page space.
  19743.  
  19744.    GpiSetModelTransformMatrix  Sets the scaling, rotation, and translation
  19745.    values for the model transformation. You can use the model transformation
  19746.    to alter retained subpictures and nonretained pictures in a world space.
  19747.  
  19748.    GpiSetPageViewport  Sets the dimensions of the page viewport. You can use
  19749.    the page viewport to shrink and expand pictures so that they fill the
  19750.    client area of a window as it shrinks and expands.
  19751.  
  19752.    GpiSetSegmentTransformMatrix  Sets the scaling, rotation, and translation
  19753.    values for the segment transformation. You can use the segment
  19754.    transformation to alter subpictures stored in retained segments in a world
  19755.    space.
  19756.  
  19757.    GpiSetViewingTransformMatrix  Sets the scaling, rotation, and translation
  19758.    values for the viewing transformation. You can use the viewing
  19759.    transformation and the viewing-limit clipping region to transform part of
  19760.    a picture in a model space and then copy it to a page space. You can also
  19761.    use the viewing transformation to transform a complete picture in a model
  19762.    space before copying it to a page space.
  19763.  
  19764.  
  19765.  
  19766.  ────────────────────────────────────────────────────────────────────────────
  19767.  Chapter 32  Line and Arc Primitives
  19768.  
  19769.         32.1    Introduction
  19770.         32.2    About Line and Arc Primitives
  19771.             32.2.1    Drawing Straight Lines
  19772.             32.2.2    Drawing Arcs
  19773.             32.2.3    Arc Parameters
  19774.             32.2.4    Line Attributes
  19775.         32.3    Using Line and Arc Primitives
  19776.             32.3.1    Drawing a Straight Line
  19777.             32.3.2    Creating a Rubber-Banding Effect with a Straight Line
  19778.             32.3.3    Drawing a Circle
  19779.             32.3.4    Drawing an Ellipse
  19780.             32.3.5    Drawing a Fillet
  19781.             32.3.6    Drawing a Spline
  19782.         32.4    Summary
  19783.  
  19784.  32.1  Introduction
  19785.  
  19786.    This chapter describes the line and arc primitives. You should also be
  19787.    familiar with the following topics:
  19788.  
  19789.    ■  Presentation spaces and device contexts
  19790.  
  19791.    ■  Coordinate spaces and transformations
  19792.  
  19793.    ■  Color and mix modes
  19794.  
  19795.  
  19796.  32.2  About Line and Arc Primitives
  19797.  
  19798.    Line and arc primitives are straight lines and arcs, respectively, that
  19799.    are drawn by line and arc functions. These primitives are useful for
  19800.    creating pictures that consist of objects such as polygons, circles,
  19801.    fillets, ellipses, and other geometric figures.
  19802.  
  19803.    Line and arc primitives are useful in many applications. Spreadsheet
  19804.    applications use them to construct pie charts, bar charts, and graphs.
  19805.    Simple drawing applications use them as drawing tools.
  19806.    Computer-aided-design (CAD) applications combine them to draw such complex
  19807.    pictures as schematic diagrams for electrical wiring, blueprints for a
  19808.    building site, and cross-sectional views of machinery. This broad range of
  19809.    pictures, from simple pie charts to complex blueprints, demonstrates how
  19810.    these primitives can benefit your applications. Figure 32.1 shows some
  19811.    sample illustrations that were drawn using line and arc functions:
  19812.  
  19813.    ┌────────────────────────────────────────────────────────────────────────┐
  19814.    │ Figure 32.1 can be found in Section 32.2 of the printed manual.        │
  19815.    └────────────────────────────────────────────────────────────────────────┘
  19816.  
  19817.    Figure 32.1  Sample Illustrations Using Line and Arc Functions
  19818.  
  19819.    In addition to the line and arc functions, there are numerous other
  19820.    functions that you can use to alter the appearance of lines and arcs drawn
  19821.    by the primitive functions. These "other" functions are called attribute
  19822.    functions since they alter the attributes, or characteristics, of lines
  19823.    and arcs.
  19824.  
  19825.  32.2.1  Drawing Straight Lines
  19826.  
  19827.    You draw straight lines by calling the GpiMove function and either the
  19828.    GpiLine or GpiPolyLine function. GpiMove sets the current position to the
  19829.    starting point of a line; GpiLine draws a single line from the current
  19830.    position to a specified point; and GpiPolyLine draws a series of connected
  19831.    lines, from the current position through successive points in an array.
  19832.  
  19833.    When MS OS/2 draws a line, it includes the pels at the starting and ending
  19834.    points of the line. The algorithm used to draw the rest of the line
  19835.    depends on the device driver. For example, a driver for a raster device
  19836.    may use a modified Brezenham algorithm to draw a line, but a driver for a
  19837.    vector device, such as a plotter, simply connects the line's starting and
  19838.    ending points. In all cases, the result is a line primitive that looks the
  19839.    same from device to device.
  19840.  
  19841.  32.2.2  Drawing Arcs
  19842.  
  19843.    You draw arcs by using GpiMove and one of the following functions:
  19844.  
  19845.    Function             Description
  19846.    ──────────────────────────────────────────────────────────────────────────
  19847.    GpiFullArc           Draws a circle or an ellipse.
  19848.  
  19849.    GpiPartialArc        Draws a section of a circle or ellipse.
  19850.  
  19851.    GpiPointArc          Draws an arc through three points.
  19852.  
  19853.    GpiPolyFillet        Draws one or more fillets.
  19854.  
  19855.    GpiPolyFilletSharp   Draws one or more fillets with varying degrees of
  19856.                         sharpness.
  19857.  
  19858.    GpiPolySpline        Draws one or more splines.
  19859.    ──────────────────────────────────────────────────────────────────────────
  19860.  
  19861.    The terms circle, ellipse, fillet, and spline are important in discussing
  19862.    arc primitives. A circle is a closed curve with a center from which every
  19863.    point on the curve is equidistant. An ellipse is a closed curve defined by
  19864.    two fixed points such that the sum of the distances from any point on the
  19865.    curve to the two fixed points is constant. A fillet is a curve that, given
  19866.    three control points, is tangent to the first and last points. A spline is
  19867.    a curve that, given four control points, is tangent to the first and last
  19868.    lines. Figure 32.2 shows a circle, an ellipse, a fillet, and a spline:
  19869.  
  19870.    ┌────────────────────────────────────────────────────────────────────────┐
  19871.    │ Figure 32.2 can be found in Section 32.2.2 of the printed manual.      │
  19872.    └────────────────────────────────────────────────────────────────────────┘
  19873.  
  19874.    Figure 32.2  Arcs
  19875.  
  19876.  32.2.3  Arc Parameters
  19877.  
  19878.    When you draw an arc or an ellipse in your application, the image that
  19879.    appears on the drawing surface reflects the current values of the arc
  19880.    parameters, p, q, r, and s. The default value of p is 1, as is the default
  19881.    value of q; the default value of r is 0, as is the default value of s.
  19882.    These parameters form a two-by-two matrix that scales and shears ellipses
  19883.    and arcs drawn by the GpiFullArc, GpiPointArc, and GpiPartialArc
  19884.    functions:
  19885.  
  19886.    ┌            ┐
  19887.    │ p=1   r=0  │
  19888.    │            │
  19889.    │ s=0   q=1  │
  19890.    └            ┘
  19891.  
  19892.  
  19893.    The parameters p and q are scaling values: p scales in the x-direction; q
  19894.    scales in the y-direction. The parameters r and s are shear components.
  19895.    When you alter r and s, a sheared ellipse or arc results. Figure 32.3
  19896.    shows four ellipses drawn by the GpiMove and GpiFullArc functions. In each
  19897.    case, one of the default arc parameters has been changed to scale or shear
  19898.    the ellipse.
  19899.  
  19900.    ┌────────────────────────────────────────────────────────────────────────┐
  19901.    │ Figure 32.3 can be found in Section 32.2.3 of the printed manual.      │
  19902.    └────────────────────────────────────────────────────────────────────────┘
  19903.  
  19904.    Figure 32.3  Transforming the Unit Circle Using the Arc Parameters
  19905.  
  19906.    All of the arc operations begin with a unit circle that lies at the origin
  19907.    in the world coordinate system. The arc parameters define a transformation
  19908.    that is applied to each point on the perimeter of the unit circle. For any
  19909.    point (x,y) on the perimeter of the unit circle, there exists a new point
  19910.    (x',y'), as determined by the following two algorithms:
  19911.  
  19912.                x' = p x x + r x y
  19913.                y' = s x x + q x y
  19914.  
  19915.  
  19916.    If the addition of (p x r) and (s x q) is zero, the transformation is
  19917.    orthogonal, and the line from the origin (0,0) to the point (p,s) is
  19918.    either the radius of a circle or half of the major or minor axis of an
  19919.    ellipse. The line from the origin to the point (r,q) is either the radius
  19920.    of a circle or half of the minor or major axis of an ellipse.
  19921.  
  19922.    Additional scaling transformations in your application can change the
  19923.    shape of the figure accordingly. For instance, if the page units in your
  19924.    application are PU_PELS and the pels on your device are rectangular
  19925.    (rather than square), MS OS/2 will draw an ellipse (rather than a circle)
  19926.    with GpiFullArc when the arc parameters are set to their default values.
  19927.  
  19928.    If (p x q) is greater than (r x s), MS OS/2 draws the ellipse
  19929.    counterclockwise for the GpiFullArc and GpiPartialArc functions. If (p x
  19930.    q) is less than (r x s), MS OS/2 draws the ellipse clockwise, and if (p x
  19931.    q) is equal to (r x s), MS OS/2 draws a straight line rather than an
  19932.    ellipse.
  19933.  
  19934.    You can determine the current arc parameters by calling the
  19935.    GpiQueryArcParams function, which copies the current arc parameters to
  19936.    their corresponding fields in the ARCPARAMS structure. You can set the arc
  19937.    parameters by calling GpiSetArcParams and passing it a copy of the
  19938.    ARCPARAMS structure that contains the new arc parameters you want to use.
  19939.    The ARCPARAMS structure has the following form:
  19940.  
  19941.    typedef struct _ARCPARAMS {    /* arcp */
  19942.        LONG lP;
  19943.        LONG lQ;
  19944.        LONG lR;
  19945.        LONG lS;
  19946.    } ARCPARAMS;
  19947.  
  19948.  32.2.4  Line Attributes
  19949.  
  19950.    Every line and arc has style, width, and color characteristics. These
  19951.    characteristics are called line attributes. The first line attribute, line
  19952.    style, defines the way the line is drawn: solid, as a series of dashes, as
  19953.    a series of dots, or as a combination of dashes and dots. Figure 32.4
  19954.    shows the various line styles:
  19955.  
  19956.    ┌────────────────────────────────────────────────────────────────────────┐
  19957.    │ Figure 32.4 can be found in Section 32.2.4 of the printed manual.      │
  19958.    └────────────────────────────────────────────────────────────────────────┘
  19959.  
  19960.    Figure 32.4  Line Styles
  19961.  
  19962.    The second line attribute, line width, defines the width of the line in
  19963.    pels. The third line attribute, line color, defines the color used to draw
  19964.    the line. Usually, this color is mixed with colors already on the drawing
  19965.    surface. This means that the final color of a line or curve depends not
  19966.    only on the line color but on the mix mode and the color of the drawing
  19967.    surface as well. If you draw a dotted or dashed line, the color that
  19968.    appears between the dots or dashes is the current drawing-surface color.
  19969.    The mix mode tells MS OS/2 how to combine the line and background colors
  19970.    (using a bitwise operation on the bits in the corresponding RGB values).
  19971.    For example, one mix mode combines the bits by using the bitwise OR
  19972.    operator. The resulting line has both the line and background colors.
  19973.    Using this mix mode, you would make a purple line when the line color is
  19974.    red and the background color is blue. For more information about color and
  19975.    mix-mode attributes, see Chapter 34, "Color and Mix Modes."
  19976.  
  19977.    When you create a normal presentation space, the line attributes are set
  19978.    to the following default values:
  19979.  
  19980.    Line attribute          Default value
  19981.    ──────────────────────────────────────────────────────────────────────────
  19982.    Line style              LINETYPE_SOLID
  19983.  
  19984.    Line color              CLR_NEUTRAL
  19985.  
  19986.    Line width              1.0
  19987.  
  19988.    Mix mode                FM_OVERPAINT
  19989.    ──────────────────────────────────────────────────────────────────────────
  19990.  
  19991.    You can retrieve the current line-attribute values by calling the
  19992.    GpiQueryAttrs function. This function copies the current line attributes
  19993.    to a LINEBUNDLE structure. You can change the values at any time by
  19994.    calling the GpiSetAttrs function. To make changes, you retrieve the
  19995.    current line attributes, set the appropriate fields in the LINEBUNDLE
  19996.    structure to new values, and pass the structure to GpiSetAttrs. The
  19997.    LINEBUNDLE structure has the following form:
  19998.  
  19999.    typedef struct _LINEBUNDLE {    /* lbnd                     */
  20000.        LONG    lColor;             /* line color               */
  20001.        LONG    lReserved;
  20002.        USHORT  usMixMode;          /* mix mode                 */
  20003.        USHORT  usReserved;
  20004.        FIXED   fxWidth;            /* line width               */
  20005.        LONG    lGeomWidth;         /* used with path functions */
  20006.        USHORT  usType;             /* line style               */
  20007.        USHORT  usEnd;              /* used with path functions */
  20008.        USHORT  usJoin;             /* used with path functions */
  20009.    } LINEBUNDLE;
  20010.  
  20011.    Several of the fields in this structure apply to a special wide line that
  20012.    you can construct using the path functions. For more information about
  20013.    paths and wide lines, see Chapter 35, "Paths."
  20014.  
  20015.  
  20016.  32.3  Using Line and Arc Primitives
  20017.  
  20018.    You can use the line and the arc functions to perform the following tasks:
  20019.  
  20020.    ■  Draw a straight line.
  20021.  
  20022.    ■  Create a "rubber-banding" effect with straight lines or arcs.
  20023.  
  20024.    ■  Draw a circle, ellipse, fillet, or spline.
  20025.  
  20026.  32.3.1  Drawing a Straight Line
  20027.  
  20028.    To draw a straight line, you must first set the current position by
  20029.    calling the GpiMove or GpiSetCurrentPosition function, then draw the line
  20030.    by calling the GpiLine function. The following code fragment shows how to
  20031.    draw straight lines:
  20032.  
  20033.    LONG DrawLine(hps, pptlStart, pptlEnd)
  20034.    HPS hps;            /* presentation-space handle            */
  20035.    PPOINTL pptlStart;  /* pointer to coordinates of line start */
  20036.    PPOINTL pptlEnd;    /* pointer to coordinates of line end   */
  20037.    {
  20038.        POINTL ptl_start, ptl_end;   /* point structures            */
  20039.  
  20040.        ptl_start.x = pptlStart->x;  /* loads starting x-coordinate */
  20041.        ptl_start.y = pptlStart->y;  /* loads starting y-coordinate */
  20042.        ptl_end.x = pptlEnd->x;      /* loads ending x-coordinate   */
  20043.        ptl_end.y = pptlEnd->y;      /* loads ending y-coordinate   */
  20044.        GpiMove(hps, &ptl_start);    /* sets current position       */
  20045.        if (GpiLine(hps, &ptl_end))  /* draws line                  */
  20046.            return (1L);
  20047.        else
  20048.            return (0L);
  20049.    }
  20050.  
  20051.    The second argument to the GpiMove function is the address of a structure
  20052.    that contains coordinates of the line's starting point; the second
  20053.    argument to the GpiLine function is the address of a structure that
  20054.    contains the coordinates of the last point on the line.
  20055.  
  20056.  32.3.2  Creating a Rubber-Banding Effect with a Straight Line
  20057.  
  20058.    When lines are drawn with a rubber-banding effect, two things happen: The
  20059.    original line (if one exists) is erased, and a new line is drawn in its
  20060.    place. This process takes place each time the mouse is dragged and
  20061.    continues until the mouse button is released. The quickest way to erase
  20062.    the original line is to set the foreground mix mode to FM_XOR and redraw
  20063.    the line. The following code fragment demonstrates how you can create this
  20064.    effect:
  20065.  
  20066.    HPS hps;          /* presentation-space handle  */
  20067.    POINTL ptlStart;  /* starting point of line     */
  20068.    POINTL ptlNew;    /* ending point of line       */
  20069.    POINTL ptlPrev;   /* previous end point of line */
  20070.    BOOL fDraw;       /* line-drawing flag          */
  20071.        .
  20072.        .
  20073.        .
  20074.    GpiSetColor(hps, CLR_GREEN); /* sets line-drawing color to green */
  20075.        .
  20076.        .
  20077.        .
  20078.    MRESULT FAR PASCAL GenericWndProc(hwnd, usMessage, mp1, mp2)
  20079.    HWND hwnd;
  20080.    USHORT usMessage;
  20081.    MPARAM mp1;
  20082.    MPARAM mp2;
  20083.    {
  20084.        .
  20085.        .
  20086.        .
  20087.        case WM_BUTTON1DOWN: /* user begins drawing */
  20088.            ptlStart.x = (LONG) (LOUSHORT(mp1));
  20089.            ptlStart.y = (LONG) (HIUSHORT(mp1));
  20090.            GpiConvert(hps, CVTC_DEVICE, CVTC_WORLD, 1L, &ptlStart);
  20091.            ptlPrev.x = ptlStart.x;
  20092.            ptlPrev.y = ptlStart.y;
  20093.            GpiMove (hps, &ptlStart);
  20094.            fDraw = TRUE;
  20095.        return TRUE;
  20096.  
  20097.        case WM_MOUSEMOVE: /* user draws line */
  20098.        if (fDraw) {
  20099.            ptlNew.x = (LONG) (LOUSHORT(mp1));
  20100.            ptlNew.y = (LONG) (HIUSHORT(mp1));
  20101.            GpiConvert(hps, CVTC_DEVICE, CVTC_WORLD, 1L, &ptlNew);
  20102.            GpiSetMix(hps, FM_XOR);
  20103.            if ((ptlStart.x != ptlPrev.x) || (ptlStart.y != ptlPrev.y)) {
  20104.                GpiMove(hps, &ptlStart);
  20105.                GpiLine(hps, &ptlPrev);
  20106.            }
  20107.            if ((ptlStart.x != ptlNew.x) || (ptlStart.y != ptlNew.y)) {
  20108.                GpiMove(hps, &ptlStart);
  20109.                GpiLine(hps, &ptlNew);
  20110.                ptlPrev.x = ptlNew.x; ptlPrev.y = ptlNew.y;
  20111.            }
  20112.            GpiSetMix(hps, FM_OVERPAINT);
  20113.        return TRUE;
  20114.        }
  20115.  
  20116.        case WM_BUTTON1UP: /* user stops drawing */
  20117.            fDraw = FALSE;
  20118.            return TRUE;
  20119.        .
  20120.        .
  20121.        .
  20122.    }
  20123.  
  20124.  32.3.3  Drawing a Circle
  20125.  
  20126.    To draw a circle, all of the transformations between the world, model,
  20127.    page, and device spaces must maintain square units. This means that
  20128.    instead of pels for page units, the application should select metric or
  20129.    English page units. (On most devices, a pel is rectangular, not square.)
  20130.    This also means that the x-values and y-values for any scaling
  20131.    transformations should be equal. If the transformations maintain square
  20132.    units, the default arc parameters will transform an ellipse drawn by the
  20133.    GpiFullArc function into a circle.
  20134.  
  20135.    If the page units are Low English and the default transformations are set,
  20136.    the following code fragment draws a circle with a diameter of 1 inch:
  20137.  
  20138.    ARCPARAMS arcp;           /* structure for arc parameters   */
  20139.    HPS hps;                  /* presentation-space handle      */
  20140.    POINTL ptlPos;            /* structure for current position */
  20141.    FIXED fxMult;             /* multiplier for circle          */
  20142.        .
  20143.        .
  20144.        .
  20145.        arcp.lP = 1L; arcp.lQ = 1L;
  20146.        arcp.lR = 0L; arcp.lS = 0L;
  20147.        GpiSetArcParams(hps,
  20148.            &arcp);                     /* sets parameters to default */
  20149.        ptlPos.x = 100;                 /* loads x-coordinate         */
  20150.        ptlPos.y = 100;                 /* loads y-coordinate         */
  20151.        GpiMove(hps, &ptlPos);          /* sets current position      */
  20152.        fxMult = (50 * 65536);          /* sets multiplier            */
  20153.        GpiFullArc(hps, DRO_OUTLINE,    /* draws circle               */
  20154.            fxMult);
  20155.  
  20156.    The second argument to the GpiFullArc function, DRO_OUTLINE, specifies
  20157.    that MS OS/2 should draw only the outline of the circle (rather than
  20158.    filling the interior with the current fill pattern). The third argument,
  20159.    fxMult, specifies that MS OS/2 should multiply the size of the circle by
  20160.    50 units. Since the page units are PU_LOENGLISH and the default
  20161.    transformations are set, 50 units are equivalent to 1/2 inch. The circle
  20162.    will have a 1/2-inch radius and a 1-inch diameter.
  20163.  
  20164.  32.3.4  Drawing an Ellipse
  20165.  
  20166.    If the world, model, page, and device transformations are set so that they
  20167.    maintain square units, you can use the arc parameters to transform the
  20168.    shape of the ellipse drawn by the GpiFullArc function. The following code
  20169.    fragment alters the arc parameter p by doubling its value, making the
  20170.    ellipse twice as wide horizontally as it is vertically.
  20171.  
  20172.    If the page units are PU_LOENGLISH and the default transformations are
  20173.    set, the following code fragment draws an ellipse with a 2-inch major axis
  20174.    (parallel to the x-axis) and a 1-inch minor axis (parallel to the y-axis).
  20175.    The ellipse is centered over a point in the lower-left corner of a
  20176.    maximized window.
  20177.  
  20178.    ARCPARAMS arcp;      /* structure for arc parameters   */
  20179.    HPS hps;             /* presentation-space handle      */
  20180.    POINTL ptlPos;       /* structure for current position */
  20181.    LONG fxMult;         /* multiplier for ellipse         */
  20182.        .
  20183.        .
  20184.        .
  20185.        arcp.lP = 2L; arcp.lQ = 1L;
  20186.        arcp.lR = 0L; arcp.lS = 0L;
  20187.        GpiSetArcParams(hps,
  20188.            &arcp);                    /* sets parameters to default */
  20189.        ptlPos.x = 200;                /* loads x-coordinate         */
  20190.        ptlPos.y = 100;                /* loads y-coordinate         */
  20191.        GpiMove(hps, &ptlPos);         /* sets current position      */
  20192.        fxMult = (50 * 65536);         /* sets multiplier            */
  20193.        GpiFullArc(hps, DRO_OUTLINE,   /* draws circle               */
  20194.            fxMult);
  20195.        .
  20196.        .
  20197.        .
  20198.  
  20199.    The arc-parameter field lP is set to 2, and the arc-parameter field lQ is
  20200.    set to 1. From these parameters, MS OS/2 creates an ellipse with a major
  20201.    axis that is twice as long as the minor axis.
  20202.  
  20203.  32.3.5  Drawing a Fillet
  20204.  
  20205.    When you draw a fillet, each curve is tangent to two lines. The curve of
  20206.    the first fillet is always tangent to a line drawn between the current
  20207.    position and the first control point and a line drawn between the current
  20208.    position and the second control point.
  20209.  
  20210.    The following code fragment shows how to draw a single curve by using the
  20211.    current position and two control points:
  20212.  
  20213.    POINTL aptl[2];  /* structure for control points */
  20214.    HPS hps;         /* presentation-space handle    */
  20215.        .
  20216.        .
  20217.        .
  20218.        aptl[0].x = 50;       /* loads x-coord. of first control point  */
  20219.        aptl[0].y = 50;       /* loads y-coord. of first control point  */
  20220.        GpiMove(hps, aptl);   /* sets current position                  */
  20221.        aptl[0].x = 75;       /* loads x-coord. of second control point */
  20222.        aptl[0].y = 75;       /* loads y-coord. of second control point */
  20223.        aptl[1].x = 100;      /* loads x-coord. of third control point  */
  20224.        aptl[1].y = 50;       /* loads y-coord. of third control point  */
  20225.        GpiPolyFillet(hps,    /* draws fillet                           */
  20226.            2L, aptl);
  20227.        .
  20228.        .
  20229.        .
  20230.  
  20231.    When you draw a sharp fillet, the sharpness value controls the shape of
  20232.    the curve: If the value is greater than 1, a hyperbola is drawn; if the
  20233.    value is 1, a parabola is drawn; and if the value is less than 1, an
  20234.    ellipse is drawn. The following code fragment uses a sharpness value
  20235.    greater than 1, which creates a hyperbolic curve:
  20236.  
  20237.    POINTL aptl[2];        /* structure for control points */
  20238.    FIXED fxSharpness[1];  /* array with sharpness value   */
  20239.    HPS hps;               /* presentation-space handle    */
  20240.        .
  20241.        .
  20242.        .
  20243.        aptl[0].x = 50;     /* loads x-coord. of first control point  */
  20244.        aptl[0].y = 50;     /* loads y-coord. of first control point  */
  20245.        GpiMove(hps, aptl); /* sets current position                  */
  20246.        aptl[0].x = 75;     /* loads x-coord. of second control point */
  20247.        aptl[0].y = 75;     /* loads y-coord. of second control point */
  20248.        aptl[1].x = 100;    /* loads x-coord. of third control point  */
  20249.        aptl[1].y = 50;     /* loads y-coord. of third control point  */
  20250.        fxSharpness[0] = 1; /* sets sharpness value                   */
  20251.        GpiPolyFilletSharp(hps, /* draws fillet                       */
  20252.            2L, aptl, fxSharpness);
  20253.        .
  20254.        .
  20255.        .
  20256.  
  20257.  32.3.6  Drawing a Spline
  20258.  
  20259.    When you use the GpiPolySpline function to draw a spline, each curve is
  20260.    tangent to the first and last lines of three intersecting lines. The
  20261.    following code fragment shows how to draw a spline:
  20262.  
  20263.    POINTL aptl[3];  /* structure for control points */
  20264.    HPS hps;         /* presentation-space handle    */
  20265.        .
  20266.        .
  20267.        .
  20268.        aptl[0].x = 50;      /* loads x-coord. of first control point  */
  20269.        aptl[0].y = 50;      /* loads y-coord. of first control point  */
  20270.        GpiMove(hps, aptl);  /* sets current position                  */
  20271.        aptl[0].x = 75;      /* loads x-coord. of second control point */
  20272.        aptl[0].y = 75;      /* loads y-coord. of second control point */
  20273.        aptl[1].x = 100;     /* loads x-coord. of third control point  */
  20274.        aptl[1].y = 75;      /* loads y-coord. of third control point  */
  20275.        aptl[2].x = 125;     /* loads x-coord. of fourth control point */
  20276.        aptl[2].y = 50;      /* loads y-coord. of fourth control point */
  20277.        GpiPolySpline(hps,   /* draws spline                           */
  20278.            3L, aptl);
  20279.        .
  20280.        .
  20281.        .
  20282.  
  20283.  
  20284.  32.4  Summary
  20285.  
  20286.    The following list summarizes the MS OS/2 line and arc functions:
  20287.  
  20288.    GpiFullArc  Draws an ellipse by translating the ellipse generated by the
  20289.    arc parameters to the current position and scaling that ellipse with a
  20290.    specified multiplier. If the arc parameters are set to their default
  20291.    values and the page units are LOENGLISH, HIENGLISH, LOMETRIC, or HIMETRIC,
  20292.    the function draws a circle. Depending on the control argument, this
  20293.    function will fill the ellipse with the current fill pattern, draw the
  20294.    ellipse's outline only, or fill and draw the outline.
  20295.  
  20296.    GpiLine  Draws a straight line from the current position to a specified
  20297.    end point.
  20298.  
  20299.    GpiMove  Sets the current position. MS OS/2 does not save the old position
  20300.    (as it does for GpiSetCurrentPosition) if the attribute mode is
  20301.    AM_PRESERVE.
  20302.  
  20303.    GpiPartialArc  Draws a straight line from the current position to the
  20304.    starting point of an arc and then draws the arc itself, using the current
  20305.    arc parameters, a sweep angle, and a multiplier. The arc parameters
  20306.    determine the shape of the arc and the direction in which it is drawn; the
  20307.    sweep angle and multiplier determine the length of the arc.
  20308.  
  20309.    GpiPointArc  Draws an arc through three points. The first point is the
  20310.    current position; the last two points are control points passed as
  20311.    arguments to the function. The function uses the current arc parameters to
  20312.    determine the size and shape of the arc.
  20313.  
  20314.    GpiPolyFillet  Draws a fillet. A fillet is a special curve that does not
  20315.    fit the circumference of an ellipse. (All of the other curves drawn by the
  20316.    various arc functions fit onto the circumference of an ellipse generated
  20317.    by the arc parameters.) A minimum of three control points defines a
  20318.    fillet.
  20319.  
  20320.    GpiPolyFilletSharp  Draws a special fillet, using an array of sharpness
  20321.    values that correspond to each curve in the fillet. Sharpness values less
  20322.    than zero generate curves resembling hyperbolas; values of zero generate
  20323.    straight lines; and values greater than zero generate curves resembling
  20324.    parts of ellipses.
  20325.  
  20326.    GpiPolyLine  Draws a series of straight lines starting at the current
  20327.    position. The attributes in the current line structure determine the style
  20328.    and color of lines.
  20329.  
  20330.    GpiPolySpline  Draws a spline. A spline consists of one or more special
  20331.    curves called Bezier curves. A minimum of four control points defines a
  20332.    spline.
  20333.  
  20334.    GpiQueryArcParams  Retrieves a pointer to a structure that contains the
  20335.    current arc parameters. MS OS/2 uses the arc parameters when it draws an
  20336.    arc using the GpiFullArc, GpiPointArc, and GpiPartialArc functions.
  20337.  
  20338.    GpiQueryCurrentPosition  Retrieves a pointer to a structure that contains
  20339.    the x- and y-coordinates of the current position.
  20340.  
  20341.    GpiQueryLineType  Retrieves the current line type, which can be one of
  20342.    nine possible values.
  20343.  
  20344.    GpiQueryLineWidth  Retrieves the current line width. Currently in MS OS/2,
  20345.    this value should always be 65,536 decimal (0x1000 hexadecimal).
  20346.  
  20347.    GpiSetArcParams  Sets the parameters of the arc. These parameters
  20348.    determine the shape of an ellipse and the direction in which MS OS/2 draws
  20349.    it. There are four arc parameters──p, s, r, and q──represented by four
  20350.    fields in the ARCPARAMS structure.
  20351.  
  20352.    GpiSetCurrentPosition  Sets the current position to a point specified by
  20353.    an x- and a y-coordinate. MS OS/2 uses the current position when it draws
  20354.    lines, arcs, fillets, and splines.
  20355.  
  20356.    GpiSetLineType  Sets the current line type, which can be one of nine
  20357.    possible values.
  20358.  
  20359.    GpiSetLineWidth  Sets the current line width. Currently in MS OS/2, this
  20360.    value should always be 65,536 decimal (0x1000 hexadecimal).
  20361.  
  20362.  
  20363.  
  20364.  ────────────────────────────────────────────────────────────────────────────
  20365.  Chapter 33  Fonts and Character Primitives
  20366.  
  20367.         33.1    Introduction
  20368.         33.2    About Fonts and Character Primitives
  20369.             33.2.1    Font Metrics
  20370.             33.2.2    Image and Outline Fonts
  20371.             33.2.3    Proportional and Fixed Fonts
  20372.             33.2.4    Glyphs, Code Pages, and Code Points
  20373.             33.2.5    Text Output
  20374.                 33.2.5.1   Text and Character Attributes
  20375.                 33.2.5.2   Character Modes
  20376.             33.2.6    Font Files and Dynamic-Link Libraries
  20377.             33.2.7    Selecting New Fonts
  20378.                 33.2.7.1   Public Fonts
  20379.                 33.2.7.2   Private Fonts
  20380.         33.3    Using Fonts and Character Primitives
  20381.             33.3.1    Selecting a Public Font
  20382.             33.3.2    Drawing Text
  20383.             33.3.3    Transforming Text from an Outline Font
  20384.             33.3.4    Transforming Text from an Image Font
  20385.         33.4    Summary
  20386.  
  20387.  33.1  Introduction
  20388.  
  20389.    This chapter defines typographic terms and concepts that are part of the
  20390.    MS OS/2 application programming interface (API). You should also be
  20391.    familiar with the following topics:
  20392.  
  20393.    ■  Presentation spaces and device contexts
  20394.  
  20395.    ■  Coordinate spaces and transformations
  20396.  
  20397.    ■  Color and mix modes
  20398.  
  20399.  
  20400.  33.2  About Fonts and Character Primitives
  20401.  
  20402.    A font family is a collection of fonts that share common stroke-width and
  20403.    serif characteristics. The term stroke width refers to the width of lines
  20404.    used to draw characters and symbols from a font. Figure 33.1 shows a
  20405.    lowercase letter f that consists of two strokes: a stem (the main vertical
  20406.    stroke) and a cross-stroke:
  20407.  
  20408.    ┌────────────────────────────────────────────────────────────────────────┐
  20409.    │ Figure 33.1 can be found in Section 33.2 of the printed manual.        │
  20410.    └────────────────────────────────────────────────────────────────────────┘
  20411.  
  20412.    Figure 33.1  Strokes
  20413.  
  20414.    A serif is a short cross-line drawn at the ends of main strokes that form
  20415.    a character or symbol. Figure 33.2 shows serifs drawn at the ends of the
  20416.    strokes in the uppercase letters A and L:
  20417.  
  20418.    ┌────────────────────────────────────────────────────────────────────────┐
  20419.    │ Figure 33.2 can be found in Section 33.2 of the printed manual.        │
  20420.    └────────────────────────────────────────────────────────────────────────┘
  20421.  
  20422.    Figure 33.2  Serifs
  20423.  
  20424.    A font, part of a font family, is a collection of characters and symbols
  20425.    that share a common height, line weight, and appearance. The height of a
  20426.    font is specified in printer's points, or points, a point being a
  20427.    typographic unit of measurement equal to 1/72 of an inch. The five
  20428.    categories of line weight and appearance are as follows:
  20429.  
  20430.    ■  Normal
  20431.  
  20432.    ■  Bold
  20433.  
  20434.    ■  Condensed
  20435.  
  20436.    ■  Expanded
  20437.  
  20438.    ■  Italic
  20439.  
  20440.    Characters from a bold font are drawn with a heavier line weight. A
  20441.    16-point Times Roman Bold is an example of a bold font, as shown in Figure
  20442.    33.3:
  20443.  
  20444.    ┌────────────────────────────────────────────────────────────────────────┐
  20445.    │ Figure 33.3 can be found in Section 33.2 of the printed manual.        │
  20446.    └────────────────────────────────────────────────────────────────────────┘
  20447.  
  20448.    Figure 33.3  Bold Font
  20449.  
  20450.    Characters from an italic font are drawn with a normal line weight and
  20451.    slanted up and to the right. A 10-point Courier Italic is an example of an
  20452.    italic font, as shown in Figure 33.4:
  20453.  
  20454.    ┌────────────────────────────────────────────────────────────────────────┐
  20455.    │ Figure 33.4 can be found in Section 33.2 of the printed manual.        │
  20456.    └────────────────────────────────────────────────────────────────────────┘
  20457.  
  20458.    Figure 33.4  Italic Font
  20459.  
  20460.    Characters from a normal font are drawn with a normal line weight. An
  20461.    8-point Helvetica is an example of a normal font, as shown in Figure
  20462.    33.5:
  20463.  
  20464.    ┌────────────────────────────────────────────────────────────────────────┐
  20465.    │ Figure 33.5 can be found in Section 33.2 of the printed manual.        │
  20466.    └────────────────────────────────────────────────────────────────────────┘
  20467.  
  20468.    Figure 33.5  Normal Font
  20469.  
  20470.  33.2.1  Font Metrics
  20471.  
  20472.    Every character in a font is drawn within a rectangular region called a
  20473.    character cell. Through the lower half of the character cell is drawn an
  20474.    imaginary horizontal line called the baseline. All uppercase letters and
  20475.    most lowercase letters in a given font rest on the baseline. Some
  20476.    lowercase letters, such as g or y, descend below the baseline. MS OS/2
  20477.    uses the baseline to position characters. When an application draws a
  20478.    string of text, MS OS/2 positions the leftmost point of the baseline over
  20479.    a predetermined point for each character in the string. The distance from
  20480.    the bottom of the character cell to its top is the character-cell height,
  20481.    and the distance from the baseline to the top of the character cell is the
  20482.    character-cell ascent. Similarly, the character-cell descent is the
  20483.    distance from the baseline to the bottom of the character cell, and the
  20484.    width of the character cell is the distance from one side to the other.
  20485.    Figure 33.6 shows a character cell, its origin, baseline, height, ascent,
  20486.    descent, and width:
  20487.  
  20488.    ┌────────────────────────────────────────────────────────────────────────┐
  20489.    │ Figure 33.6 can be found in Section 33.2.1 of the printed manual.      │
  20490.    └────────────────────────────────────────────────────────────────────────┘
  20491.  
  20492.    Figure 33.6  Character Cell
  20493.  
  20494.    The average distance from the baseline to the top of any uppercase
  20495.    character is called a font's em height. This measurement was given its
  20496.    name because the height of an uppercase letter M is usually equal to the
  20497.    average height of all uppercase characters in the font. Figure 33.7 shows
  20498.    the em height:
  20499.  
  20500.    ┌────────────────────────────────────────────────────────────────────────┐
  20501.    │ Figure 33.7 can be found in Section 33.2.1 of the printed manual.      │
  20502.    └────────────────────────────────────────────────────────────────────────┘
  20503.  
  20504.    Figure 33.7  Em Height
  20505.  
  20506.    The average distance from the baseline to the top of any lowercase
  20507.    character is called a font's x height. This measurement was given its name
  20508.    because the height of a lowercase letter x is usually equal to the average
  20509.    height of all lowercase characters in the font. Figure 33.8 shows the x
  20510.    height:
  20511.  
  20512.    ┌────────────────────────────────────────────────────────────────────────┐
  20513.    │ Figure 33.8 can be found in Section 33.2.1 of the printed manual.      │
  20514.    └────────────────────────────────────────────────────────────────────────┘
  20515.  
  20516.    Figure 33.8  X Height
  20517.  
  20518.    The maximum ascender, which is the height of the tallest character in a
  20519.    font, is shown in Figure 33.9:
  20520.  
  20521.    ┌────────────────────────────────────────────────────────────────────────┐
  20522.    │ Figure 33.9 can be found in Section 33.2.1 of the printed manual.      │
  20523.    └────────────────────────────────────────────────────────────────────────┘
  20524.  
  20525.    Figure 33.9  Maximum Ascender
  20526.  
  20527.    The maximum descender, which is the depth (below the baseline) of the
  20528.    lowest character in a font, is shown in Figure 33.10:
  20529.  
  20530.    ┌────────────────────────────────────────────────────────────────────────┐
  20531.    │ Figure 33.10 can be found in Section 33.2.1 of the printed manual.     │
  20532.    └────────────────────────────────────────────────────────────────────────┘
  20533.  
  20534.    Figure 33.10  Maximum Descender
  20535.  
  20536.    The lowercase ascent, which is the height of the tallest lowercase
  20537.    character in a font, is shown in Figure 33.11:
  20538.  
  20539.    ┌────────────────────────────────────────────────────────────────────────┐
  20540.    │ Figure 33.11 can be found in Section 33.2.1 of the printed manual.     │
  20541.    └────────────────────────────────────────────────────────────────────────┘
  20542.  
  20543.    Figure 33.11  Lowercase Ascent
  20544.  
  20545.    The lowercase descent, which is the depth (below the baseline) of the
  20546.    lowest lowercase character in a font, is shown in Figure 33.12:
  20547.  
  20548.    ┌────────────────────────────────────────────────────────────────────────┐
  20549.    │ Figure 33.12 can be found in Section 33.2.1 of the printed manual.     │
  20550.    └────────────────────────────────────────────────────────────────────────┘
  20551.  
  20552.    Figure 33.12  Lowercase Descent
  20553.  
  20554.    Many fonts reserve part of the space in the top of each character cell for
  20555.    accent marks. This reserved space, called internal leading, is shown in
  20556.    Figure 33.13:
  20557.  
  20558.    ┌────────────────────────────────────────────────────────────────────────┐
  20559.    │ Figure 33.13 can be found in Section 33.2.1 of the printed manual.     │
  20560.    └────────────────────────────────────────────────────────────────────────┘
  20561.  
  20562.    Figure 33.13  Internal Leading
  20563.  
  20564.    Some fonts designate a certain amount of space to leave between rows of
  20565.    text. This space, called external leading, is not included in the
  20566.    character-cell height or ascent measurements. It is shown in Figure
  20567.    33.14:
  20568.  
  20569.    ┌────────────────────────────────────────────────────────────────────────┐
  20570.    │ Figure 33.14 can be found in Section 33.2.1 of the printed manual.     │
  20571.    └────────────────────────────────────────────────────────────────────────┘
  20572.  
  20573.    Figure 33.14  External Leading
  20574.  
  20575.    The average character width is determined by multiplying the width of each
  20576.    lowercase letter by a predetermined factor, adding the results for each
  20577.    letter in the alphabet, and then dividing by 1000. The average character
  20578.    width is determined by the setting in the lAveCharWidth field in the
  20579.    FONTMETRICS structure. For information about FONTMETRICS, see the
  20580.    Microsoft Operating System/2 Programmer's Reference, Volume 2.
  20581.  
  20582.    The em increment, which is the width of the uppercase letter M in a font,
  20583.    is shown in Figure 33.15:
  20584.  
  20585.    ┌────────────────────────────────────────────────────────────────────────┐
  20586.    │ Figure 33.15 can be found in Section 33.2.1 of the printed manual.     │
  20587.    └────────────────────────────────────────────────────────────────────────┘
  20588.  
  20589.    Figure 33.15  Em Increment
  20590.  
  20591.    The maximum baseline extent for a font is the sum of the maximum ascender
  20592.    and the maximum descender. Figure 33.16 shows an example of a maximum
  20593.    baseline extent:
  20594.  
  20595.    ┌────────────────────────────────────────────────────────────────────────┐
  20596.    │ Figure 33.16 can be found in Section 33.2.1 of the printed manual.     │
  20597.    └────────────────────────────────────────────────────────────────────────┘
  20598.  
  20599.    Figure 33.16  Maximum Baseline Extent
  20600.  
  20601.    The character slope is an angle measured clockwise with respect to a
  20602.    vertical line. The slope of a normal font is zero; the slope of an italic
  20603.    font is nonzero. Figure 33.17 shows a character slope:
  20604.  
  20605.    ┌────────────────────────────────────────────────────────────────────────┐
  20606.    │ Figure 33.17 can be found in Section 33.2.1 of the printed manual.     │
  20607.    └────────────────────────────────────────────────────────────────────────┘
  20608.  
  20609.    Figure 33.17  Character Slope
  20610.  
  20611.    The in-line direction is an angle measured clockwise with respect to a
  20612.    horizontal line. The in-line direction for a Swiss, Helvetica, or Roman
  20613.    font is normally zero; the in-line direction for a Hebrew font is normally
  20614.    180. Figure 33.18 shows the in-line direction for a Roman font:
  20615.  
  20616.    ┌────────────────────────────────────────────────────────────────────────┐
  20617.    │ Figure 33.18 can be found in Section 33.2.1 of the printed manual.     │
  20618.    └────────────────────────────────────────────────────────────────────────┘
  20619.  
  20620.    Figure 33.18  In-line Direction
  20621.  
  20622.    The character-rotation angle is an angle measured counterclockwise with
  20623.    respect to a horizontal line. The baselines of characters are aligned with
  20624.    a vector drawn at the angle of rotation. Figure 33.19 shows a
  20625.    character-rotation angle and a character-angle vector:
  20626.  
  20627.    ┌────────────────────────────────────────────────────────────────────────┐
  20628.    │ Figure 33.19 can be found in Section 33.2.1 of the printed manual.     │
  20629.    └────────────────────────────────────────────────────────────────────────┘
  20630.  
  20631.    Figure 33.19  Character Rotation
  20632.  
  20633.    The weight class specifies the thickness of each stroke that forms part of
  20634.    each character in a font.
  20635.  
  20636.    A superscript is a character drawn immediately above and to the right of a
  20637.    normal character in a string of text. Superscripts are identified by a
  20638.    width and a height, and by vertical and horizontal offsets. Figure 33.20
  20639.    shows a superscript:
  20640.  
  20641.    ┌────────────────────────────────────────────────────────────────────────┐
  20642.    │ Figure 33.20 can be found in Section 33.2.1 of the printed manual.     │
  20643.    └────────────────────────────────────────────────────────────────────────┘
  20644.  
  20645.    Figure 33.20  Superscript
  20646.  
  20647.    A subscript is a character drawn immediately below and to the right of a
  20648.    normal character in a string of text. Subscripts are identified by a width
  20649.    and a height, and by vertical and horizontal offsets. Figure 33.21 shows
  20650.    a subscript:
  20651.  
  20652.    ┌────────────────────────────────────────────────────────────────────────┐
  20653.    │ Figure 33.21 can be found in Section 33.2.1 of the printed manual.     │
  20654.    └────────────────────────────────────────────────────────────────────────┘
  20655.  
  20656.    Figure 33.21  Subscript
  20657.  
  20658.    Kerning is an adjustment to space between certain characters in a font.
  20659.    Some fonts contain a kerning table, which is a table of kerning values
  20660.    specifying the amount of space that should appear between certain
  20661.    characters. You can examine the kerning information by calling the
  20662.    GpiQueryKerningPairs function. You cannot set kerning for a font, but you
  20663.    can simulate kerning for an image font, using MS OS/2 Font Editor, by
  20664.    adjusting the a-space and c-space for each character. The a-space is the
  20665.    space between the left edge of a character cell and the left edge of the
  20666.    cell's character. The c-space is the space between the right edge of a
  20667.    character cell and the right edge of its character.
  20668.  
  20669.    Most of the terms described in the previous pages have corresponding
  20670.    fields in a special structure called a FONTMETRICS structure. This
  20671.    structure has the following form:
  20672.  
  20673.    typedef struct _FONTMETRICS {   /* fm */
  20674.        CHAR    szFamilyname[FACESIZE];
  20675.        CHAR    szFacename[FACESIZE];
  20676.        USHORT  idRegistry;
  20677.        USHORT  usCodePage;
  20678.        LONG    lEmHeight;
  20679.        LONG    lXHeight;
  20680.        LONG    lMaxAscender;
  20681.        LONG    lMaxDescender;
  20682.        LONG    lLowerCaseAscent;
  20683.        LONG    lLowerCaseDescent;
  20684.        LONG    lInternalLeading;
  20685.        LONG    lExternalLeading;
  20686.        LONG    lAveCharWidth;
  20687.        LONG    lMaxCharInc;
  20688.        LONG    lEmInc;
  20689.        LONG    lMaxBaselineExt;
  20690.        SHORT   sCharSlope;
  20691.        SHORT   sInlineDir;
  20692.        SHORT   sCharRot;
  20693.        USHORT  usWeightClass;
  20694.        USHORT  usWidthClass;
  20695.        SHORT   sXDeviceRes;
  20696.        SHORT   sYDeviceRes;
  20697.        SHORT   sFirstChar;
  20698.        SHORT   sLastChar;
  20699.        SHORT   sDefaultChar;
  20700.        SHORT   sBreakChar;
  20701.        SHORT   sNominalPointSize;
  20702.        SHORT   sMinimumPointSize;
  20703.        SHORT   sMaximumPointSize;
  20704.        USHORT  fsType;
  20705.        USHORT  fsDefn;
  20706.        USHORT  fsSelection;
  20707.        USHORT  fsCapabilities;
  20708.        LONG    lSubscriptXSize;
  20709.        LONG    lSubscriptYSize;
  20710.        LONG    lSubscriptXOffset;
  20711.        LONG    lSubscriptYOffset;
  20712.        LONG    lSuperscriptXSize;
  20713.        LONG    lSuperscriptYSize;
  20714.        LONG    lSuperscriptXOffset;
  20715.        LONG    lSuperscriptYOffset;
  20716.        LONG    lUnderscoreSize;
  20717.        LONG    lUnderscorePosition;
  20718.        LONG    lStrikeoutSize;
  20719.        LONG    lStrikeoutPosition;
  20720.        SHORT   sKerningPairs;
  20721.        SHORT   sReserved;
  20722.        LONG    lMatch;
  20723.    } FONTMETRICS;
  20724.  
  20725.    For a complete description of each field in the FONTMETRICS structure, see
  20726.    the Microsoft Operating System/2 Programmer's Reference, Volume 2.
  20727.  
  20728.  33.2.2  Image and Outline Fonts
  20729.  
  20730.    Characters in a font are stored either as bitmaps or as collections of
  20731.    calls to line, arc, and path functions. Fonts stored as bitmaps are image
  20732.    fonts. Fonts stored as collections of line, arc, and path calls are
  20733.    outline fonts. Figure 33.22 shows an enlarged view of a lowercase letter
  20734.    a from an image font:
  20735.  
  20736.    ┌────────────────────────────────────────────────────────────────────────┐
  20737.    │ Figure 33.22 can be found in Section 33.2.2 of the printed manual.     │
  20738.    └────────────────────────────────────────────────────────────────────────┘
  20739.  
  20740.    Figure 33.22  Image Font
  20741.  
  20742.    Figure 33.23 shows an enlarged view of a lowercase letter a from an
  20743.    outline font:
  20744.  
  20745.    ┌────────────────────────────────────────────────────────────────────────┐
  20746.    │ Figure 33.23 can be found in Section 33.2.2 of the printed manual.     │
  20747.    └────────────────────────────────────────────────────────────────────────┘
  20748.  
  20749.    Figure 33.23  Outline Font
  20750.  
  20751.  33.2.3  Proportional and Fixed Fonts
  20752.  
  20753.    When text is drawn, MS OS/2 aligns each character by positioning its
  20754.    character cell next to the previous character's cell, as shown in Figure
  20755.    33.24:
  20756.  
  20757.    ┌────────────────────────────────────────────────────────────────────────┐
  20758.    │ Figure 33.24 can be found in Section 33.2.3 of the printed manual.     │
  20759.    └────────────────────────────────────────────────────────────────────────┘
  20760.  
  20761.    Figure 33.24  Character-Cell Alignment
  20762.  
  20763.    Some fonts adjust the width of character cells so that narrow letters like
  20764.    a lowercase l or i appear closer to adjacent characters. Fonts that adjust
  20765.    the width of character cells are called proportional fonts; fonts that do
  20766.    not are called fixed fonts. Proportional fonts are generally easier to
  20767.    read than fixed fonts. Figure 33.25 shows a line of text from a
  20768.    proportional font, followed by a line of text from a fixed font:
  20769.  
  20770.    ┌────────────────────────────────────────────────────────────────────────┐
  20771.    │ Figure 33.25 can be found in Section 33.2.3 of the printed manual.     │
  20772.    └────────────────────────────────────────────────────────────────────────┘
  20773.  
  20774.    Figure 33.25  Proportional and Fixed Fonts
  20775.  
  20776.  33.2.4  Glyphs, Code Pages, and Code Points
  20777.  
  20778.    The image or picture that you associate with each character or symbol in a
  20779.    font is a glyph. A set of glyphs is called a code page. Each code page
  20780.    contains 256 code points (16-bit integers), in the range 0 through 255,
  20781.    that correspond to the glyphs in that code page. MS OS/2 assigns unique
  20782.    identifiers to each of its code pages. A common code page is code page
  20783.    437. Figure 33.26 shows the glyphs and corresponding code points for this
  20784.    code page:
  20785.  
  20786.    ┌────────────────────────────────────────────────────────────────────────┐
  20787.    │ Figure 33.26 can be found in Section 33.2.4 of the printed manual.     │
  20788.    └────────────────────────────────────────────────────────────────────────┘
  20789.  
  20790.    Figure 33.26  Code Page 437
  20791.  
  20792.    Each code page contains four special code points: a first character, a
  20793.    last character, a default character, and a break character. The default
  20794.    character is the one that appears in text when an application specifies a
  20795.    code point that does not lie between the first and last character code
  20796.    points. The break character is the space character and often has the same
  20797.    code point as the default character.
  20798.  
  20799.    If the current font is the default system font, you can determine the
  20800.    current code page by calling the GpiQueryCp function, or you can assign a
  20801.    new code page by calling the GpiSetCp function. For more information about
  20802.    code pages, see the Microsoft Operating System/2 Programmer's Reference,
  20803.    Volume 3.
  20804.  
  20805.  33.2.5  Text Output
  20806.  
  20807.    Text output is alphanumeric output drawn with characters and symbols from
  20808.    a font. In MS OS/2, fonts are stored either in memory or on devices.
  20809.    Applications access them through a device context associated with the
  20810.    current presentation space. When you create a presentation space by
  20811.    calling the GpiCreatePS or WinGetPS function, MS OS/2 assigns the
  20812.    presentation space a default font from one of the fonts available either
  20813.    in memory or on the associated device. You can retrieve information about
  20814.    this default font by calling the GpiQueryFontMetrics function.
  20815.  
  20816.    33.2.5.1  Text and Character Attributes
  20817.  
  20818.    There are five character attributes that affect the appearance of your
  20819.    application's text output. These character attributes are listed as
  20820.    follows:
  20821.  
  20822.    ■  Character color
  20823.  
  20824.    ■  Character-color mix mode
  20825.  
  20826.    ■  Character angle
  20827.  
  20828.    ■  Character shear
  20829.  
  20830.    ■  Character box
  20831.  
  20832.    There are two character colors: foreground and background. The foreground
  20833.    color is the color of the strokes in each character. The background color
  20834.    is the color that appears behind the character.
  20835.  
  20836.    There are two character mix modes that affect how MS OS/2 combines the
  20837.    character colors with the existing color(s) on your application's drawing
  20838.    surface. The foreground character mix mode is overpaint; the background
  20839.    character mix mode is leave-alone. If the default colors and mix modes do
  20840.    not suit your application, you can change them by calling the GpiSetAttrs
  20841.    function. You can determine the current color and mix-mode settings by
  20842.    calling the GpiQueryAttrs function. For more information about color and
  20843.    mix modes, see Chapter 34, "Color and Mix Modes."
  20844.  
  20845.    A special vector, drawn from the origin of an imaginary Cartesian
  20846.    coordinate system through a specified point, defines the character-angle
  20847.    attribute. MS OS/2 aligns the baseline with this vector. You can retrieve
  20848.    the point that defines the character-angle vector by calling the
  20849.    GpiQueryCharAngle function, or you can set the character angle by calling
  20850.    the GpiSetCharAngle function and passing it the coordinates of a point
  20851.    that defines the new vector.
  20852.  
  20853.    A character box is an imaginary rectangle that applications use to scale
  20854.    characters in a font. You can determine the current character-box
  20855.    dimensions by calling the GpiQueryCharBox function. You can set new
  20856.    character-box dimensions by calling the GpiSetCharBox function. The
  20857.    dimensions that you pass to GpiSetCharBox and the dimensions that
  20858.    GpiQueryCharBox returns are fixed values. A fixed value, which is a
  20859.    representation of a floating-point number, is a 32-bit value whose
  20860.    high-order 16-bits contain the integral part of the floating-point number
  20861.    and whose low-order 16-bits contain the fractional part. The fractional
  20862.    part is the numerator of a fraction whose denominator is fixed at 65,536.
  20863.    If, for example, one of the box dimensions were 7.635 world units, you
  20864.    could obtain the corresponding fixed value by multiplying 7.635 by 65,536
  20865.    and storing the integer part of the result (500,367) in a fixed variable.
  20866.    The high-order 16-bits would contain 0x0007 and the low-order 16-bits
  20867.    would contain 0xA28F.
  20868.  
  20869.    A special vector, drawn from the origin of an imaginary Cartesian
  20870.    coordinate system through a specified point, defines the character-shear
  20871.    attribute. MS OS/2 aligns the vertical lines of the character box and the
  20872.    vertical strokes in a character with this vector. Figure 33.27 shows the
  20873.    effect of shearing a character:
  20874.  
  20875.    ┌────────────────────────────────────────────────────────────────────────┐
  20876.    │ Figure 33.27 can be found in Section 33.2.5.1 of the printed manual.   │
  20877.    └────────────────────────────────────────────────────────────────────────┘
  20878.  
  20879.    Figure 33.27  Character Shear
  20880.  
  20881.    You can determine the current character-shear angle by calling the
  20882.    GpiQueryCharShear function. This function returns a point you can use to
  20883.    determine the shear vector. You can set the character-shear angle by
  20884.    calling the GpiSetCharShear function and passing it a point structure with
  20885.    the appropriate values.
  20886.  
  20887.    33.2.5.2  Character Modes
  20888.  
  20889.    There are three character modes that determine whether MS OS/2 draws text
  20890.    using the current character attributes. When character mode 1 is set and
  20891.    the current font is an image font, MS OS/2 ignores the current shear,
  20892.    angle, and box attributes. When character mode 2 is set and the current
  20893.    font is an image font, MS OS/2 uses the current shear, angle, and box
  20894.    character attributes when it draws image-font text. In the current release
  20895.    of MS OS/2 Presentation Manager, mode 3 is reserved for outline fonts; if
  20896.    an application attempts to draw text output in mode 3 using an image font,
  20897.    MS OS/2 issues an error.
  20898.  
  20899.    Figure 33.28 shows a line drawn at the current character-shear angle and
  20900.    an image-font character drawn after an application set the character mode
  20901.    to 2:
  20902.  
  20903.    ┌────────────────────────────────────────────────────────────────────────┐
  20904.    │ Figure 33.28 can be found in Section 33.2.5.2 of the printed manual.   │
  20905.    └────────────────────────────────────────────────────────────────────────┘
  20906.  
  20907.    Figure 33.28  Image Font and Character Shear
  20908.  
  20909.    Figure 33.29 shows a line drawn at the current character angle and a
  20910.    string of image-font text drawn after an application set the character
  20911.    mode to 2:
  20912.  
  20913.    ┌────────────────────────────────────────────────────────────────────────┐
  20914.    │ Figure 33.29 can be found in Section 33.2.5.2 of the printed manual.   │
  20915.    └────────────────────────────────────────────────────────────────────────┘
  20916.  
  20917.    Figure 33.29  Image Font and Character Angle
  20918.  
  20919.    Figure 33.30 shows two letters of image-font text as they would appear in
  20920.    different sizes of character box after an application set the character
  20921.    mode to 2:
  20922.  
  20923.    ┌────────────────────────────────────────────────────────────────────────┐
  20924.    │ Figure 33.30 can be found in Section 33.2.5.2 of the printed manual.   │
  20925.    └────────────────────────────────────────────────────────────────────────┘
  20926.  
  20927.    Figure 33.30  Image Font and Three Sizes of Character Box
  20928.  
  20929.    You can determine which character mode is set by calling the
  20930.    GpiQueryCharMode function. You can set a new character mode by calling the
  20931.    GpiSetCharMode function.
  20932.  
  20933.    If the current font is an outline font, MS OS/2 always draws text using
  20934.    the current character attributes──regardless of the current character
  20935.    mode.
  20936.  
  20937.    Figure 33.31 shows a vector that corresponds to the current
  20938.    character-shear angle and a character of outline-font text:
  20939.  
  20940.    ┌────────────────────────────────────────────────────────────────────────┐
  20941.    │ Figure 33.31 can be found in Section 33.2.5.2 of the printed manual.   │
  20942.    └────────────────────────────────────────────────────────────────────────┘
  20943.  
  20944.    Figure 33.31  Outline Font and Character Shear
  20945.  
  20946.    Figure 33.32 shows a vector that corresponds to the current character
  20947.    angle and a string of outline-font text:
  20948.  
  20949.    ┌────────────────────────────────────────────────────────────────────────┐
  20950.    │ Figure 33.32 can be found in Section 33.2.5.2 of the printed manual.   │
  20951.    └────────────────────────────────────────────────────────────────────────┘
  20952.  
  20953.    Figure 33.32  Outline Font and Character Angle
  20954.  
  20955.    Figure 33.33 shows two letters of outline-font text as they would appear
  20956.    in different sizes of character box:
  20957.  
  20958.    ┌────────────────────────────────────────────────────────────────────────┐
  20959.    │ Figure 33.33 can be found in Section 33.2.5.2 of the printed manual.   │
  20960.    └────────────────────────────────────────────────────────────────────────┘
  20961.  
  20962.    Figure 33.33  Outline Font and Three Sizes of Character Box
  20963.  
  20964.    In addition to the character-attribute functions, you can use the
  20965.    Presentation Manager transformations to scale, rotate, translate, shear,
  20966.    and reflect text output drawn with an outline font. Figure 33.34 shows a
  20967.    bar graph labeled with outline text that has been rotated 90 degrees:
  20968.  
  20969.    ┌────────────────────────────────────────────────────────────────────────┐
  20970.    │ Figure 33.34 can be found in Section 33.2.5.2 of the printed manual.   │
  20971.    └────────────────────────────────────────────────────────────────────────┘
  20972.  
  20973.    Figure 33.34  Graph with Outline Font
  20974.  
  20975.  33.2.6  Font Files and Dynamic-Link Libraries
  20976.  
  20977.    You can use Font Editor to alter and customize image-font files (files
  20978.    with a .fnt extension). After creating a custom font tailored to your
  20979.    application, you need to turn it into a dynamic-link library that your
  20980.    application can load. Once your application loads this library, it can use
  20981.    any font within it. A dynamic-link library is a collection of code and
  20982.    data segments that applications can access at run time. The code and data
  20983.    in a dynamic-link library is shareable──several applications can access it
  20984.    simultaneously. Dynamic-link libraries that contain fonts are unique; they
  20985.    contain data segments and empty (or useless) code segments. The MS OS/2
  20986.    naming convention for a dynamic-link library requires that the library
  20987.    name end with a .fon extension.
  20988.  
  20989.    The following text explains how you can create a dynamic-link library that
  20990.    contains your custom font. To create a dynamic-link library, you must use
  20991.    masm, the Microsoft Macro Assembler; link, the Microsoft
  20992.    Segmented-Executable linker; and rc, the MS OS/2 Resource Compiler. For
  20993.    this example, assume that your custom font file is named newfont.fnt.
  20994.  
  20995.    After creating your custom font file, you need to create a special
  20996.    assembler file with your editor. You can use the following code fragment
  20997.    as the source code for this file:
  20998.  
  20999.    code segment word   ;makes dummy code segment aligned on word boundary
  21000.    db "empty_segment"  ;initializes a string in dummy segment
  21001.    code ends           ;dummy segment ends here
  21002.    end                 ;terminates source file
  21003.  
  21004.    Call this file generic.asm. Once you have created generic.asm, assemble it
  21005.    with the following command:
  21006.  
  21007.    masm generic
  21008.  
  21009.    After assembling the file, you create a module-definition file. Call this
  21010.    file generic.def. It should contain the following statements:
  21011.  
  21012.    LIBRARY generic
  21013.    SEGMENTS  CODE MOVEABLE
  21014.  
  21015.    The first statement tells the linker that you are creating a library with
  21016.    the module name generic. The second statement tells the linker that the
  21017.    segments in this library are movable code segments.
  21018.  
  21019.    Upon creating generic.def, you start the linker with the following
  21020.    command:
  21021.  
  21022.    link generic,,,,generic.def
  21023.  
  21024.    This command creates an empty executable file called generic.exe.
  21025.  
  21026.    After creating the empty executable file (which is the template for a
  21027.    dynamic-link library), you should create a resource file and call it
  21028.    generic.rc. For example, if your font file is called newfont.fnt, you
  21029.    would place the following statement in generic.rc:
  21030.  
  21031.    FONT 200     newfont.fnt
  21032.  
  21033.    This statement assigns an identifier, 200, to the font resource
  21034.    newfont.fnt.
  21035.  
  21036.    Finally, you should use Resource Compiler to add the font file
  21037.    (newfont.fnt) to the empty dynamic-link library:
  21038.  
  21039.    rc  generic.rc
  21040.  
  21041.    The executable file, generic.exe, now contains your custom fonts. You
  21042.    still must rename this file generic.fon and copy it to a directory pointed
  21043.    to by the libpath command in your config.sys file. After you have done so,
  21044.    you can load the fonts into your application by calling the GpiLoadFonts
  21045.    function and passing it a pointer to the library name, generic, as the
  21046.    second argument.
  21047.  
  21048.  33.2.7  Selecting New Fonts
  21049.  
  21050.    If you need to use a font other than the default system font in your
  21051.    application, you can select a new one by calling the GpiCreateLogFont
  21052.    function. There are two kinds of fonts that you can select: public fonts
  21053.    and private fonts.
  21054.  
  21055.    33.2.7.1  Public Fonts
  21056.  
  21057.    Public fonts are those that a user loads by using the MS OS/2 Presentation
  21058.    Manager Control Panel. There are three dynamic-link libraries that contain
  21059.    Courier, Helvetica, and Times Roman fonts. If you load each library by
  21060.    using Control Panel, a total of 76 public fonts are available to any
  21061.    application that you run. These fonts are available in both outline and
  21062.    image formats in point sizes ranging from 8 to 24 points.
  21063.  
  21064.    You can determine how many public fonts are currently loaded by calling
  21065.    the GpiQueryFonts function and passing it the QF_PUBLIC flag as the second
  21066.    argument, a NULL pointer as the third argument, and a count of 0 as the
  21067.    fourth argument, as shown in the following code fragment:
  21068.  
  21069.    FONTMETRICS fm, afm[80];
  21070.    LONG lCount, lFontCount;
  21071.    HPS hps;
  21072.  
  21073.    lFontCount = GpiQueryFonts(hps,
  21074.        QF_PUBLIC,
  21075.        NULL,   /* queries all public fonts */
  21076.        &lCount,
  21077.        (LONG) (sizeof(fm)),
  21078.        (PFONTMETRICS) afm);
  21079.  
  21080.    You can determine the characteristics of the loaded public fonts by
  21081.    calling GpiQueryFonts and passing it the QF_PUBLIC flag, the count of
  21082.    available fonts returned by the first call, and the address of an array of
  21083.    FONTMETRICS structures, as shown in the following code fragment. MS OS/2
  21084.    copies the attributes of the fonts into the array of FONTMETRICS
  21085.    structures, which you can then examine in order to select a font.
  21086.  
  21087.    lFontCount = GpiQueryFonts(hps,
  21088.        QF_PUBLIC,
  21089.        NULL,
  21090.        &lCount,
  21091.        (LONG) (sizeof(fm)),
  21092.        (PFONTMETRICS) afm);
  21093.  
  21094.    Once you determine which font you need, call the GpiCreateLogFont func-
  21095.    tion, which copies various fields from the FONTMETRICS structure of the
  21096.    desired font into their corresponding fields in a FATTRS structure. The
  21097.    fields in the FATTRS structure describe the face name, code page, maximum
  21098.    baseline extent, and average character width of the font you would like to
  21099.    use. A special field, lMatch, contains a unique identifier that MS OS/2
  21100.    uses to match your request to a font. Another field in the FATTRS
  21101.    structure specifies whether the font should be an image font or an outline
  21102.    font. You can use other fields to request that MS OS/2 synthesize an
  21103.    italic, underscored, strikeout, or bold font.
  21104.  
  21105.    If MS OS/2 returns the value 2 after the call to GpiCreateLogFont, the
  21106.    function was successful. You can begin using the font after you assign it
  21107.    to the application's presentation space by passing the local identifier
  21108.    (lcid) from GpiCreateLogFont to the GpiSetCharSet function.
  21109.  
  21110.    33.2.7.2  Private Fonts
  21111.  
  21112.    Private fonts are fonts that an application loads exclusively for its own
  21113.    use. An application loads a private font when it calls the GpiLoadFonts
  21114.    function and passes it the name of the dynamic-link library that contains
  21115.    the fonts. (Note that in order to load a dynamic-link library of fonts,
  21116.    the library must be in one of the directories pointed to by the libpath
  21117.    command in the config.sys file.)
  21118.  
  21119.    After the application loads the dynamic-link library of fonts, it can
  21120.    determine the characteristics of the fonts in that library by calling the
  21121.    GpiQueryFonts function.
  21122.  
  21123.    You can determine how many private fonts are currently loaded by calling
  21124.    GpiQueryFonts passing it the QF_PRIVATE flag as the second argument, a
  21125.    NULL pointer as the third argument, and a count of 0 as the fourth
  21126.    argument, as shown in the following code fragment.
  21127.  
  21128.    FONTMETRICS fm, afm[80];
  21129.    LONG lCount;
  21130.  
  21131.    lFontCount = GpiQueryFonts(hps,
  21132.        QF_PRIVATE,
  21133.        NULL,   /* queries all private fonts */
  21134.        &lCount,
  21135.        (LONG) (sizeof(fm)),
  21136.        (PFONTMETRICS) afm);
  21137.  
  21138.    You can determine the characteristics of the loaded private fonts by
  21139.    calling GpiQueryFonts and passing it the QF_PRIVATE flag, the count of
  21140.    available fonts returned by the first call, and the address of an array of
  21141.    FONTMETRICS structures, as shown in the following code fragment. MS OS/2
  21142.    copies the font attributes into the array of FONTMETRICS structures, which
  21143.    you can then examine in order to select a font.
  21144.  
  21145.    lFontCount = GpiQueryFonts(hps,
  21146.        QF_PRIVATE,
  21147.        NULL,
  21148.        &lCount,
  21149.        (LONG) (sizeof(fm)),
  21150.        (PFONTMETRICS) afm);
  21151.  
  21152.    Once you determine which font you need, call the GpiCreateLogFont func-
  21153.    tion, which copies various fields from the FONTMETRICS structure into
  21154.    their corresponding fields in a FATTRS structure. The fields in the FATTRS
  21155.    structure describe the face name, code page, maximum baseline extent, and
  21156.    average character width of the font you would like to use. A special
  21157.    field, lMatch, contains a unique identifier that MS OS/2 uses to match
  21158.    your request to a font. Other fields in the FATTRS structure specify
  21159.    whether the font is an outline font or an image font and whether it is
  21160.    proportional or fixed. You can use another of the fields to request that
  21161.    MS OS/2 synthesize an italic, underscored, strikeout, or bold font. The
  21162.    FATTRS structure has the following form:
  21163.  
  21164.    typedef struct _FATTRS {          /* fat */
  21165.        USHORT  usRecordLength;
  21166.        USHORT  fsSelection;
  21167.        LONG    lMatch;
  21168.        CHAR    szFacename[FACESIZE];
  21169.        USHORT  idRegistry;
  21170.        USHORT  usCodePage;
  21171.        LONG    lMaxBaselineExt;
  21172.        LONG    lAveCharWidth;
  21173.        USHORT  fsType;
  21174.        USHORT  fsFontUse;
  21175.    } FATTRS;
  21176.  
  21177.    If MS OS/2 returns the value 2 after the call to GpiCreateLogFont, the
  21178.    function was successful. You can begin using the font after you assign it
  21179.    to the application's presentation space by passing the local identifier
  21180.    (lcid) from GpiCreateLogFont to the GpiSetCharSet function. If MS OS/2
  21181.    returns 1 after you call GpiCreateLogFont, the function was not successful
  21182.    and the new font is the default system font.
  21183.  
  21184.  
  21185.  33.3  Using Fonts and Character Primitives
  21186.  
  21187.    You can use the font and character functions to perform the following
  21188.    tasks:
  21189.  
  21190.    ■  Select a font from the public fonts loaded with Control Panel.
  21191.  
  21192.    ■  Select a font from a library of private fonts loaded by the
  21193.       application.
  21194.  
  21195.    ■  Draw a string of text using the selected font.
  21196.  
  21197.    ■  Scale, translate, and rotate a string of text from an outline font.
  21198.  
  21199.    ■  Scale, shear, and alter the direction of a string of text from image
  21200.       and outline fonts.
  21201.  
  21202.  33.3.1  Selecting a Public Font
  21203.  
  21204.    To select a public font, you must perform the following tasks:
  21205.  
  21206.    ■  Call the GpiQueryFonts function, passing the QF_PUBLIC flag, a NULL
  21207.       pointer to the font's face name, and a count of 0 to determine the
  21208.       number of available public fonts.
  21209.  
  21210.    ■  Copy this number (the GpiQueryFonts return value) into an integer
  21211.       variable.
  21212.  
  21213.    ■  Call GpiQueryFonts again, passing the QF_PUBLIC flag, a NULL pointer to
  21214.       the font's face name, and the count returned by the previous call.
  21215.  
  21216.    ■  Examine the metrics, looking for the face name and attributes of the
  21217.       font that your application needs.
  21218.  
  21219.    ■  Copy the appropriate metrics from the font that suits your application
  21220.       into a FATTRS structure.
  21221.  
  21222.    ■  Initialize a local identifier (lcid) for the new font.
  21223.  
  21224.    ■  Call the GpiCreateLogFont function, passing a local identifier for the
  21225.       font, the address of an empty array of eight characters, and the
  21226.       address of the FATTRS structure.
  21227.  
  21228.    ■  Examine the return value from GpiCreateLogFont. If the function was
  21229.       successful, it should be 2.
  21230.  
  21231.    ■  Pass the local identifier to the etCharSet function, assigning the font
  21232.       to your application's presentation space.
  21233.  
  21234.    The following code fragment shows how to select a Helvetica public font:
  21235.  
  21236.    i = 0;
  21237.    while (!strcomp(afm[i++].szFacename, "Helv"));
  21238.    lFontCount = GpiQueryFonts(hps,
  21239.        QF_PUBLIC,
  21240.        NULL,
  21241.        &lCount,
  21242.        (LONG) (sizeof(fm)),
  21243.        (PFONTMETRICS) afm);
  21244.    lCount = lFontCount;
  21245.    lFontCount = GpiQueryFonts(hps,
  21246.        QF_PUBLIC,
  21247.        NULL,
  21248.        &lCount,
  21249.        (LONG) (sizeof(fm)),
  21250.        (PFONTMETRICS) afm);
  21251.    fat.usRecordLength = sizeof(fat);
  21252.    fat.fsSelection = afm[i].fsSelection;
  21253.    fat.lMatch = afm[i].lMatch;
  21254.    strcpy(fat.szFacename, afm[i].szFacename);
  21255.    fat.idRegistry = afm[i].idRegistry;
  21256.    fat.usCodePage = afm[i].usCodePage;
  21257.    fat.lMaxBaselineExt = afm[i].lMaxBaselineExt;
  21258.    fat.lAveCharWidth = afm[i].lAveCharWidth;
  21259.    fat.fsType = afm[i].fsType;
  21260.    fat.fsFontUse = 0;
  21261.    GpiCreateLogFont(hps,
  21262.        (PSTR8) chName,
  21263.        lcid,
  21264.        (PFATTRS) &fat);
  21265.    GpiSetCharSet(hps, lcid);
  21266.  
  21267.  33.3.2  Drawing Text
  21268.  
  21269.    Before drawing text, you must determine which of the four ext-output
  21270.    functions you should use. The following list describes the specific
  21271.    purpose of each text-output function:
  21272.  
  21273. ╓┌─┌───────────────────┌─────────────────────────────────────────────────────╖
  21274.    Function name       Purpose
  21275.    Function name       Purpose
  21276.    ──────────────────────────────────────────────────────────────────────────
  21277.    GpiCharString       This function draws a string of text starting at the
  21278.                        current position.
  21279.  
  21280.    GpiCharStringAt     This function draws a string of text starting at a
  21281.                        point that you pass as a function argument. It is
  21282.                        identical to a function sequence of GpiMove,
  21283.                        GpiCharString.
  21284.  
  21285.    GpiCharStringPos    This function alters the intercharacter spacing in a
  21286.                        string of text in order to shade a special rectangle
  21287.                        that surrounds a string of text, to draw a string of
  21288.                        text in halftones, or to clip a string of text to a
  21289.                        special rectangle. This function starts drawing the
  21290.                        text at the current position.
  21291.  
  21292.    GpiCharStringPosAt  This function alters the intercharacter spacing in a
  21293.                        string of text in order to shade a special rectangle
  21294.                        that surrounds a string of text, to draw a string of
  21295.                        text in halftones, or to clip a string of text to a
  21296.    Function name       Purpose
  21297.    ──────────────────────────────────────────────────────────────────────────
  21298.                       text in halftones, or to clip a string of text to a
  21299.                        special rectangle. This function starts drawing the
  21300.                        text at a point that you pass as one of the function
  21301.                        arguments.
  21302.    ──────────────────────────────────────────────────────────────────────────
  21303.  
  21304.  
  21305.    The following code fragment shows how to load an array of characters with
  21306.    the string "MS OS/2 Presentation Manager", set the current position to the
  21307.    point (100,100) by calling the GpiMove function, and then draw the string
  21308.    by calling the GpiCharString function:
  21309.  
  21310.    ptl.x = 100; ptl.y = 100;
  21311.    GpiMove (hps, &ptl);
  21312.    GpiCharString(hps, 28L, "MS OS/2 Presentation Manager");
  21313.  
  21314.  33.3.3  Transforming Text from an Outline Font
  21315.  
  21316.    The following code fragment shows how to rotate a string of text 90
  21317.    degrees counterclockwise by using the model transformation:
  21318.  
  21319.    matlfTransform.fxM11 = MAKEFIXED(1, 0);       /* translates text */
  21320.    matlfTransform.fxM12 = MAKEFIXED(0, 0);
  21321.    matlfTransform.lM13 = 0L;
  21322.    matlfTransform.fxM21 = MAKEFIXED(0, 0);
  21323.    matlfTransform.fxM22 = MAKEFIXED(1, 0);
  21324.    matlfTransform.lM23 = 0L;
  21325.    matlfTransform.lM31 = -300L;
  21326.    matlfTransform.lM32 = -100L;
  21327.    matlfTransform.lM33 = 1L;
  21328.    GpiSetModelTransformMatrix(hps, 9L, &matlfTransform,
  21329.        TRANSFORM_REPLACE);
  21330.    matlfTransform.fxM11 = MAKEFIXED(0, 0);       /* rotates text */
  21331.    matlfTransform.fxM12 = MAKEFIXED(1, 0);
  21332.    matlfTransform.lM13 = 0L;
  21333.    matlfTransform.fxM21 = -MAKEFIXED(1, 0);
  21334.    matlfTransform.fxM22 = MAKEFIXED(0, 0);
  21335.    matlfTransform.lM23 = 0L;
  21336.    matlfTransform.lM31 = 0L;
  21337.    matlfTransform.lM32 = 0L;
  21338.    matlfTransform.lM33 = 1L;
  21339.    GpiSetModelTransformMatrix(hps, 9L, &matlfTransform, TRANSFORM_ADD);
  21340.  
  21341.    matlfTransform.fxM11 = MAKEFIXED(1, 0);       /* translates again */
  21342.    matlfTransform.fxM12 = MAKEFIXED(0, 0);
  21343.    matlfTransform.lM13 = 0L;
  21344.    matlfTransform.fxM21 = MAKEFIXED(0, 0);
  21345.    matlfTransform.fxM22 = MAKEFIXED(1, 0);
  21346.    matlfTransform.lM23 = 0L;
  21347.    matlfTransform.lM31 = 300L;
  21348.    matlfTransform.lM32 = 100L;
  21349.    matlfTransform.lM33 = 1L;
  21350.    GpiSetModelTransformMatrix(hps, 9L, &matlfTransform, TRANSFORM_ADD);
  21351.  
  21352.    ptl.x = 100;
  21353.    ptl.y = 100;
  21354.    GpiMove(hps, &ptl);
  21355.    GpiCharString(hps, 28L, "MS OS/2 Presentation Manager");
  21356.  
  21357.  33.3.4  Transforming Text from an Image Font
  21358.  
  21359.    The following code fragment shows how to double the size of the character
  21360.    box, set the character mode to 2, and then print a string of text:
  21361.  
  21362.    GpiQueryCharBox(hps, &sizfxBox);
  21363.    sizfxBox.cx = 2 * sizfxBox.cx;
  21364.    sizfxBox.cy = 2 * sizfxBox.cy;
  21365.    GpiSetCharBox(hps, &sizfxBox);
  21366.    ptl.x = 100;
  21367.    ptl.y = 100;
  21368.    GpiMove(hps, &ptl);
  21369.    GpiCharString(hps, 28L, "MS OS/2 Presentation Manager");
  21370.  
  21371.  
  21372.  33.4  Summary
  21373.  
  21374.    The following list summarizes the MS OS/2 font and character-primitive
  21375.    functions:
  21376.  
  21377.    GpiCharString  Draws a string of text starting at the current position. It
  21378.    sets the current position to the end of the string at the point where the
  21379.    next character would be drawn. All text is drawn using the font assigned
  21380.    to the application's presentation space.
  21381.  
  21382.    GpiCharStringAt  Draws a string of text starting at a point that you
  21383.    specify as a function argument. It updates the current position after
  21384.    drawing each character in the string and, upon completion, sets the
  21385.    current position to the point where the next character would be drawn. All
  21386.    text is drawn using the font assigned to the application's presentation
  21387.    space.
  21388.  
  21389.    GpiCharStringPos  Draws a string of text starting at the current position.
  21390.    It sets the current position to the end of the string at the point where
  21391.    the next character would be drawn. All text is drawn using the font
  21392.    assigned to the application's presentation space. In addition to drawing a
  21393.    string of text, you can use this function to do the following:
  21394.  
  21395.    ■  Adjust spacing between characters in the string.
  21396.  
  21397.    ■  Clip the text to a small rectangle.
  21398.  
  21399.    GpiCharStringPosAt  Draws a string of text starting at a point that you
  21400.    specify as one of the function arguments. It sets the current position to
  21401.    the end of the string at the point where the next character would be
  21402.    drawn. All text is drawn using the font assigned to the application's
  21403.    presentation space. In addition to drawing a string of text, you can use
  21404.    this function to do the following:
  21405.  
  21406.    ■  Adjust spacing between characters in the string.
  21407.  
  21408.    ■  Shade the text by drawing it in halftones.
  21409.  
  21410.    ■  Clip the text to a small rectangle.
  21411.  
  21412.    GpiCreateLogFont  Passes a description of a font to MS OS/2, which
  21413.    attempts to select the closest possible match from available fonts in MS
  21414.    OS/2 or on the device associated with the current presentation space. If
  21415.    the font you request is not available, MS OS/2 selects the default system
  21416.    font. A FATTRS structure contains a description of the requested font.
  21417.    Typically, applications call the GpiQueryFonts function and examine the
  21418.    metrics for a number of fonts in the system and then load the FATTRS
  21419.    structure with values from the metrics of the desired font. If MS OS/2 is
  21420.    successful and finds a font that matches the values in FATTRS, the
  21421.    function returns a value of 2; if MS OS/2 does not find a matching font
  21422.    and substitutes the default system font instead, the function returns a
  21423.    value of 1; if the function fails completely, it returns 0.
  21424.  
  21425.    GpiDeleteSetId  Frees a local identifier (lcid). A local identifier is a
  21426.    long integer value that identifies a particular font that you are using in
  21427.    your application. Once you free a local identifier from a particular font,
  21428.    that font is no longer available for use.
  21429.  
  21430.    GpiLoadFonts  Loads private fonts from a dynamic-link library of fonts so
  21431.    that an application can access them by calling the GpiQueryFonts and
  21432.    GpiCreateLogFont functions. You identify a specific dynamic-link library
  21433.    by passing it the appropriate path and filename as arguments.
  21434.  
  21435.    GpiQueryCharAngle  Retrieves the current value of the character-baseline
  21436.    angle. If the current font is an outline font, the baseline of each
  21437.    character's cell is drawn parallel to this angle. If the current font is
  21438.    an image font, the character-baseline angle uniquely affects the
  21439.    image-font output. If the current font is an image font and the character
  21440.    mode is 1, MS OS/2 ignores the baseline angle. If the current font is an
  21441.    image font, the character mode is 2, and the baseline angle is nonzero, MS
  21442.    OS/2 aligns text with the baseline angle. However, the baseline of each
  21443.    character remains parallel to the x-axis.
  21444.  
  21445.    GpiQueryCharBox  Retrieves the dimensions (in world coordinates) of the
  21446.    character box. If the current font is an outline font, the character-cell
  21447.    dimensions are reduced or expanded to match the character-box dimensions.
  21448.    If the current font is an image font, the character-box dimensions
  21449.    uniquely affect the image-font output. If the current font is an image
  21450.    font and the character mode is 1, MS OS/2 ignores the character-box
  21451.    dimensions when it draws text. If the current font is an image font and
  21452.    the character mode is 2, MS OS/2 increases or reduces the spacing between
  21453.    characters (based on the box dimensions) when it draws text.
  21454.  
  21455.    GpiQueryCharMode  Retrieves the current character-mode attribute. There
  21456.    are three character modes; each affects text output with an image font. In
  21457.    mode 1, MS OS/2 ignores the character angle, box, and shear attributes
  21458.    when drawing text with an image font. In mode 2, MS OS/2 uses each of the
  21459.    attributes when drawing text with an image font. In mode 3, MS OS/2 issues
  21460.    an error if the application attempts to draw text using an image font. An
  21461.    application can use outline fonts for text output in character mode 3
  21462.    only.
  21463.  
  21464.    GpiQueryCharSet  Retrieves the local identifier assigned to the current
  21465.    font.
  21466.  
  21467.    GpiQueryCharShear  Retrieves the current character-shear attribute. The
  21468.    character-shear attribute is a point that defines the angle between the
  21469.    x-axis of a coordinate system and a line drawn from a system's origin
  21470.    through the point. If the current font is an outline font, the sides of
  21471.    the character box are drawn parallel to this angle and the character
  21472.    within the box is slanted accordingly. If the current font is an image
  21473.    font and the character mode is 1, MS OS/2 ignores this attribute when
  21474.    drawing text. If the current font is an image font and the character mode
  21475.    is 2, MS OS/2 draws the sides of the character box parallel to the angle;
  21476.    the character itself remains upright.
  21477.  
  21478.    GpiQueryCharStringPos  Retrieves an array of points that specify the
  21479.    position (in world coordinates) that MS OS/2 would assign to each
  21480.    character in a string of text if the string were drawn by the
  21481.    GpiCharStringPos function.
  21482.  
  21483.    GpiQueryCharStringPosAt  Retrieves an array of points that specify the
  21484.    position (in world coordinates) that MS OS/2 would assign to each
  21485.    character in a string of text if the string were drawn by the
  21486.    GpiCharStringPosAt function.
  21487.  
  21488.    GpiQueryCp  Retrieves the current code-page identifier. A code page is a
  21489.    character set that contains 256 characters. Each character in the code
  21490.    page is assigned a value (called a code point) in the range 0 through 255.
  21491.    A code-page identifier is a three-digit value in the range 0 through 999.
  21492.  
  21493.    GpiQueryDefCharBox  Retrieves the default character-box dimensions (in
  21494.    world coordinates). The default dimensions are assigned by the font's
  21495.    designer.
  21496.  
  21497.    GpiQueryFontFileDescriptions  Retrieves the types and face names of fonts
  21498.    in a file, if that file is a font file.
  21499.  
  21500.    GpiQueryFontMetrics  Retrieves the font metrics for the current logical
  21501.    font.
  21502.  
  21503.    GpiQueryFonts  Retrieves metrics for all of the public or private fonts if
  21504.    the third argument is a NULL pointer. Otherwise, it returns the metrics
  21505.    for fonts with a particular face name. The function returns the metrics in
  21506.    an array of FONTMETRICS structures. A public font is one that MS OS/2
  21507.    loads when a user turns the computer on. A private font is one that an
  21508.    application loads.
  21509.  
  21510.    GpiQueryKerningPairs  Retrieves an array of KERNINGPAIRS structures.
  21511.    Kerning is space that appears between a pair of characters when MS OS/2
  21512.    draws them. By adjusting the kerning between certain characters, you can
  21513.    make text more readable. The KERNINGPAIRS structure contains three fields:
  21514.    The first two identify the characters, and the third specifies the amount
  21515.    of kerning (measured in world coordinates). If this last field contains a
  21516.    negative number, the kerning is reduced by that amount; if the last field
  21517.    contains a positive number, the kerning is increased by that amount.
  21518.  
  21519.    GpiQueryNumberSetIds  Retrieves the number of current local identifiers
  21520.    that an application is using. You can use this value when you call the
  21521.    GpiQuerySetIds function.
  21522.  
  21523.    GpiQueryTextBox  Retrieves the dimensions of a rectangle surrounding a
  21524.    string of text that an application draws using the GpiCharStringPos or
  21525.    GpiCharStringPosAt function. You can use these dimensions to draw a shaded
  21526.    rectangle behind the text.
  21527.  
  21528.    GpiQueryWidthTable  Retrieves width values you can use to determine the
  21529.    average character width of characters in the current logical font. To
  21530.    determine this average character width, you multiply the width values by
  21531.    the factors given in the description of the FONTMETRICS structure.
  21532.  
  21533.    GpiSetCharAngle  Sets the current value of the character-baseline angle.
  21534.    If the current font is an outline font, the baseline of each character's
  21535.    cell is drawn parallel to this angle. If the current font is an image
  21536.    font, the character-baseline angle uniquely affects the image-font output.
  21537.    If the current font is an image font and the character mode is 1, MS OS/2
  21538.    ignores the baseline angle. If the current font is an image font, the
  21539.    character mode is 2, and the baseline angle is nonzero, MS OS/2 aligns
  21540.    text with the baseline angle. However, the baseline of each character
  21541.    remains parallel to the x-axis.
  21542.  
  21543.    GpiSetCharBox  Sets the dimensions (in world coordinates) of the character
  21544.    box. If the current font is an outline font, the character-cell dimensions
  21545.    are reduced or expanded to match the dimensions of the character box. If
  21546.    the current font is an image font, the dimensions of the character box
  21547.    uniquely affect the image-font output. If the current font is an image
  21548.    font and the character mode is 1, MS OS/2 ignores the character-box
  21549.    dimensions when drawing text. If the current font is an image font and the
  21550.    character mode is 2, MS OS/2 increases or reduces the spacing between
  21551.    characters (based on the box dimensions) when drawing text strings.
  21552.  
  21553.    GpiSetCharMode  Sets the current character-mode attribute. There are three
  21554.    character modes; each affects text output with an image font. In mode 1,
  21555.    MS OS/2 ignores the angle, box, and shear attributes when drawing text
  21556.    with an image font. In mode 2, MS OS/2 uses each of the attributes when
  21557.    drawing text with an image font. In mode 3, MS OS/2 issues an error if the
  21558.    application attempts to draw text using an image font. An application can
  21559.    use outline fonts for text output in character mode 3 only.
  21560.  
  21561.    GpiSetCharSet  Assigns a font to a presentation space. The font is
  21562.    identified by a local identifier (lcid).
  21563.  
  21564.    GpiSetCharShear  Sets the current character-shear attribute. The
  21565.    character-shear attribute is a point that defines an angle between the
  21566.    x-axis of a coordinate system and a line drawn from a system's origin
  21567.    through the point. If the current font is an outline font, the sides of
  21568.    the character box are drawn parallel to this angle and the character
  21569.    within the box is slanted accordingly. If the current font is an image
  21570.    font and the character mode is 1, MS OS/2 ignores this attribute when
  21571.    drawing text. If the current font is an image font and the character mode
  21572.    is 2, MS OS/2 draws the sides of the character box parallel to the angle;
  21573.    the character itself remains upright.
  21574.  
  21575.    GpiSetCp  Sets the current code-page identifier. A code page is a
  21576.    character set that contains 256 characters. Each character in the code
  21577.    page is assigned a value (called a code point) in the range 0 through 255.
  21578.    A code-page identifier is a three-digit value in the range 0 through 999.
  21579.  
  21580.    GpiUnloadFonts  Unloads font definitions that were loaded previously from
  21581.    a resource file.
  21582.  
  21583.  
  21584.  
  21585.  ────────────────────────────────────────────────────────────────────────────
  21586.  Chapter 34  Color and Mix Modes
  21587.  
  21588.         34.1    Introduction
  21589.         34.2    About Color and Mix Modes
  21590.             34.2.1    Color and RGB Values
  21591.             34.2.2    Color Tables
  21592.             34.2.3    Color Output and Mix Modes
  21593.             34.2.4    Dithering
  21594.         34.3    Using Colors and Mix Modes
  21595.             34.3.1    Creating a Logical Color Table
  21596.             34.3.2    Determining the Color-Table Format and Index Values
  21597.             34.3.3    Determining an Index Value for an RGB Value
  21598.             34.3.4    Setting the Primitive Color Attributes
  21599.         34.4    Summary
  21600.  
  21601.  34.1  Introduction
  21602.  
  21603.    This chapter describes color and mix modes and their use in MS OS/2
  21604.    applications. You should also be familiar with the following topics:
  21605.  
  21606.    ■  Presentation spaces and device contexts
  21607.  
  21608.    ■  Line and arc primitives
  21609.  
  21610.    ■  Area primitives
  21611.  
  21612.    ■  Character primitives
  21613.  
  21614.    ■  Marker primitives
  21615.  
  21616.  
  21617.  34.2  About Color and Mix Modes
  21618.  
  21619.    Color and mix modes are two primitive attributes. The color attribute
  21620.    describes a line, arc, character, marker, area, or image color before it
  21621.    is combined with the color on the drawing surface. The mix-mode attribute
  21622.    describes how the system combines a primitive's color with the color of
  21623.    the drawing surface. Some primitives have foreground and background color
  21624.    attributes. For instance, the character primitive has a foreground color
  21625.    attribute that specifies the color of the character and a background color
  21626.    attribute that specifies the color surrounding the character. The
  21627.    primitives that have foreground and background attributes also have
  21628.    foreground and background mix modes.
  21629.  
  21630.    To understand color, it is important to understand several principles of
  21631.    color devices. Most color devices can generate three fundamental colors:
  21632.    red, green, and blue. On some devices, each of these three colors
  21633.    corresponds to a color plane──for example, a red pel is visible when a pel
  21634.    in the red plane is on and the corresponding pels in the green and blue
  21635.    planes are off. On other devices, there is only one color plane, and each
  21636.    pel contains a red, a green, and a blue section──for example, a red pel is
  21637.    visible when the red section of that pel is on and the green and blue
  21638.    sections are off. By combining the three fundamental colors, a device can
  21639.    obtain five additional colors, for a total of eight. These eight colors,
  21640.    and the combinations that produce them, are as follows:
  21641.  
  21642.    Resulting   Combined colors
  21643.    color
  21644.    ──────────────────────────────────────────────────────────────────────────
  21645.    Black       Red, green, and blue are off.
  21646.  
  21647.    Red         Red is on; green and blue are off.
  21648.  
  21649.    Green       Green is on; red and blue are off.
  21650.  
  21651.    Blue        Blue is on; red and green are off.
  21652.  
  21653.    Pink        Red and blue are on; green is off.
  21654.  
  21655.    Cyan        Blue and green are on; red is off.
  21656.  
  21657.    Yellow      Red and green are on; blue is off.
  21658.  
  21659.    White       Red, green, and blue are on.
  21660.    ──────────────────────────────────────────────────────────────────────────
  21661.  
  21662.  34.2.1  Color and RGB Values
  21663.  
  21664.    In MS OS/2, the red, green, and blue components of a color are either
  21665.    stored in an RGB structure or stored as a long integer (32-bit) value. The
  21666.    RGB structure has the following format:
  21667.  
  21668.    typedef struct _RGB {     /* rgb */
  21669.        BYTE bBlue;
  21670.        BYTE bGreen;
  21671.        BYTE bRed;
  21672.    } RGB;
  21673.  
  21674.    The RGB value has the following format:
  21675.  
  21676.    0x00RRGGBB.
  21677.  
  21678.    Each field in the RGB structure and each of the last three bytes in the
  21679.    RGB value specify a color intensity in the range 0 through 255, 0 being
  21680.    the lowest intensity, 255 the highest. If a field or byte contains 0, its
  21681.    corresponding color is not visible; if a field or byte contains 128, the
  21682.    color is pale; and if a field or byte contains 255, the color is as
  21683.    intense as the device allows. If all the fields or bytes are set to 0, the
  21684.    corresponding color is black. Similarly, if all the fields or bytes are
  21685.    set to 255, the corresponding color is white.
  21686.  
  21687.    The following list shows the RGB value associated with each of the eight
  21688.    fundamental colors:
  21689.  
  21690.    Color       Associated RGB value
  21691.    ──────────────────────────────────────────────────────────────────────────
  21692.    White       0x00FFFFFF
  21693.  
  21694.    Yellow      0x00FFFF00
  21695.  
  21696.    Pink        0x00FF00FF
  21697.  
  21698.    Cyan        0x0000FFFF
  21699.  
  21700.    Blue        0x000000FF
  21701.  
  21702.    Green       0x0000FF00
  21703.  
  21704.    Red         0x00FF0000
  21705.  
  21706.    Black       0x00000000
  21707.    ──────────────────────────────────────────────────────────────────────────
  21708.  
  21709.  34.2.2  Color Tables
  21710.  
  21711.    A color table is an array of RGB values. There are two kinds of color
  21712.    tables: physical (used by device drivers) and logical (used by
  21713.    applications). The physical color table contains RGB values representing
  21714.    the available colors on a device. The logical color table contains RGB
  21715.    values representing the colors that an application would prefer to use.
  21716.    You can determine which colors are in the physical color table by calling
  21717.    the GpiQueryRealColors function. You can determine which colors are in the
  21718.    current logical color table by calling the GpiQueryLogColorTable function.
  21719.  
  21720.    The following list contains the index values and colors found in a logical
  21721.    color table:
  21722.  
  21723. ╓┌─┌──────┌──────────────────────────────────────────────────────────────────╖
  21724.    Index  Color
  21725.    ──────────────────────────────────────────────────────────────────────────
  21726.    0      Device's background color (white)
  21727.  
  21728.    1      Blue
  21729.  
  21730.    2      Red
  21731.  
  21732.    3      Pink
  21733.  
  21734.    4      Green
  21735.  
  21736.    5      Cyan
  21737.    Index  Color
  21738.    ──────────────────────────────────────────────────────────────────────────
  21739.   5      Cyan
  21740.  
  21741.    6      Yellow
  21742.  
  21743.    7      Neutral color (black)
  21744.  
  21745.    8      Dark gray
  21746.  
  21747.    9      Pale blue
  21748.  
  21749.    10     Pale red
  21750.  
  21751.    11     Pale pink
  21752.  
  21753.    12     Dark green
  21754.  
  21755.    13     Dark cyan
  21756.  
  21757.    14     Brown
  21758.    Index  Color
  21759.    ──────────────────────────────────────────────────────────────────────────
  21760.   14     Brown
  21761.  
  21762.    15     Pale gray
  21763.    ──────────────────────────────────────────────────────────────────────────
  21764.  
  21765.  
  21766.    The value you place in the color field of a primitive-attribute structure
  21767.    (by using GpiSetAttrs) is an index into the logical color table. When MS
  21768.    OS/2 draws the primitive, it searches the physical color table for a color
  21769.    that is the closest approximation to this color index. MS OS/2 then uses
  21770.    this approximate color to draw with.
  21771.  
  21772.    You can replace the default logical color table with a new color table by
  21773.    calling the GpiCreateLogColorTable function. You can also use this
  21774.    function to reset the logical color table to its original values. Either
  21775.    way, once you create a new logical color table (or reset it to its
  21776.    original values), it becomes part of the application's presentation space.
  21777.  
  21778.    For a given device, you can determine the maximum size of the logical
  21779.    color table by using the DevQueryCaps function. This function also returns
  21780.    the maximum number of distinct colors available on a particular device.
  21781.  
  21782.  34.2.3  Color Output and Mix Modes
  21783.  
  21784.    When an application draws a line, arc, character, marker, area, or image,
  21785.    MS OS/2 uses a mix mode to determine the color that appears on a video
  21786.    display, printer, or plotter. A mix mode is a bitwise operation on the
  21787.    color indices in a device's physical color table. For example, suppose an
  21788.    application has set the lColor field in the LINEBUNDLE structure to
  21789.    CLR_BLUE and the usMixMode field in the same structure to FM_OR. The
  21790.    current drawing-surface color is CLR_BACKGROUND. The CLR_BLUE entry
  21791.    corresponds to the color blue in both the presentation space's logical
  21792.    color table and the device's physical color table. The CLR_BACKGROUND
  21793.    entry corresponds to the color white in both the presentation space's
  21794.    logical color table and the device's physical color table. The index value
  21795.    for blue in the device's table is 0x0001, and the index value for white in
  21796.    the device's table is 0x0000. To determine the color of a line, MS OS/2
  21797.    performs a bitwise OR operation on the two index values, as follows:
  21798.  
  21799.          0x0001
  21800.          0x0000
  21801.          ──────
  21802.          0x0001  (Result of bitwise OR)
  21803.  
  21804.    In this case, the result is 0x0001, the index value for blue in the
  21805.    device's color table. This means that a blue line appears when the
  21806.    application calls the GpiLine or GpiPolyLine function.
  21807.  
  21808.    Some of the primitive bundles contain foreground and background colors and
  21809.    mix modes. For instance, the AREABUNDLE structure contains a foreground
  21810.    color that corresponds to the foreground color of the area fill pattern.
  21811.    The AREABUNDLE structure also contains a background color that corresponds
  21812.    to the background color that appears behind the area fill pattern.
  21813.    AREABUNDLE also contains foreground and background mix modes that specify
  21814.    bitwise operations on index values in the device's physical color table.
  21815.  
  21816.    There are 16 foreground mix modes. For each mix mode, the index value for
  21817.    the foreground and current drawing-surface colors (in the device's
  21818.    physical color table) are combined by using one of the bitwise operators.
  21819.    The different foreground mix modes are described in the following list:
  21820.  
  21821. ╓┌─┌───────────────────┌─────────────────────────────────────────────────────╖
  21822.    Mix mode            Description
  21823.    ──────────────────────────────────────────────────────────────────────────
  21824.    FM_AND              Final color's index value is determined by a bitwise
  21825.                        AND operation on the foreground color's index value
  21826.                        and the drawing surface's index value.
  21827.  
  21828.    FM_INVERT           Final color's index value is always the inverse of the
  21829.                        drawing surface's index value.
  21830.  
  21831.    FM_LEAVEALONE       Final color's index value is that of the
  21832.                        drawing-surface color.
  21833.  
  21834.    FM_MASKSRCNOT       Final color's index value is determined by inverting
  21835.                        the drawing surface's index value and performing a
  21836.                        bitwise AND operation on this value and the foreground
  21837.                        color's index value.
  21838.  
  21839.    FM_MERGENOTSRC      Final color's index value is determined by performing
  21840.                        a bitwise AND operation on the drawing surface's index
  21841.                        value and the inverse of the foreground color's index
  21842.    Mix mode            Description
  21843.    ──────────────────────────────────────────────────────────────────────────
  21844.                       value and the inverse of the foreground color's index
  21845.                        value.
  21846.  
  21847.    FM_MERGESRCNOT      Final color's index value is determined by performing
  21848.                        a bitwise AND operation on the foreground color's
  21849.                        index value and the inverse of the drawing-surface
  21850.                        color's index value.
  21851.  
  21852.    FM_NOTCOPYSRC       Final color's index value is the inverse of the
  21853.                        foreground color's index value.
  21854.  
  21855.    FM_NOTMASKSRC       Final color's index value is the inverse of the FM_AND
  21856.                        result.
  21857.  
  21858.    FM_NOTMERGESRC      Final color's index value is always the inverse of the
  21859.                        FM_OR result.
  21860.  
  21861.    FM_NOTXORSRC        Final color's index value is always the inverse of the
  21862.                        FM_XOR result.
  21863.    Mix mode            Description
  21864.    ──────────────────────────────────────────────────────────────────────────
  21865.                       FM_XOR result.
  21866.  
  21867.    FM_ONE              Final color's index value is always 1.
  21868.  
  21869.    FM_OR               Final color's index value is determined by a bitwise
  21870.                        OR operation on the foreground color's index value and
  21871.                        the drawing surface's index value.
  21872.  
  21873.    FM_OVERPAINT        Final color's index value is that of the foreground
  21874.                        color.
  21875.  
  21876.    FM_SUBTRACT         Final color's index value is determined by inverting
  21877.                        the foreground color's index value and performing a
  21878.                        bitwise AND operation on this value and the drawing
  21879.                        surface's index value.
  21880.  
  21881.    FM_XOR              Final color's index value is determined by a bitwise
  21882.                        XOR operation on the foreground color's index value
  21883.                        and the drawing surface's index value.
  21884.    Mix mode            Description
  21885.    ──────────────────────────────────────────────────────────────────────────
  21886.                       and the drawing surface's index value.
  21887.  
  21888.    FM_ZERO             Final color's index value is always zero.
  21889.    ──────────────────────────────────────────────────────────────────────────
  21890.  
  21891.  
  21892.    There are four background mix modes. For each mix mode, the index value
  21893.    for the background color and the current drawing-surface color (in the
  21894.    device's physical color table) are combined using one of the bitwise
  21895.    operators. The different background mix modes are described in the
  21896.    following list:
  21897.  
  21898.    Mix mode            Description
  21899.    ──────────────────────────────────────────────────────────────────────────
  21900.    BM_LEAVEALONE       Final color's index value is that of the
  21901.                        drawing-surface color.
  21902.  
  21903.    BM_OR               Final color's index value is determined by a bitwise
  21904.                        OR operation on the background color's index value and
  21905.                        the drawing surface's index value.
  21906.  
  21907.    BM_OVERPAINT        Final color's index value is that of the background
  21908.                        color.
  21909.  
  21910.    BM_XOR              Final color's index value is determined by a bitwise
  21911.                        XOR operation on the background color's index value
  21912.                        and the drawing surface's index value.
  21913.    ──────────────────────────────────────────────────────────────────────────
  21914.  
  21915.  34.2.4  Dithering
  21916.  
  21917.    If you request a color that isn't available in the physical color table,
  21918.    MS OS/2 obtains the closest match by a process called dithering. For
  21919.    example, if the physical color table does not contain a certain shade of
  21920.    gray, MS OS/2 can create what appears to be a gray by mixing black pels
  21921.    and white pels. Similarly, if the physical color table does not contain a
  21922.    light green color but does contain a yellow and a green, MS OS/2 can
  21923.    create what appears to be light green by mixing yellow pels and green
  21924.    pels.
  21925.  
  21926.    Dithering is especially important on monochrome devices. By combining
  21927.    various combinations of black pels with white pels, MS OS/2 can create
  21928.    numerous shades of gray.
  21929.  
  21930.  
  21931.  34.3  Using Colors and Mix Modes
  21932.  
  21933.    You can use the color and mix-mode functions to perform the following
  21934.    tasks:
  21935.  
  21936.    ■  Create a logical color table.
  21937.  
  21938.    ■  Determine the format and the starting and ending index values of the
  21939.       current logical color table.
  21940.  
  21941.    ■  Determine the index value for an entry in the logical color table that
  21942.       is the closest match to an RGB value.
  21943.  
  21944.    ■  Determine the RGB value associated with a particular entry in the
  21945.       logical color table.
  21946.  
  21947.    ■  Determine and set the current foreground and background colors.
  21948.  
  21949.    ■  Determine and set the current foreground and background mix modes.
  21950.  
  21951.  34.3.1  Creating a Logical Color Table
  21952.  
  21953.    To create a logical color table, you must perform the following tasks:
  21954.  
  21955.    1.  Create an array of RGB values that will replace the existing logical
  21956.        color table.
  21957.  
  21958.    2.  Call the GpiCreateLogColorTable function, using the LCOL_RESET and
  21959.        LCOLF_CONSECRGB flags.
  21960.  
  21961.    The following code fragment demonstrates this process:
  21962.  
  21963.    LONG alTable[] = {
  21964.        0xFFFFFF,  /* white */
  21965.        0xEDEDED,
  21966.        0xDBDBDB,
  21967.        0xC9C9C9,
  21968.        0xB7B7B7,
  21969.        0xA6A6A6,
  21970.        0x949494,
  21971.        0x828282,
  21972.        0x707070,
  21973.        0x5E5E5E,
  21974.        0x4D4D4D,
  21975.        0x3B3B3B,
  21976.        0x292929,
  21977.        0x171717,
  21978.        0x050505,
  21979.        0x000000 }; /* black */
  21980.  
  21981.    GpiCreateLogColorTable(hps,
  21982.        LCOL_RESET,      /* begins with default         */
  21983.        LCOLF_CONSECRGB, /* consecutive RGB values      */
  21984.        0L,              /* starting index in table     */
  21985.        16L,             /* number of elements in table */
  21986.        alTable);
  21987.  
  21988.  34.3.2  Determining the Color-Table Format and Index Values
  21989.  
  21990.    To determine the format and the starting and ending index values of the
  21991.    current logical color table, you can call the GpiQueryColorData function.
  21992.    The following code fragment calls GpiQueryColorData to determine whether
  21993.    the default logical color table is loaded and, if so, loads a new table:
  21994.  
  21995.    LONG lClrData[3];
  21996.        .
  21997.        .
  21998.        .
  21999.    GpiQueryColorData(hps, 3L, lClrData);
  22000.    if (lClrData == LCOLF_DEFAULT)
  22001.        GpiCreateLogColorTable(hps,
  22002.            LCOL_RESET,      /* begins with default         */
  22003.            LCOLF_CONSECRGB, /* consecutive RGB values      */
  22004.            0L,              /* starting index in table     */
  22005.            16L,             /* number of elements in table */
  22006.            alTable);
  22007.  
  22008.  34.3.3  Determining an Index Value for an RGB Value
  22009.  
  22010.    To determine the logical-color-table index value associated with an RGB
  22011.    value, you can call the GpiQueryColorIndex function. The following code
  22012.    fragment shows how to determine which index value matches the RGB value
  22013.    for pink (0x00FF00FF) and then use that index entry to set the foreground
  22014.    color to pink for each of the primitive attributes:
  22015.  
  22016.    LONG lIndex = 255;    /* logical-color-table index */
  22017.  
  22018.    lIndex = GpiQueryColorIndex(hps, LCOLOPT_REALIZED, 0x00FF00FF);
  22019.    if ((lIndex>= 0) && (lIndex <= 15))    /* checks for valid index */
  22020.        GpiSetColor(hps, lIndex);
  22021.  
  22022.  34.3.4  Setting the Primitive Color Attributes
  22023.  
  22024.    To set the color attributes for a single primitive, you can call the
  22025.    GpiSetAttrs function, or you can set the color attributes for all of the
  22026.    primitives in a presentation space by calling the GpiSetColor and
  22027.    GpiSetBackColor functions.
  22028.  
  22029.    The following code fragment shows how to use GpiSetAttrs to set the
  22030.    line-primitive color attribute to dark gray:
  22031.  
  22032.    LINEBUNDLE lbnd; /* line-primitive attribute bundle */
  22033.  
  22034.    lbnd.lColor = CLR_DARKGRAY;
  22035.    GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lbnd);
  22036.  
  22037.    The next code fragment shows how to use GpiSetColor to set the foreground
  22038.    color attribute for all of the primitives to dark gray:
  22039.  
  22040.    GpiSetColor(hps, CLR_DARKGRAY);
  22041.  
  22042.  
  22043.  34.4  Summary
  22044.  
  22045.    The following list summarizes the MS OS/2 color and mix-mode functions:
  22046.  
  22047.    GpiCreateLogColorTable  Creates a table of colors for an application.
  22048.    After you call this function, MS OS/2 creates the closest match to the
  22049.    ideal colors in your logical color table by mapping colors from the
  22050.    device's physical color table and then dithering them.
  22051.  
  22052.    GpiQueryBackColor  Retrieves the current background color. If the
  22053.    background colors were set by the GpiSetBackColor function, the color
  22054.    returned by GpiQueryBackColor is the background color for line, character,
  22055.    marker, and bitmap operations. If the background colors were set by the
  22056.    GpiSetAttrs function, the color returned by GpiQueryBackColor is the
  22057.    background color for character output only.
  22058.  
  22059.    GpiQueryBackMix  Retrieves the current background mix mode. If the
  22060.    background mix mode was set by the GpiSetBackMix function, the mix mode
  22061.    returned by GpiQueryBackMix is the background mix mode for line,
  22062.    character, marker, and bitmap operations. If the background mix mode was
  22063.    set by the GpiSetAttrs function, the mix mode returned by GpiQueryBackMix
  22064.    is the background mix mode for character output only.
  22065.  
  22066.    GpiQueryColor  Retrieves the current foreground color. If the foreground
  22067.    color was set by the GpiSetColor function, the color returned by
  22068.    GpiQueryColor is the foreground color for line, character, marker, and
  22069.    bitmap operations. If the foreground color was set by the GpiSetAttrs
  22070.    function, the color returned by GpiQueryColor is the foreground color for
  22071.    character output only.
  22072.  
  22073.    GpiQueryColorData  Retrieves information about the current logical color
  22074.    table. This information includes the format and the starting and ending
  22075.    index values of the current logical color table.
  22076.  
  22077.    GpiQueryColorIndex  Retrieves the index value for the logical-color-table
  22078.    entry that is the closest possible match to a specified RGB value.
  22079.  
  22080.    GpiQueryLogColorTable  Retrieves information about the current logical
  22081.    color table.
  22082.  
  22083.    GpiQueryMix  Retrieves the value of the current foreground-color mix-mode
  22084.    attribute.
  22085.  
  22086.    GpiQueryNearestColor  Retrieves the RGB value for an available color on
  22087.    the current output device that is the closest possible color match to a
  22088.    specified RGB value.
  22089.  
  22090.    GpiQueryRGBColor  Retrieves the RGB value associated with a
  22091.    logical-color-table index.
  22092.  
  22093.    GpiQueryRealColors  Retrieves the RGB values for actual colors in the
  22094.    device's color table.
  22095.  
  22096.    GpiRealizeColorTable  Not supported in the current release of Presentation
  22097.    Manager for MS OS/2.
  22098.  
  22099.    GpiUnrealizeColorTable  Not supported in the current release of
  22100.    Presentation Manager for MS OS/2.
  22101.  
  22102.    GpiSetBackColor  Sets the background color for line, character, marker,
  22103.    and bitmap operations.
  22104.  
  22105.    GpiSetBackMix  Sets the background mix mode for line, character, marker,
  22106.    and bitmap operations.
  22107.  
  22108.    GpiSetColor  Sets the foreground color for line, character, marker, and
  22109.    bitmap operations.
  22110.  
  22111.    GpiSetMix  Sets the foreground mix mode for line, character, marker, and
  22112.    bitmap operations.
  22113.  
  22114.  
  22115.  
  22116.  ────────────────────────────────────────────────────────────────────────────
  22117.  Chapter 35  Paths
  22118.  
  22119.         35.1    Introduction
  22120.         35.2    About Paths
  22121.             35.2.1    Geometric Lines
  22122.             35.2.2    Polygons and Other Shapes
  22123.             35.2.3    Fill Modes
  22124.                 35.2.3.1   Alternate Mode
  22125.                 35.2.3.2   Winding Mode
  22126.             35.2.4    Clip Paths
  22127.         35.3    Using Paths
  22128.             35.3.1    Drawing a Geometric Line
  22129.             35.3.2    Drawing a Filled Polygon
  22130.             35.3.3    Creating a Clip Path
  22131.         35.4    Summary
  22132.  
  22133.  35.1  Introduction
  22134.  
  22135.    This chapter describes a graphics object called a path. You should also be
  22136.    familiar with the following topics:
  22137.  
  22138.    ■  Presentation spaces and device contexts
  22139.  
  22140.    ■  Line and arc primitives
  22141.  
  22142.    ■  Color and mix modes
  22143.  
  22144.    ■  Area primitives
  22145.  
  22146.    ■  Clipping
  22147.  
  22148.  
  22149.  35.2  About Paths
  22150.  
  22151.    A path is a figure that is filled or outlined. You can use paths to draw
  22152.    geometric (wide) lines, create nonrectangular clipping regions, and
  22153.    outline and/or fill irregular shapes and polygons.
  22154.  
  22155.    Paths provide the only means of drawing lines that are wider than one pel
  22156.    (pixel); the only means of clipping to circular, elliptical, or other
  22157.    nonrectangular regions; and the only means of generating filled or
  22158.    outlined irregular shapes and polygons (including triangles, trapezoids,
  22159.    rhomboids, and other nonrectangular regions). To generate filled or
  22160.    outlined rectangles, you can use the GpiBox function, and to generate
  22161.    filled or outlined circles and ellipses, you can use the GpiFullArc
  22162.    function.
  22163.  
  22164.    A path is similar to another graphics object called an area, but there are
  22165.    fundamental differences between the two objects. The interior of an area
  22166.    is always filled, while the interior of a path can be empty. Even when the
  22167.    interior of a path is empty, the borders are visible. Paths with empty
  22168.    interiors are called stroked paths because their visible borders are
  22169.    drawn, or "stroked." Another difference is in the use of paths and areas.
  22170.    Applications perform clipping operations by using paths but not by using
  22171.    areas. For more information about areas, see Chapter 36, "Area
  22172.    Primitives."
  22173.  
  22174.    There are two operations that an application can perform on a path: stroke
  22175.    and fill. You use a stroked path to draw geometric lines and to outline
  22176.    polygons. You use a filled path to fill the interior of polygons. Figure
  22177.    35.1 shows a rectangle that is drawn first as a stroked path and then as
  22178.    a filled path:
  22179.  
  22180.    ┌────────────────────────────────────────────────────────────────────────┐
  22181.    │ Figure 35.1 can be found in Section 35.2 of the printed manual.        │
  22182.    └────────────────────────────────────────────────────────────────────────┘
  22183.  
  22184.    Figure 35.1  Stroked and Filled Rectangles
  22185.  
  22186.    When MS OS/2 strokes a path, it generates a geometric line along the
  22187.    original line that defined the path. The end result is like the stroke of
  22188.    a brush. When MS OS/2 fills a path, it fills the region surrounded by the
  22189.    original line that defined the path. If this original line did not close
  22190.    the region, MS OS/2 automatically closes the region and fills the path.
  22191.  
  22192.    The functions that generate a path are always enclosed in a path bracket.
  22193.    The GpiBeginPath function defines the beginning of a path bracket, and the
  22194.    GpiEndPath function defines the end of a path bracket. The functions you
  22195.    can use within a path bracket are as follows:
  22196.  
  22197.    ■  GpiBeginElement
  22198.  
  22199.    ■  GpiBox
  22200.  
  22201.    ■  GpiCallSegmentMatrix
  22202.  
  22203.    ■  GpiCharString
  22204.  
  22205.    ■  GpiCharStringAt
  22206.  
  22207.    ■  GpiCharStringPos
  22208.  
  22209.    ■  GpiCharStringPosAt
  22210.  
  22211.    ■  GpiCloseFigure
  22212.  
  22213.    ■  GpiComment
  22214.  
  22215.    ■  GpiCreateLogFont
  22216.  
  22217.    ■  GpiDeleteElement (retain mode only)
  22218.  
  22219.    ■  GpiDeleteElementRange (retain mode only)
  22220.  
  22221.    ■  GpiDeleteElementsBetweenLabels (retain mode only)
  22222.  
  22223.    ■  GpiDeleteSetId
  22224.  
  22225.    ■  GpiElement
  22226.  
  22227.    ■  GpiEndElement
  22228.  
  22229.    ■  GpiEndPath
  22230.  
  22231.    ■  GpiFullArc
  22232.  
  22233.    ■  GpiGetData
  22234.  
  22235.    ■  GpiLabel
  22236.  
  22237.    ■  GpiLine
  22238.  
  22239.    ■  GpiMarker
  22240.  
  22241.    ■  GpiMove
  22242.  
  22243.    ■  GpiOffsetElementPointer
  22244.  
  22245.    ■  GpiPartialArc
  22246.  
  22247.    ■  GpiPointArc
  22248.  
  22249.    ■  GpiPolyFillet
  22250.  
  22251.    ■  GpiPolyFilletSharp
  22252.  
  22253.    ■  GpiPolyLine
  22254.  
  22255.    ■  GpiPolyMarker
  22256.  
  22257.    ■  GpiPolySpline
  22258.  
  22259.    ■  GpiPop
  22260.  
  22261.    ■  GpiPutData
  22262.  
  22263.    ■  GpiQueryArcParams (not valid in retain mode)
  22264.  
  22265.    ■  GpiQueryAttrMode
  22266.  
  22267.    ■  GpiQueryCurrentPosition (not valid in retain mode)
  22268.  
  22269.    ■  GpiSetArcParams
  22270.  
  22271.    ■  GpiSetAttrMode
  22272.  
  22273.    ■  GpiSetAttrs
  22274.  
  22275.    ■  GpiSetCharAngle
  22276.  
  22277.    ■  GpiSetCharBox
  22278.  
  22279.    ■  GpiSetCharDirection
  22280.  
  22281.    ■  GpiSetCharMode
  22282.  
  22283.    ■  GpiSetCharSet
  22284.  
  22285.    ■  GpiSetCharShear
  22286.  
  22287.    ■  GpiSetColor
  22288.  
  22289.    ■  GpiSetCp
  22290.  
  22291.    ■  GpiSetCurrentPosition
  22292.  
  22293.    ■  GpiSetEditMode
  22294.  
  22295.    ■  GpiSetElementPointer (not valid in retain mode)
  22296.  
  22297.    ■  GpiSetElementPointerAtLabel (not valid in retain mode)
  22298.  
  22299.    ■  GpiSetLineEnd
  22300.  
  22301.    ■  GpiSetLineJoin
  22302.  
  22303.    ■  GpiSetLineType
  22304.  
  22305.    ■  GpiSetLineWidth
  22306.  
  22307.    ■  GpiSetMarker
  22308.  
  22309.    ■  GpiSetMarkerBox
  22310.  
  22311.    ■  GpiSetMarkerSet
  22312.  
  22313.    ■  GpiSetMix
  22314.  
  22315.    ■  GpiSetModelTransformMatrix
  22316.  
  22317.  35.2.1  Geometric Lines
  22318.  
  22319.    A geometric line is a stroked path that your application can scale by
  22320.    using one of the scaling transformations. Geometric lines can be wider
  22321.    than one pel. When you draw geometric lines, you use the same functions
  22322.    you would use to draw normal lines: GpiMove, GpiLine, GpiPolyLine,
  22323.    GpiPartialArc, and so on. But you must enclose these functions in a path
  22324.    bracket.
  22325.  
  22326.    In the floor plan shown in Figure 35.2, the outer walls were drawn using
  22327.    geometric lines. All of the other objects were drawn using normal lines.
  22328.  
  22329.    ┌────────────────────────────────────────────────────────────────────────┐
  22330.    │ Figure 35.2 can be found in Section 35.2.1 of the printed manual.      │
  22331.    └────────────────────────────────────────────────────────────────────────┘
  22332.  
  22333.    Figure 35.2  Geometric Lines and Normal Lines
  22334.  
  22335.    After constructing a path bracket for a geometric line, you must specify a
  22336.    line-end style, a line-join style, and a line width. To specify the
  22337.    line-end style, you call the GpiSetLineEnd function; to specify the
  22338.    line-join style, you call the GpiSetLineJoin function; and to specify the
  22339.    line width, you call the GpiSetLineWidthGeom function. Once you have
  22340.    completed these steps, you can draw the line by calling the GpiStrokePath
  22341.    function.
  22342.  
  22343.  35.2.2  Polygons and Other Shapes
  22344.  
  22345.    As noted earlier, the GpiFullArc function can generate filled or outlined
  22346.    circles and ellipses, and the GpiBox function can generate filled or
  22347.    outlined rectangles. But to generate filled or outlined regions that are
  22348.    not circular, elliptical, or rectangular, you should use the path
  22349.    functions.
  22350.  
  22351.    Figure 35.3 shows outlines of a trapezoid, a rhomboid, and a rhombus,
  22352.    each constructed by calling the GpiBeginPath, GpiPolyLine, GpiEndPath, and
  22353.    GpiStrokePath functions:
  22354.  
  22355.    ┌────────────────────────────────────────────────────────────────────────┐
  22356.    │ Figure 35.3 can be found in Section 35.2.2 of the printed manual.      │
  22357.    └────────────────────────────────────────────────────────────────────────┘
  22358.  
  22359.    Figure 35.3  Stroked Paths
  22360.  
  22361.    Figure 35.4 shows the same quadrilaterals, only this time they were
  22362.    filled by calling the GpiFillPath function:
  22363.  
  22364.    ┌────────────────────────────────────────────────────────────────────────┐
  22365.    │ Figure 35.4 can be found in Section 35.2.2 of the printed manual.      │
  22366.    └────────────────────────────────────────────────────────────────────────┘
  22367.  
  22368.    Figure 35.4  Filled Paths
  22369.  
  22370.  35.2.3  Fill Modes
  22371.  
  22372.    To fill a path, MS OS/2 uses one of two methods, called fill modes. You
  22373.    can select the mode──either alternate or winding──when you call
  22374.    GpiFillPath. If the path consists of multiple intersecting regions, the
  22375.    mode will affect the final appearance of the path. Figure 35.5 shows two
  22376.    identical paths that were filled using the two modes. Each path consists
  22377.    of a triangle drawn within a rectangle. The path on the left was filled
  22378.    using the alternate mode, the path on the right was filled using the
  22379.    winding mode.
  22380.  
  22381.    ┌────────────────────────────────────────────────────────────────────────┐
  22382.    │ Figure 35.5 can be found in Section 35.2.3 of the printed manual.      │
  22383.    └────────────────────────────────────────────────────────────────────────┘
  22384.  
  22385.    Figure 35.5  Fill Modes
  22386.  
  22387.    35.2.3.1  Alternate Mode
  22388.  
  22389.    When an application specifies the alternate mode, MS OS/2 performs a test
  22390.    on pels inside the path's boundary lines. This test involves the following
  22391.    steps:
  22392.  
  22393.    1.  Select a pel within the path's boundary lines.
  22394.  
  22395.    2.  Draw an imaginary ray, in the positive x-direction, from that pel
  22396.        towards infinity.
  22397.  
  22398.    3.  Highlight the pel if the ray intersects the boundary lines of the path
  22399.        an odd number of times.
  22400.  
  22401.    Figure 35.6 shows how MS OS/2 would perform this test on the path shown
  22402.    in Figure 35.5:
  22403.  
  22404.    ┌──────