home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / docs / rwpos2.inf (.txt) < prev    next >
Encoding:
OS/2 Help File  |  1993-10-28  |  121.8 KB  |  3,367 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Title Page and Book Information ΓòÉΓòÉΓòÉ
  3.  
  4.                        Real-World Programming for OS/2 2.1
  5.  
  6.                                   Derrel Blain
  7.  
  8.                                   Kurt Delimon
  9.  
  10.                                   Jeff English
  11.  
  12.  
  13. ΓòÉΓòÉΓòÉ 2. Copyright ΓòÉΓòÉΓòÉ
  14.  
  15.         This book is dedicated to our wives, Laurie, Beth, and September,
  16.                 each of whom is a professional in her own right.
  17.                  Thanks for enabling us to take the time out of
  18.               our lives and the general business of living to spend
  19.                      even more time glued to our computers.
  20.  
  21. (C) 1993 by Sams 
  22.  
  23. All rights reserved. No part of this book shall be reproduced, stored in a 
  24. retrieval system, or transmitted by any means, electronic, mechanical, 
  25. photocopying, recording, or otherwise, without written permission from the 
  26. publisher. No patent liability is assumed with respect to the use of the 
  27. information contained herein. Although every precaution has been taken in the 
  28. preparation of this book, the publisher and author assume no responsibility for 
  29. errors or omissions. Neither is any liability assumed for damages resulting 
  30. from the use of the information contained herein. For information, address Sams 
  31. Publishing, 11711 N. College Ave., Carmel, IN 46032. 
  32.  
  33. International Standard Book Number: 0-672-30300-0
  34.  
  35. Library of Congress Catalog Card Number: 92-82105
  36.  
  37. 96   95   94   93       4   3   2   1
  38.  
  39. Interpretation of the printing code: the rightmost double-digit number is the 
  40. year of the book's printing; the rightmost single-digit, the number of the 
  41. book's printing. For example, a printing code of 93-1 shows that the first 
  42. printing of the book occurred in 1993. 
  43. Trademarks 
  44.  
  45. All terms mentioned in this book that are known to be trademarks or service 
  46. marks have been appropriately capitalized. Sams Publishing cannot attest to the 
  47. accuracy of this information. Use of a term in this book should not be regarded 
  48. as affecting the validity of any trademark or service mark. OS/2 is a 
  49. registered trademark of International Business Machines Corporation. 
  50.  
  51. Screen reproductions in this book were created by means of the program Collage 
  52. Plus from Inner Media, Inc., Hollis, NH. 
  53.  
  54. Composed in AGaramond and MCPDigital by Prentice Hall Computer Publishing 
  55.  
  56. Printed in the United States of America 
  57.  
  58.  
  59. ΓòÉΓòÉΓòÉ 3. Ordering Information ΓòÉΓòÉΓòÉ
  60.  
  61. Sams 
  62.  
  63. To order this book or any Sams publication, call 1-800-428-5331 between 9m. and 
  64. 5m. EST.  For faster service please have your credit card available. 
  65.  
  66. I.V. League 
  67.  
  68. To receive a free copy of the PSP Product Catalog, or to order any of the books 
  69. reviewed here, please call 1-800-342-6672.  All orders are shipped next day 
  70. air. 
  71.  
  72.  
  73. ΓòÉΓòÉΓòÉ 4. Foreword ΓòÉΓòÉΓòÉ
  74.  
  75. In our five years of publishing for OS/2 application developers, we have 
  76. learned what programmers need: real-life, function-filled, practical 
  77. programming examples. Both new and intermediate developers seem to learn best 
  78. from good source code samples. Often, they will cut and paste, building a new 
  79. application on a working base, learning as they go. 
  80.  
  81. Real-World Programming for OS/2 2.1 understands and meets that need. This book 
  82. is filled with practical, meaty tips and techniques about OS/2 programming. The 
  83. authors deliver their considerable experience in the form of useful sample 
  84. programs and narrative. They have tested their code on four popular OS/2 
  85. compilers, and they have provided it on a diskette for the convenience of their 
  86. readers. 
  87.  
  88. This book sets a new standard in practical programming. The authors are to be 
  89. congratulated! 
  90.  
  91. Dick Conklin
  92. Editor
  93. OS/2 Developer Magazine
  94.  
  95.  
  96. ΓòÉΓòÉΓòÉ 5. Acknowledgments ΓòÉΓòÉΓòÉ
  97.  
  98. We would like to say thanks to some of the many individuals who helped us in 
  99. this project. Thanks to Karen Ali and Mike Polla of Watcom, David Intersimone 
  100. and Dan Horn of Borland, Constantine of Zortech, and David Mooney and Maxine 
  101. Houghton of IBM. Thanks also to Andy Cohen of Micrografx. 
  102.  
  103.  
  104. ΓòÉΓòÉΓòÉ 6. Table of Contents ΓòÉΓòÉΓòÉ
  105.  
  106. Foreword
  107.  
  108. Programming for OS/2
  109.   The Nature of This Book
  110.   Compilers Used
  111.   Building the Applications
  112.   Installing Your Compiler
  113.   Installing the Software
  114.   Building a Sample Application
  115.   Heading Out on Your Own
  116.  
  117. OS/2 Application Window Fundamentals
  118.   Windows
  119.   Parent-Child Relationship
  120.   Ownership
  121.   Messages
  122.   The Window Procedure
  123.   Window Procedures Return Values
  124.   SKELETON Application
  125.   Component Files
  126.   SKELETON.C
  127.   The Main Procedure
  128.   Creating the Application Window
  129.   Message Queues
  130.   Registering a Class
  131.   Loading a String
  132.   SKELETON.H
  133.   SKELETON.RC
  134.   Compiling SKELTON.RC
  135.   SKELETON.DEF
  136.   SKELETON.ICO
  137.   Using the SKELETON Application
  138.   Useful Window Reference Material
  139.   Common Window Functions
  140.   Standard Window Classes
  141.   Class Styles
  142.   Standard Window Styles
  143.   Dialog Manager Styles
  144.   Frame Control Flags
  145.   Frame Contol Identifiers
  146.   Predefined Window Handles
  147.   Includes
  148.  
  149. Window Management
  150.   Introduction
  151.   The Family Tree
  152.   A Look at the Frame Window
  153.   Window Characteristics
  154.   Window Data
  155.   Window Sizing and Positioning
  156.   Window Focus and Activation
  157.   Application Activation
  158.   Window Subclassing
  159.   Titlebar Painting
  160.   Mouse Pointer
  161.   Preventing Window Tracking
  162.   Restricting a Window's Size
  163.   Window Icons
  164.   Message Processing
  165.   WM_USER Messages
  166.   Multiple Document Interface Application
  167.   MINIMDI.RC
  168.   TOOLBAR.DLG
  169.   WININFO.DLG
  170.   MINIMDI.C
  171.   MINIMDI.H
  172.   MINIMDI.DEF
  173.   How MINIMDI Works
  174.  
  175. 2.1 Common Dialogs
  176.   Introduction to Common Dialogs
  177.   Practice with the CONTROL Sample Application
  178.   The File Menu
  179.   The Font Menu
  180.   Development of the Sample
  181.   File Dialog
  182.   Creating a Simple Application
  183.   The FILEDLG Structure
  184.   Using Nondefault Values
  185.   Custom Template
  186.   Multiple File Selection
  187.   Save As Dialog
  188.   Font Dialog
  189.   Understanding the Basics of Fonts
  190.   Font Representation
  191.   The Common Font API
  192.   Basic File Dialog
  193.   Changing the Font
  194.   Font as Logical Resource
  195.   Making the Dialog Modeless
  196.   Font Notification Messages
  197.   Owner Draw Preview
  198.   The CONTROL Sample Application
  199.   Files to Build the CONTROL Sample
  200.   COMMDLG.C
  201.   COMMDLG.H
  202.   COMMDLG.RC
  203.   CUSTOM .DLG
  204.   COMMDLG.DEF
  205.  
  206. Menus
  207.   Introduction
  208.   Types of Menus
  209.   Pull-Down and Cascaded Menus
  210.   Pop-Up Menus
  211.   Menu Components
  212.   Menu Hierarchy
  213.   Menu Window Styles
  214.   Menu Items
  215.   Specifying Menus in the RC File
  216.   Menu Messages
  217.   Menu Notification Messages
  218.   Menu Item Selection
  219.   Menu Application
  220.   Menu Application Files
  221.   MENU.C
  222.   MENU.H
  223.   MENUXTRA.H
  224.   MENU.RC
  225.   MENU.DEF
  226.   Using the Menu Application
  227.   Basic Menu and Changing Menu Items
  228.   Changing the Menu Item Checkmark
  229.   Bitmap Menu Items
  230.   OWNERDRAW Menu Items
  231.   Pop-Up Menu Window
  232.   Replacing the Actionbar Menu
  233.   Using the Same Submenu in Multiple Menus
  234.   Changing the System Menu
  235.   Menu Messages
  236.   Menu Messages
  237.   MM_QUERYSELITEMID_ 0x018a
  238.   Menu Notification Messages
  239.  
  240. Presentation Spaces and Drawing
  241.   Introduction of GPI
  242.   Presentation Spaces (PS)
  243.   Types of Presentation Spaces
  244.   WM_PAINT & WM_ERASEBACKGROUND
  245.   Summary of Presentation Space Functions
  246.   Cached Micro Presentation Spaces
  247.   hPS WinGetPS (hWnd)
  248.   hPS WinBeginPaint(hWnd,hPS,pRectl)
  249.   Micro or Normal Presentation Spaces
  250.   hPS GpiCreatePS (hAB,hDC,pSizel,lOptions)
  251.   hPS WinBeginPaint(hWnd,hPS,pRectl)
  252.   GpiAssociate(hPS,hDC)
  253.   GpiDestroyPS(hPS)
  254.   Device Contexts
  255.   Device Capabilities
  256.   Coordinates
  257.   Default Presentation Space Attributes
  258.   BUNDLES
  259.   GpiSetAttrs (hPS,lPrimType,ulAttrMask, ulDefMask,pBundle)
  260.   Area Bundle
  261.   usSet
  262.   usSymbol
  263.   ptlRefPoint
  264.   CHARBUNDLE
  265.   LINEBUNDLE
  266.   fxWidth
  267.   lGeomWidth
  268.   ulType
  269.   ulEnd
  270.   ulJoin
  271.   MARKERBUNDLE
  272.   usSet
  273.   usSymbol
  274.   sizefxCell
  275.   Color Models
  276.   Line and Arc Primitives
  277.   Drawing a Thermometer
  278.   Areas and Paths
  279.   Areas
  280.   Paths
  281.   Resources
  282.   Presentation Space Attribute Defaults
  283.   Functions That Can Be Cal
  284.   in a Path Bracket
  285.   The Drawing Sample Application
  286.   DRAW.H
  287.   DRAW.C
  288.   DRAW.DEF
  289.   DRAW.RC
  290.   THERMO.H
  291.   THERMO.C
  292.  
  293. Creating and Manipulating PM Fonts and Text
  294.   Introduction
  295.   Terminology
  296.   Single-Byte and Double-Byte Characters
  297.   Point Size
  298.   Font Families
  299.   Font Rendering
  300.   Default Font
  301.   Text Output Functions
  302.   Text Extents and Spacing
  303.   Common Dialog
  304.   Enumeration
  305.   The FONTMETRICS Structure
  306.   Creating Fonts
  307.   Scaling, Shearing, and Rotating
  308.   Character Modes
  309.   Rotation and Shear in PMFONT
  310.   Character Bundle Structure
  311.   Logical Inches
  312.   Code Pages
  313.   The PMFONT Application
  314.   PMFONT.C
  315.   PMFONT.H
  316.   PMFONT.RC
  317.   PMFONT.DLG
  318.   PMFONT.DEF
  319.   Font Class sFamilyClass
  320.  
  321. Profile Management
  322.   Introduction
  323.   The Profile Management API
  324.   Enumerating the Entries in the INI File
  325.   Adding Entries
  326.   Deleting Entries
  327.   The INITOR Sample Application
  328.   INITOR.C
  329.   INITOR.DEF
  330.   INITOR.H
  331.   INITOR.RC
  332.   Using INITOR
  333.   Looking at System Initialization Files
  334.   Using Your Own INI File
  335.   Spooler Functions_Additional Profile API
  336.  
  337. Memory Management
  338.   The Memory Architecture of OS/2 2.1
  339.   16-Bit and 32-Bit Memory
  340.   32-Bit Memory
  341.   The Memory Manager API
  342.   NonShared Memory
  343.   Suballocated Memory
  344.   Shared Memory
  345.   Converting from Unshared to Shared Memory
  346.   The MEMMAP Application
  347.   MEMMAP's Files
  348.   MEMMAP.C
  349.   MEMMAP.H
  350.   MEMMAP.RC
  351.   MEMMAP.DLG
  352.   Using MEMMAP
  353.   Understanding MEMMAP's Code
  354.   The MEMORY Application
  355.   MEMORY's Files
  356.   MEMORY.C
  357.   MEMORY.H
  358.   MEMORY.RC
  359.   ALLOCATE.DLG
  360.   MEMORY.DLG
  361.   MEMORY.DEF
  362.   Using the MEMORY Sample Application
  363.   Understanding MEMORY's Code
  364.  
  365. Dynamic Link Libraries
  366.   What Is a DLL and How Does It Work?
  367.   How to Build a DLL
  368.   DLLSAMP.C
  369.   DLLSAMP.H
  370.   DLLSAMP.DEF
  371.   APPSAMP.H
  372.   APPSAMP.RC
  373.   APPSAMP.C
  374.   The LIBPATH Statement
  375.   Runtime Dynamic Linking
  376.   DLLSAMP.H
  377.   APPSAMP2.C
  378.   Global versus Instance Data
  379.   Initialization and Termination
  380.   DLLINIT.ASM
  381.   DosExitList
  382.   OS2.INI
  383.   Resource-Only DLLs
  384.   Thermometer Application
  385.   CONTROLS.H
  386.   CONTROLS.DEF
  387.   CTLINIT.ASM
  388.   CONTROLS.C
  389.   MEMDLL.H
  390.   MEMDLL.DEF
  391.   MEMINIT.ASM
  392.   MEMINST.H
  393.   MEMINST.C
  394.   MEMDLL.C
  395.   THERMO.RC
  396.   THERMO.DLG
  397.   THERMO.H
  398.   THERMO.DEF
  399.   THERMO.C
  400.  
  401. Printing
  402.   Introduction
  403.   Some Printing Background: The DOS Days
  404.   Device Independence
  405.   Printing Under OS/2 1.x and Windows 3.x
  406.   OS/2 2.1 Print Objects
  407.   Spooler
  408.   Determining Installed Devices
  409.   SplEnumQueue
  410.   PRQINFO3/PRQINFO6
  411.   PRQINFO6 Only
  412.   Identifying the Default Print Object
  413.   Printer versus Job Properties
  414.   Printer Properties
  415.   Job Properites
  416.   Posting the Job Properties Dialog: DevPostDeviceModes
  417.   Creating an Information Device Context
  418.   Querying Device Forms
  419.   Determining Page and Printable Area Size
  420.   Calculating Printer Offset
  421.   Basic Printing
  422.   Printing in an Application
  423.   Tracking Your Print Job Using the Spooler API
  424.   SplControlDevice
  425.   SplCopyJob
  426.   SplDeleteJob
  427.   SplEnumJob
  428.   SplHoldJob
  429.   SplHoldQueue
  430.   SplPurgeQueue
  431.   SplQueryJob
  432.   SplReleaseJob
  433.   SplReleaseQueue
  434.   SplSetJob
  435.   Installing Private Device Drivers
  436.   Converting Profile Quer
  437.   to the Spooler Equivalents
  438.   PM_SPOOLER
  439.   PM_SPOOLER_PRINTER
  440.   PM_SPOOLER_PRINTER_DESCR
  441.   PM_SPOOLER_QUEUE_DESCR
  442.   The PRNT Application
  443.   PRNT.DLG
  444.   DIALOG.H
  445.   PRNT.C
  446.   PRNTINFO.C
  447.   PRNT.DEF
  448.   PRNT.H
  449.   PRNT.RC
  450.  
  451. Threads and Semaphores
  452.   Multitasking in OS/2
  453.   Three Types of Multitasking
  454.   Threads and Time Slices
  455.   Priority Classes and Priority Levels
  456.   OS/2 System Settings for Threads
  457.   Working with Threads
  458.   The Thread Function
  459.   Threading Considerations
  460.   Semaphores
  461.   Event Semaphores
  462.   Mutual Exclusion Semaphores
  463.   Multiple Wait Semaphores
  464.   Thread Demonstration Application
  465.   THREADS.H
  466.   THREADS.RC
  467.   TID.DLG
  468.   SORT.DLG
  469.   THREADS.C
  470.   Thread Observations
  471.  
  472. Calling 16-Bit Code
  473.   Introduction
  474.   Tiled Memory
  475.   Data Address Conversion
  476.   Code Address Conversion
  477.   Structure Alignment
  478.   Thunks
  479.   Thunk Application
  480.   BOOK16.DEF
  481.   BOOK16.C
  482.   BOOK16.H
  483.   THUNKS.DEF
  484.   THUNKS.RC
  485.   BOOKINFO.DLG
  486.   THUNKS.H
  487.   THUNKS.C
  488.   THUNKASM.ASM
  489.  
  490. Communications Basics
  491.   Introduction
  492.   Features of OS/2 Communications
  493.   Hardware Settings
  494.   Flow Control
  495.   Communicating w
  496.   the ASYNC Device Driver
  497.   The DosDevIOCtl Function
  498.   Phone Application
  499.   Main Thread
  500.   LED.C
  501.   LED.H
  502.   Files Required to Build the Phone Application
  503.   PHONE.C
  504.   PHONE.H
  505.   PHONE.RC
  506.   PHONE.DEF
  507.   SETTINGS.DLG
  508.   STATUS.DLG
  509.   BUTTONS.DLG
  510.   Understanding PHONE.C
  511.  
  512. Miscellaneous Topics
  513.   Miscellaneous Application
  514.   MISC.C
  515.   MISC.H
  516.   MISC.RC
  517.   MISC.DEF
  518.   Obtaining Thread Information
  519.   PIBTIB.C
  520.   PIBTIB.H
  521.   PIBTIB.DLG
  522.   Querying System Information
  523.   SYSINFO.C
  524.   SYSTINFO.H
  525.   SYSTINFO.DLG
  526.   Determining Drive Types
  527.   DRIVES.C
  528.   DRIVES.H
  529.   DRIVES.DLG
  530.   File Searching
  531.   FILESRCH.C
  532.   FILESRCH.H
  533.   FILESRCH.DLG
  534.  
  535.  
  536. ΓòÉΓòÉΓòÉ 7. Chapter1 - Programming for OS/2 ΓòÉΓòÉΓòÉ
  537.  
  538. Programming for OS/2 
  539.  
  540.  
  541. ΓòÉΓòÉΓòÉ 7.1. The Nature of This Book ΓòÉΓòÉΓòÉ
  542.  
  543. More than likely you bought this book because you have a programming problem to 
  544. solve. That's the reason we wrote it. We know from experience that the way to 
  545. start programming on a new platform and the way to solve many programming tasks 
  546. is not to stand back theorizing for a couple of weeks about how it should be 
  547. done. Instead, you get a good example to work from, then tear into it with your 
  548. own additions and changes. Now, more than likely, your first efforts will serve 
  549. only as a stepping stone for later development, but you need that initial 
  550. experience to build on. 
  551.  
  552. Trouble is, many times the software development kits do not have the room to 
  553. provide examples for you to work with, and the last thing the world needs is 
  554. another programming book showing you how to write another "Hello, World" 
  555. program, only for OS/2. This book covers areas of programming that are largely 
  556. ignored or poorly exemplified in software development kits and documentation. 
  557. It is aimed at intermediate level programmers. This does not mean you must be 
  558. an intermediate level programmer for OS/2, only that you should have the habit 
  559. of analysis and be familiar with coding concepts that come with programming 
  560. experience. 
  561.  
  562. Again, the emphasis is on developing code and techniques directly applicable to 
  563. your programming efforts. Each sample application in this book is designed as a 
  564. framework on which you can found your efforts. General areas of knowledge 
  565. covered are message-based architecture, working with OS/2 windows, working with 
  566. fonts, working with printers, creating DLLs, interprocess coordination, menus, 
  567. and drawing. Although you can work from the front to the back, it is not 
  568. necessary to follow only that path. We suggest that you first work through 
  569. Chapters 2, "OS/2 Application Window Fundamentals," 3, "Window Management," and 
  570. 4, "2.1 Common Dialogs," consecutively. After that, you should be able to dive 
  571. into the chapters that apply to your particular need. 
  572.  
  573. The sample applications in this book are longer than usual, but we felt this 
  574. was nec-essary to provide you with a useful framework. As a result, there is 
  575. not a line-by-line discussion of each sample; otherwise, the book would have 
  576. been huge! We suggest you first read the discussion about the concepts and 
  577. important API entries at the beginning of each chapter. After that, load the 
  578. working executable from the companion disk and spend some time working with it. 
  579. This will help familiarize you with the general issues involved. Then, you can 
  580. begin working through the code to see how the general concepts and behavior of 
  581. the application have been realized in the code. 
  582.  
  583. The applications in this book use the graphical user interface facilities 
  584. provided by the Presentation Manager API of OS/2. This continues to be an area 
  585. in which many programmers need some assistance. Don't forget that OS/2 still 
  586. allows character-based applications to run perfectly well in a window or 
  587. full-screen session. These types of applications just aren't the focus of this 
  588. book. 
  589.  
  590. This is a book designed to help you solve some of the more difficult issues 
  591. involved in creating a nontrivial program for OS/2. We have tried to address 
  592. the issues that programmers frequently face_things like how to open a file by 
  593. using the common file dialogs and how to use multithreading. 
  594.  
  595. That's what the book is, but we should also say a word about what the book is 
  596. not. This is not a programming manual about how to program in C. There simply 
  597. isn't room. This book also is not simply a recapitulation of the OS/2 Technical 
  598. Library. We have tried to distill the essential elements; we have tried to 
  599. bring together things that are sometimes located all over the documentation in 
  600. several different manuals; and we hope this helps; but really this book is a 
  601. collection of applications that shows how to get something done_something 
  602. usually fairly complicated. We tried to go far beyond the examples you will see 
  603. both in the documentation for OS/2 and for the compiler that you will be using. 
  604.  
  605. You are welcome to build applications on the code that we supply with the book. 
  606. We, however, do insist that you do not redistribute the software or the code 
  607. from this book without substantial modification and addition on your part. 
  608.  
  609. If you have not built an application for OS/2 yet with your compiler, we 
  610. certainly recommend working through one of the smaller examples supplied with 
  611. the compiler before tackling one of the applications in this book. This will 
  612. ensure that your environment is set up correctly and will save you a 
  613. considerable amount of frustration. 
  614.  
  615. Each application on the disk that accompanies the book has a number of files 
  616. associated with it. There is a compiled executable, along with a command file, 
  617. a make file, and the C, DEF, RC, ICO, DLG, and all the other files necessary to 
  618. build the application. To begin understanding the applications, we suggest you 
  619. first use the compiled versions that are shipped on the disk. 
  620.  
  621.  
  622. ΓòÉΓòÉΓòÉ 7.2. Compilers Used ΓòÉΓòÉΓòÉ
  623.  
  624. We wrote the sample applications for this book to be compatible with the four 
  625. major C compilers in the OS/2 environment. These are the Watcom, Borland, 
  626. Zortech, and IBM C Set/2 compilers. Each has its own characteristics, which may 
  627. make one more desirable than another. 
  628.  
  629.  
  630. ΓòÉΓòÉΓòÉ 7.3. Building the Applications ΓòÉΓòÉΓòÉ
  631.  
  632. The fact that a suite of applications could actually be made compatible across 
  633. all these compilers says volumes about the stability of the platform and the 
  634. tools developed for it. Each application has been provided with a make file 
  635. that can be used to build the application for each of the compiler products. 
  636. This process is described in greater detail in this chapter in the section 
  637. "Building a Sample Application." You can, of course, use the integrated 
  638. development environments provided with the compilers. Merely follow their 
  639. instructions about where to place particular modules, switches, and so forth. 
  640.  
  641.  
  642. ΓòÉΓòÉΓòÉ 7.4. Installing Your Compiler ΓòÉΓòÉΓòÉ
  643.  
  644. Each of the compilers installs in a different way. You must follow the 
  645. instructions for the compiler you plan to use. Further, we suggest that you 
  646. practice with some of the smaller examples provided with your compiler. This 
  647. will ensure that your development environment is set up correctly before you 
  648. take on some of the larger projects that accompany this book. We strongly 
  649. suggest you ensure that the PATH, INCLUDE, and LIBPATH environment variables 
  650. are set correctly. 
  651.  
  652.  
  653. ΓòÉΓòÉΓòÉ 7.5. Installing the Software ΓòÉΓòÉΓòÉ
  654.  
  655. We have provided an installation program with the software. This installation 
  656. program will copy the software from the companion distribution disk to your 
  657. hard drive. It will also ensure that the proper directory structure to contain 
  658. the software is set up on your hard drive. To use the installation program, 
  659. start an OS/2 session, either full screen or in a window. Change to the drive 
  660. containing the distribution disk. Then, type this command: 
  661.  
  662. INSTALL
  663.  
  664. First, the installation program will present you with the screen shown in 
  665. Figure 1.1. Figure 1.1. Opening screen shot file.
  666.  
  667. You may choose which chapters to install. You may also select a check box to 
  668. cause the installation program to place all the programs automatically in a 
  669. folder on the desktop. You may also change the root directory under which the 
  670. software will be installed. If you do not make a change to the default 
  671. directory name, the software will be installed in a directory structure by 
  672. chapter under a directory named \RWPOS2. 
  673.  
  674. Once the installation has begun, you will be presented with the dialog box 
  675. shown in Figure 1.2. Figure 1.2. Dialog box file.
  676.  
  677. This dialog box will change to show the progression of the installation. 
  678.  
  679.  
  680. ΓòÉΓòÉΓòÉ 7.6. Building a Sample Application ΓòÉΓòÉΓòÉ
  681.  
  682. After your compiler is installed on your system and the sample software is 
  683. installed, you are almost ready to build the samples. Notice that executable 
  684. versions of the samples are shipped for each chapter. You do not have to run 
  685. the make utility to use the programs. We included the make files, however, 
  686. because more than likely you will want to make additions and changes to the 
  687. samples. 
  688.  
  689. First, before building any of the applications, you need to indicate which of 
  690. the compilers you will be using to create the application. This is done by 
  691. setting an environment variable for the compiler. This environment variable is 
  692. used in the command file to determine which of the compilers to use to build 
  693. the application for the GO command file. To set up the environment variable use 
  694. this command: 
  695.  
  696. SET COMPILER=
  697.  
  698. You may choose from these: 
  699.  
  700.       BORLAND 
  701.       WATCOM 
  702.       IBMC 
  703.       ZORTECH 
  704.       CL386 
  705.  
  706.  For example, if you are using the Watcom compiler, enter this command: 
  707.  
  708.   SET COMPILER=WATCOM
  709.  
  710.  To make it even easier, we suggest making this line a part of your CONFIG.SYS 
  711.  file. 
  712.  
  713.  There is a file common to all the applications. This is the About box. Before 
  714.  you can build any of the applications, this needs to be created with the 
  715.  compiler that you will be using. After you have set the environment variable, 
  716.  therefore, change to the \COMMON directory and enter the GO command. You are 
  717.  now ready to begin building the samples. 
  718.  
  719.  Each sample is built by using the following: 
  720.    o  The modules that make up the application code. These include C code 
  721.       modules, resources, and include files. 
  722.  
  723.    o  A file that is a list of dependencies for each sample. This file will 
  724.       have the extension .DEP. 
  725.  
  726.    o  A make file for each of the four compilers. 
  727.  
  728.    o  An OS/2 command file that starts the make process. 
  729.  
  730.  The SKELETON application, for example, will have these files in its installed 
  731.  directory: 
  732.  
  733.       SKELETON.DEP 
  734.       SKELETON.H 
  735.       SKELETON.DEF 
  736.       GO.CMD 
  737.       SKELETON.C 
  738.       SKELETON.RC 
  739.       SKELETON.OBJ 
  740.       SKELETON.RES 
  741.       SKELETON.MAP 
  742.       SKELETON.ICO 
  743.       SKELETON.EXE 
  744.  
  745.  To build this sample, change to the directory that contains these files and 
  746.  enter the following command: 
  747.  
  748.   GO
  749.  
  750.  This will cause the command file to start the build for the SKELETON 
  751.  application. The actual lines in the command file are as follows: 
  752.  
  753.   @ECHO --------------------------------------------------
  754.   @ECHO | Skeleton Application                           |
  755.   @ECHO | Chapter 2                                      |
  756.   @ECHO | Real-World Programming for OS/2 2.1            |
  757.   @ECHO | Copyright (c) 1993 Blain, Delimon, and English |
  758.   @ECHO --------------------------------------------------
  759.   @if "%COMPILER%"==""    goto nocompiler
  760.   @if %COMPILER%==CL386   set MAKECMD=nmake
  761.   @if %COMPILER%==cl386   set MAKECMD=nmake
  762.   @if %COMPILER%==BORLAND set MAKECMD=make
  763.   @if %COMPILER%==borland set MAKECMD=make
  764.   @if %COMPILER%==IBMC    set MAKECMD=nmake
  765.   @if %COMPILER%==ibmc    set MAKECMD=nmake
  766.   @if %COMPILER%==WATCOM  set MAKECMD=wmake
  767.   @if %COMPILER%==watcom  set MAKECMD=wmake
  768.   @if %COMPILER%==ZORTECH set MAKECMD=make
  769.   @if %COMPILER%==zortech set MAKECMD=make
  770.   %MAKECMD% -f ..\%COMPILER%.mak MAKEFILE=skeleton.dep
  771.   @goto done
  772.   :nocompiler
  773.   @ECHO
  774.   @ECHO ╨┐╨┐╨┐ COMPILER environment variable must be set to compiler name
  775.   @ECHO
  776.   :done
  777.  
  778.  The make file follows the usual structure. There is a make file for each of 
  779.  the compilers supported. Each of these is in the root directory where you 
  780.  installed the distributed files. Let's say you are using the Borland compiler. 
  781.  The make file for this compiler has these lines: 
  782.  
  783.   #====================================================================
  784.   # Borland C++ for OS/2
  785.   # Compiler Definition File
  786.   # Real-World Programming for OS/2 2.1
  787.   # Copyright (c) 1993 Blain, Delimon, and English
  788.   #====================================================================
  789.  
  790.   #=====================================================================
  791.   # Inference rules
  792.   #=====================================================================
  793.  
  794.   BORLANDEXEOPTS  = -m -aa -Toe -L$(LIB)
  795.   BORLANDDLLOPTS  = -m -Tod -L$(LIB)
  796.   ABOUT           = ..\common\about.obj
  797.  
  798.   .c.obj :
  799.       @echo ╨┐╨┐╨┐
  800.       @echo ╨╛╨╛╨╛ Compiling $*.c using Borland options ╨┐╨┐╨┐
  801.       @echo ╨┐╨┐╨┐
  802.       bcc -c -K -w -D__BORLAND__ $(BORLANDOPTS) $*.c > $*.err
  803.       type $*.err
  804.  
  805.   .asm.obj :
  806.       @echo ╨┐╨┐╨┐
  807.       @echo ╨╛╨╛╨╛ Assembling $*.asm using MASM386 options ╨┐╨┐╨┐
  808.       @echo ╨┐╨┐╨┐
  809.       tasm -ml -mx -d__TASM__ -oi -w2 $*.asm,$*.obj;
  810.  
  811.   .rc.res :
  812.       @echo ╨┐╨┐╨┐
  813.       @echo ╨╛╨╛╨╛ Running resource compiler on $*.rc ╨┐╨┐╨┐
  814.       @echo ╨┐╨┐╨┐
  815.       rc -r $*.rc
  816.  
  817.   .def.lib :
  818.       @echo ╨┐╨┐╨┐
  819.       @echo ╨╛╨╛╨╛ Creating import library from $*.def ╨┐╨┐╨┐
  820.       @echo ╨┐╨┐╨┐
  821.       implib $*.lib $*.def
  822.  
  823.   .obj.exe :
  824.       @echo ╨┐╨┐╨┐
  825.       @echo ╨╛╨╛╨╛ Building $*.exe using Borland options ╨┐╨┐╨┐
  826.       @echo ╨┐╨┐╨┐
  827.       tlink $(BORLANDEXEOPTS) c02 $(OBJS) $(ABOUT),$*.exe,$*.map,$(LIBS)
  828.    c2 os2386,$*.def
  829.  
  830.       rc $*.res $*.exe
  831.  
  832.   .obj.dll :
  833.       @echo ╨┐╨┐╨┐
  834.       @echo ╨╛╨╛╨╛ Building $*.dll using Borland options ╨┐╨┐╨┐
  835.       @echo ╨┐╨┐╨┐
  836.       tlink $(BORLANDDLLOPTS) $(OBJS)
  837.   $(BORLANDINITOBJ),$*.dll,$*.map,$(LIBS) os2386,$*.def
  838.  
  839.       rc $*.res $*.dll
  840.  
  841.   !include $(MAKEFILE)
  842.  
  843.   # MEMINST.OBJ must be built this way to force the _INSTANCEDATA segment
  844.   # to be placed in a separate segment from the _DATA segment
  845.   # The -oi option of tasm creates the correct kind of object record
  846.   # for the linker
  847.   meminst.obj : meminst.c
  848.       bcc -c -K -w -S -D__BORLAND__ -zR_INSTANCEDATA -zTFAR_DATA $(BORLANDOPTS) $*.c >
  849.   $*.err
  850.       tasm -ml -mx -d__TASM__ -oi -w2 $*.asm,$*.obj;
  851.       del $*.asm
  852.  
  853.  This file, in turn, depends on a file that lists the dependencies for the 
  854.  particular sam-ple being made. There is a dependency file for each sample. In 
  855.  Chapter 2, "OS/2 Application Window Fundamentals," in the SKELETON 
  856.  application, the dependency file is named SKELETON.DEP. It contains these 
  857.  lines: 
  858.  
  859.   #====================================================================
  860.   # Skeleton Dependencies Make File
  861.   # Chapter 2
  862.   # Real-World Programming for OS/2 2.1
  863.   # Copyright (c) 1993 Blain, Delimon, and English
  864.   #====================================================================
  865.  
  866.   #====================================================================
  867.   # Dependencies and Build Items
  868.   #====================================================================
  869.  
  870.   OBJS = skeleton.obj
  871.  
  872.   all: skeleton.exe
  873.  
  874.   skeleton.obj: skeleton.c skeleton.h
  875.  
  876.   skeleton.res: skeleton.rc skeleton.ico
  877.  
  878.   skeleton.exe: $(OBJS) skeleton.res skeleton.def
  879.  
  880.  
  881. ΓòÉΓòÉΓòÉ 7.7. Heading Out on Your Own ΓòÉΓòÉΓòÉ
  882.  
  883. After you have built a few of the applications just as they are installed, you 
  884. can begin to modify them to suit your own purposes. We suggest making small 
  885. changes at first. This will keep you from getting too far off the track. Write 
  886. if you get work. 
  887.  
  888.  
  889. ΓòÉΓòÉΓòÉ 8. Chapter 9 - Memory Management ΓòÉΓòÉΓòÉ
  890.  
  891. Memory Management 
  892.  
  893.  
  894. ΓòÉΓòÉΓòÉ 8.1. The Memory Architecture of OS/2 2.1 ΓòÉΓòÉΓòÉ
  895.  
  896. Many developers starting out programming for OS/2 2.1 have programmed for DOS. 
  897. The clunky, segmented addressing architecture demanded by the chips on which 
  898. DOS runs is notorious for its inefficiency and quirkiness. A 640K limitation 
  899. and competing and confusing schemes such as extended and expanded memory are 
  900. the result of this segmented architecture. OS/2 2.1, running on the 80386 chip, 
  901. is capable of leaving all this behind. 
  902.  
  903. OS/2 2.1 has a linear address space. That is, the address of each byte that 
  904. follows another is incremented by one. Some call this a "flat address space." 
  905. Memory allocation in OS/2 2.1 takes advantage of the 32-bit protected mode of 
  906. the Intel 80386 and 80486 processors. Because OS/2 2.1, as of this writing, 
  907. runs on a chip that uses 32-bit pointers, 4GB of memory may be addressed. Not 
  908. all this memory, however, is immediately available to an application, nor is 
  909. the memory architecture as simple as the term "flat address space" implies. 
  910.  
  911. Remember, OS/2 2.1 is a true multitasking operating system. This means that a 
  912. number of different processes, which may have any number of threads, occupy the 
  913. system memory simultaneously along with the operating system. If any process 
  914. could access any place in memory at will, confusion and corruption would often 
  915. be the result. Further, if the physical address space taken by one application 
  916. was large, it might limit another from running. More often than not this would 
  917. be the case because although memory is cheap, it's not yet free. Most systems 
  918. do not have 4GB laying about for use. Most office and home systems have 8 
  919. physical megabytes available to the CPU, so some mechanism is necessary to 
  920. allow applications to use a much larger virtual address space. 
  921.  
  922. In OS/2 2.1, each process can access 512M of linear address space. This area of 
  923. memory is referred to as the process address space. The 512M limit is incurred 
  924. by the need to support both 16-bit and 32-bit applications. This 512M of 
  925. potential memory is, in fact, further limited to the amount of physical memory 
  926. added to the amount of available hard disk memory. 
  927.  
  928. To make this large address space available to multiple applications in the much 
  929. smaller space of physical memory available on most machines, OS/2 2.1 uses a 
  930. paged memory system. This 512M of memory for each process is completely 
  931. unrelated to the 512M available to other processes that may be running on the 
  932. machine. The total amount of committed memory for all processes, however, 
  933. cannot exceed the amount of physical memory plus the available hard disk space. 
  934. The entire 4GB of address space is partitioned into private, shared, and system 
  935. memory. Figure 9.1 illustrates how the address space is allocated to these 
  936. three regions. 
  937.  
  938. Of the 64M reserved for private memory allocation, the first 64K is reserved 
  939. for operating system overhead. The address range from 448M to 512M is reserved 
  940. for shared memory. Addresses above 512M are in the OS/2 system space; these are 
  941. where the operating system kernel is loaded. The remaining 384M between 
  942. addresses 64M and 448M is allocated as needed for either private or shared 
  943. memory. 
  944. Figure 9.1. OS/2 address space.
  945.  
  946. Private memory for each process grows upward (upward in value ) from the bottom 
  947. 64K. This is true for every process running on the system. Shared memory starts 
  948. at the top of the 512M address space and grows downward. Shared memory is 
  949. memory shared across processes. Keep in mind that a process is different from a 
  950. thread. A process may have many threads, but processes are individuals to 
  951. themselves. Shared memory is used to share memory across processes as well as 
  952. for Dynamic Link Library (DLL) code and data. Private memory is composed of the 
  953. application's code, data, heap, stack, and allocated non-shared memory objects. 
  954.  
  955. Shared memory is allocated for all processes. For example, if several processes 
  956. are running and one allocates 2M of shared memory, this shared memory is 
  957. allocated from the shared memory address space for all the processes. This is 
  958. true even if some of the processes do not have access to the allocated memory. 
  959.  
  960.  
  961. ΓòÉΓòÉΓòÉ 8.2. 16-Bit and 32-Bit Memory ΓòÉΓòÉΓòÉ
  962.  
  963. To fully understand the allocation scheme, you will find it helpful to first 
  964. understand the 16-bit segmented allocation scheme. Prior versions of OS/2 
  965. relied on the segmented memory model, and all memory was addressed by a 16-bit 
  966. selector and 16-bit offset. Memory was allocated by blocks of up to 64K, and a 
  967. 16-bit segment selector was returned. Memory was then accessed by combining the 
  968. 16-bit selector with a 16-bit offset, with all offsets starting at 0. Memory 
  969. was allocated and accessible immediately after allocation. This architecture 
  970. limits each segment to 64K, so allocating blocks larger than 64K required the 
  971. segment register to be changed to match the desired portion of allocated 
  972. memory. 
  973.  
  974. OS/2 2.1 provides support for true 32-bit memory allocation and access, but it 
  975. also still supports 16-bit segmented memory allocation for 16-bit applications. 
  976. As it is possible for 32-bit applications and 16-bit applications to share data 
  977. address spaces (shared memory) and also to pass memory addresses between each 
  978. other, it is necessary to allow for differences in the addressing scheme. This 
  979. support is provided by placing several restrictions on the 32-bit memory 
  980. allocation process. 
  981.  
  982. In the 32-bit world, all addresses are near addresses into what is called the 
  983. FLAT address space. The FLAT address space, sometimes called linear address 
  984. space, is the entire 4GB of addressable memory. Because the 16-bit world 
  985. requires all segment offsets to start at 0, you can see that only those 
  986. addresses in the 32-bit space which have 0 as the low word of their address 
  987. should map to segment boundaries. This is done in OS/2 by what is called memory 
  988. tiling, or TILED memory, which restricts the base linear addresses to multiples 
  989. of 64K. Figure 9.2 shows how the two addressing schemes can share the same 
  990. memory space through tiling. 
  991. Figure 9.2. Tiled memory architecture.
  992.  
  993. Notice that all selectors have the low 3-bits set and that the memory 
  994. referenced starts on a 64K multiple. Because the system reserves the first 64K, 
  995. it is never possible to have a selector value of 0. The process of converting 
  996. linear addresses to a 16-bit selector and offset and vice versa will be covered 
  997. in Chapter 13, "Calling 16-Bit Code," which discusses the concept of thunking. 
  998.  
  999. OS/2 2.1 enables you to force memory allocation to follow the TILED memory 
  1000. restriction when memory is allocated. Using this option does reduce the amount 
  1001. of available memory address space because the entire range of 64K is reserved 
  1002. on such an allocation request. This is discussed later when we get into the 
  1003. memory management API. 
  1004.  
  1005.  
  1006. ΓòÉΓòÉΓòÉ 8.3. 32-Bit Memory ΓòÉΓòÉΓòÉ
  1007.  
  1008. The fundamental unit of memory for OS/2 2.1 memory management is the page. A 
  1009. page of memory is always 4,096 bytes, 4K. If an application needs to allocate 
  1010. only 64 bytes of memory, this still causes a whole page, 4,096, to be allocated 
  1011. to contain that 64 bytes. If more than a page of memory is asked for, a page 
  1012. range is allocated. A page range is several contiguous pages. 
  1013.  
  1014. The total virtual memory space available to a process is divided into pages. 
  1015. Each of these pages may be in one of only three states at any particular 
  1016. moment. These three states are as follows: 
  1017.  Free      The page has not been allocated. 
  1018.  Private   The process has allocated the page for use. 
  1019.  Shared    The page has been allocated as memory to be shared between 
  1020.            processes. 
  1021.  
  1022.  Memory pages have an additional pair of characteristics. A memory page may be 
  1023.  committed or uncommitted. Committed pages within memory objects have been 
  1024.  allotted physical storage for the logical address range. Uncommitted pages are 
  1025.  not yet backed by physical storage. 
  1026.  
  1027.  Memory allocation merely reserves a range of memory addresses in the process 
  1028.  address space. It does not use any physical memory until the memory is 
  1029.  committed and referenced. Memory commitment is the process of physically 
  1030.  allocating memory from the system and assigning it to the address space that 
  1031.  has been allocated. Requests to commit memory are done on a page basis. A page 
  1032.  in memory cannot be accessed until the page has been committed. Attempts to 
  1033.  access uncommitted memory will result in a protection violation. 
  1034.  
  1035.  Memory objects are allocated in units of 4K pages. All memory requests are 
  1036.  resolved to a page boundary. All pages allocated are fully addressable. A 
  1037.  request to allocate 1 byte of memory will result in a 4K page being allocated. 
  1038.  The entire 4K is available for use by the application. A request to allocate 
  1039.  4,097 bytes of memory will result in two 4K pages being allocated. Again, the 
  1040.  entire 8K is available for allocation. For small memory requests, this can 
  1041.  result in a lot of unused memory being allocated, thus reducing the amount of 
  1042.  memory available for use. We will discuss ways to handle such requests more 
  1043.  efficiently later in this chapter. 
  1044.  
  1045.  When an application no longer requires the use of a physical memory object, it 
  1046.  can either be freed or decommitted. Decommitment allows the application to 
  1047.  commit the memory again without the need for a memory allocation request. 
  1048.  
  1049.  Notice that applications do not actually allocate "pages" for their use. 
  1050.  Applications or processes allocate memory, which is then set aside by the 
  1051.  operating system in terms of pages. Applications allocate and use memory as 
  1052.  memory objects. Memory objects are one or more pages. Processes or 
  1053.  applications may allocate more than one memory object. These memory objects 
  1054.  have the following characteristics: 
  1055.  
  1056.    o  Each is allocated in increments of 4K. 
  1057.  
  1058.    o  Each has memory objects that are not relocatable. 
  1059.  
  1060.  The operating system reserves a linear address range when an application asks 
  1061.  it to allocate memory. This address range, however, is not backed by physical 
  1062.  memory until the memory is committed. Any attempt to use uncommitted memory 
  1063.  will cause an access violation. 
  1064.  
  1065.  Memory may be committed when it is allocated, or it may be allocated as 
  1066.  uncommitted and then committed at a later time. If the memory is committed 
  1067.  when allocated, all of it is committed, and it is available for immediate use. 
  1068.  If the memory is allocated as uncommitted, however, individual portions of the 
  1069.  memory may be allocated at different times later. Allocated memory objects 
  1070.  that are not committed are called by the peculiar term "sparse." 
  1071.  
  1072.  You can see that the best practice for memory management is to allocate a 
  1073.  sparse memory object initially for as much space as the process might need. 
  1074.  Later, parts of the memory object may be committed as needed. When a memory 
  1075.  object is allocated as uncommitted, no physical memory is involved, so it is 
  1076.  not wasteful to allocate several extra megabytes. Better yet, this practice 
  1077.  actually optimizes the use of memory within the system. Pages are not given 
  1078.  memory storage to back them up until they are both committed and referenced. 
  1079.  No memory is wasted for unreferenced, committed pages. 
  1080.  
  1081.  Access to committed pages is further refined to have access rights: read, 
  1082.  write, or execute. A fourth right, guard page, is also available but is not 
  1083.  discussed here. 
  1084.  
  1085.  At any time, an application may change the access rights of a committed page 
  1086.  of memory. It may also commit and decommit allocated pages on demand. Figure 
  1087.  9.3 shows an initial allocation request for 16K of memory. 
  1088.  
  1089.  Notice that an entire range of 64K of address space has been allocated. This 
  1090.  is due to the current implementation of memory allocation in OS/2 2.1, which 
  1091.  makes all memory allocation requests follow the TILED memory scheme. 
  1092.  
  1093.  Before accessing any of this memory, the application would have to make a 
  1094.  request to commit the necessary pages. Figure 9.4 shows the result of a 
  1095.  request by an application to commit the first 8K of memory, starting at 
  1096.  address 14F00000. 
  1097.  Figure 9.3. 16K uncommitted memory allocation.
  1098.  
  1099.  Figure 9.4. Memory committment.
  1100.  
  1101.  At this point, we are free to access memory in the range 14F00000 to 14F01FFF. 
  1102.  Attempts to address 14F02000 would generate a protection violation. 
  1103.  
  1104.  Memory objects cannot be resized after allocation. An application, thus, must 
  1105.  allocate the maximum amount of memory for a memory object and commit the 
  1106.  memory as needed. 
  1107.  
  1108.  Committing and decommitting pages in a range of allocated memory as they are 
  1109.  needed is a more efficient way of managing memory than requesting memory 
  1110.  allocation and commitment every time. This, however, requires the application 
  1111.  to keep track of how many pages have been committed so that memory requests to 
  1112.  commit and decommit do not fail. 
  1113.  
  1114.  An easier way of handling such a situation is to allocate a memory object as a 
  1115.  heap and use the memory suballocation functions to allocate and commit the 
  1116.  memory as needed. The heap management functions in the operating system keep 
  1117.  track of the committed and uncommitted pages and manage these pages as memory 
  1118.  requests are made. Care must be taken when using a heap, as accessing memory 
  1119.  above the requested amount of suballocated memory may write over memory 
  1120.  allocated to another suballocated block of memory or destroy information 
  1121.  maintained by the heap itself. Memory requests suballocated from a heap are 
  1122.  rounded up to a multiple of 8 bytes. 
  1123.  
  1124.  
  1125. ΓòÉΓòÉΓòÉ 8.4. The Memory Manager API ΓòÉΓòÉΓòÉ
  1126.  
  1127. The memory management functions in OS/2 are divided into three categories: 
  1128. nonshared, suballocated, and shared. Some functions that are discussed as a 
  1129. part of the nonshared memory API are also available for use with shared memory. 
  1130.  
  1131.  
  1132. ΓòÉΓòÉΓòÉ 8.5. NonShared Memory ΓòÉΓòÉΓòÉ
  1133.  
  1134. NonShared memory is allocated with the DosAllocMem API: 
  1135.  
  1136. APIRET DosAllocMem (PPVOID ppBaseAddress, ULONG ulObjectSize,
  1137.                     ULONG ulAllocationFlags)
  1138.  
  1139.  PPVOID  ppBaseAddress              Address of pointer to receive memory 
  1140.                                     address. 
  1141.  ULONG  ulObjectSize                Maximum size of memory object to be 
  1142.                                     allocated. 
  1143.  ULONG  ulAllocationFlags           Memory allocation flags: 
  1144.       PAG_READ            Allows read access. 
  1145.       PAG_EXECUTE         Allows execute access (executable code). 
  1146.       PAG_WRITE           Allows write access (includes read and execute 
  1147.                           access). 
  1148.       PAG_COMMIT          Commits all requested pages. 
  1149.       OBJ_TILE            Allocates memory on a 64K boundary. 
  1150.  
  1151.  The following example allocates an 8K memory object: 
  1152.  
  1153.   PBYTE pMem;
  1154.   APIRET RetCode;
  1155.   RetCode = DosAllocMem ((PPVOID) &pMem, 8192L, PAG_READ | PAG_WRITE);
  1156.  
  1157.  The memory object returned in pMem must be committed before it can be 
  1158.  accessed. Memory can be committed at the same time it is allocated by using 
  1159.  the PAG_COMMIT flag: 
  1160.  
  1161.   RetCode = DosAllocMem ((PPVOID) &pMem, 8192L,
  1162.                 PAG_READ | PAG_WRITE | PAG_COMMIT);
  1163.  
  1164.  The memory object returned in pMem can now be immediately accessed. Each page 
  1165.  of a memory object is initialized to zeroes the first time the page is read or 
  1166.  written. The flag fALLOC can be used to request memory that is readable, 
  1167.  writable, and committed: 
  1168.  
  1169.   #define fPERM  (PAG_EXECUTE + PAG_READ + PAG_WRITE)
  1170.   #define fALLOC (OBJ_TILE + PAG_COMMIT + fPERM)
  1171.  
  1172.  Note:  The current implementation of OS/2 2.1 always allocates memory as 
  1173.         though the OBJ_TILE flag is set. If the PAG_COMMIT flag is set, 
  1174.         however, only those pages required to satisfy the allocation request 
  1175.         are committed. In the previous example, only the first four pages 
  1176.         (8,192 bytes) would be committed, although 16 pages (64K) are 
  1177.         allocated. This may change in a future release of OS/2 2.1. 
  1178.  
  1179.  After the memory is allocated, it can be committed and decommitted as needed 
  1180.  with the DosSetMem API: 
  1181.  
  1182.   APIRET DosSetMem (PVOID pBaseAddress, ULONG ulRegionSize,
  1183.                     ULONG ulAttributeFlags)
  1184.  
  1185.  PVOID  pBaseAddress                Base address of memory object. 
  1186.  ULONG  ulRegionSize                Size of memory to set. 
  1187.  ULONG  ulAttributeFlags            Memory attribute flags: 
  1188.       PAG_COMMIT          Commits pages specified in ulRegionSize. 
  1189.       PAG_DECOMMIT        Decommits pages specified in ulRegionSize starting at 
  1190.                           pBaseAddress. 
  1191.       PAG_READ            Read access. 
  1192.       PAG_EXECUTE         Execute access. 
  1193.       PAG_WRITE           Write access. 
  1194.       PAG_DEFAULT         Use default access. 
  1195.  
  1196.  If you are committing memory, you must also specify PAG_DEFAULT or at least 
  1197.  one of these_ PAG_READ, PAG_WRITE, or PAG_EXECUTE. PAG_DEFAULT sets the access 
  1198.  rights of the page to the same rights as when the memory object was allocated. 
  1199.  
  1200.  The following example allocates an 8K memory object and commits the first page 
  1201.  of the object: 
  1202.  
  1203.   PBYTE pMem;
  1204.   APIRET RetCode;
  1205.   if ( !(RetCode = DosAllocMem ((PPVOID) &pMem, 8192L,
  1206.                        PAG_READ | PAG_WRITE)) )
  1207.   {
  1208.       RetCode = DosSetMem ((PVOID) pMem, 4096L,
  1209.                     PAG_COMMIT | PAG_READ | PAG_WRITE);
  1210.   }
  1211.  
  1212.  Attempts to set the commitment state of a page of memory to a state it is 
  1213.  already in will fail. The second call to DosSetMem in the following sequence 
  1214.  will fail as the second page is already committed: 
  1215.  
  1216.   RetCode = DosSetMem ((PVOID) pMem, 8192L,
  1217.                 PAG_COMMIT | PAG_READ | PAG_WRITE);
  1218.   RetCode = DosSetMem ((PVOID) pMem+4096, 4096L,
  1219.                 PAG_COMMIT | PAG_READ | PAG_WRITE);
  1220.  DosSetMem can also be used to change the access rights of committed pages of 
  1221.  the memory object. The following example allocates and commits an 8K memory 
  1222.  object and then changes the access right of the first page from readable and 
  1223.  writable to only readable: 
  1224.  
  1225.   PBYTE pMem;
  1226.   APIRET RetCode;
  1227.   if ( !(RetCode = DosAllocMem ((PPVOID) &pMem, 8192L, fALLOC)) )
  1228.   {
  1229.       RetCode = DosSetMem ((PVOID) pMem, 4096L, PAG_READ);
  1230.   }
  1231.  
  1232.  The first page is now readable, but the second page is still readable and 
  1233.  writable. It is not possible to change the access rights for uncommitted 
  1234.  memory. 
  1235.  
  1236.  It is important for you to remember that the access right of PAG_EXECUTE can 
  1237.  be set for a page of memory only if the memory was originally allocated with 
  1238.  PAG_EXECUTE. 
  1239.  
  1240.  When memory is no longer needed, you can release it with the DosFreeMem API: 
  1241.  
  1242.   APIRET DosFreeMem (PVOID pBaseAddress)
  1243.  
  1244.  PVOID pBaseAddress                 Base address of memory object 
  1245.  
  1246.  The following example allocates and commits an 8K memory object and then 
  1247.  releases it when done: 
  1248.  
  1249.   PBYTE pMem;
  1250.   APIRET RetCode;
  1251.   if ( !(RetCode = DosAllocMem ((PPVOID) &pMem, 8192L, fALLOC)) )
  1252.   {
  1253.       .
  1254.       .
  1255.       .
  1256.       RetCode = DosFreeMem ((PVOID) pMem);
  1257.   }
  1258.  
  1259.  Any range of memory can be queried to determine its current state with the 
  1260.  DosQueryMem API: 
  1261.  
  1262.   APIRET DosQueryMem (PVOID pBaseAddress, PULONG pulRegionSize,
  1263.                       PULONG pulAllocationFlags)
  1264.  
  1265.  PPVOID  ppBaseAddress              Base address of memory object. 
  1266.  PULONG  pulRegionSize              Address of variable to receive region size. 
  1267.  PULONG  pulAllocationFlags         Address of variable to receive allocation 
  1268.                                     flags. 
  1269.  
  1270.  DosQueryMem will scan the pages of memory starting at pBaseAddress and will 
  1271.  return the allocation flags of the memory in the range specified. On input, 
  1272.  pulRegionSize points to a variable containing the size, in bytes, of the 
  1273.  amount of memory to scan. The range of memory pages scanned will stop when a 
  1274.  page with attribute flags different from the first page is encountered, the 
  1275.  number of pages requested is scanned, or the end of the allocated object is 
  1276.  reached. On return, the variable pointed to by pulRegionSize will contain the 
  1277.  actual number of bytes scanned. 
  1278.  
  1279.  The allocation flags include two new flags: 
  1280.  
  1281.  PAG_FREE            The memory pages are not allocated. 
  1282.  PAG_BASE            The first page specified is the first page of the 
  1283.                      allocated memory object. 
  1284.  PAG_SHARED          The memory pages are in a shared memory object. (This flag 
  1285.                      is returned only if the pages are committed.) 
  1286.  
  1287.  The following example queries the second page to see whether it is committed 
  1288.  and writable: 
  1289.  
  1290.   ULONG ulMemSize = 4096L;
  1291.   ULONG ulFlags;
  1292.   if ( !(RetCode = DosQueryMem ((PVOID) (pMem+4096),
  1293.                        &ulMemSize, &ulFlags)) )
  1294.   {
  1295.       if ( (ulFlags & (PAG_COMMIT | PAG_WRITE)) ==
  1296.                       (PAG_COMMIT | PAG_WRITE)) )
  1297.       {
  1298.           .
  1299.           .
  1300.           .
  1301.       }
  1302.   }
  1303.  
  1304.  If every page of an allocated memory object has the same attributes, you can 
  1305.  determine the amount of committed memory for the object with the following 
  1306.  call: 
  1307.  
  1308.   ULONG ulMemSize = 0xFFFFFFFF;
  1309.   ULONG ulFlags;
  1310.   if ( (RetCode = DosQueryMem (pMem, &ulMemSize, &ulFlags)) ||
  1311.        !(ulFlags & PAG_COMMIT) )
  1312.       ulMemSize = 0L;
  1313.  
  1314.  This example requests DosQueryMem to scan all memory pages starting at pMem. 
  1315.  If DosQueryMem returns successful, we still need to check the flags because 
  1316.  all memory may be uncommitted. The applications presented later demonstrate 
  1317.  how to determine the amount of allocated and committed memory when all pages 
  1318.  do not have the same attributes. 
  1319.  
  1320.  
  1321. ΓòÉΓòÉΓòÉ 8.6. Suballocated Memory ΓòÉΓòÉΓòÉ
  1322.  
  1323. There are several drawbacks to allocating, committing, and managing the pages 
  1324. of memory that your application may need. 
  1325.  
  1326.    o  Your application must track which pages have been committed and must 
  1327.       check this before each memory access. 
  1328.  
  1329.    o  Small memory requests result in large amounts of address space being 
  1330.       reserved. 
  1331.  
  1332.    o  Small memory requests for committed pages result in at least 4K of 
  1333.       physical memory being used. 
  1334.  
  1335.    o  Memory allocation requests for new blocks of memory will be slower than 
  1336.       suballocating from already committed memory. 
  1337.  
  1338.  Consider the following memory requests: 
  1339.  
  1340.   DosAllocMem ((PPVOID) &pMem, 20L, fALLOC);
  1341.   DosAllocMem ((PPVOID) &pMem, 32L, fALLOC);
  1342.  
  1343.  This results in a total of 128K of address space being reserved (64K for each 
  1344.  request) and 8K of physical memory being used (4K for each request). It would 
  1345.  be more efficient if we could satisfy both requests in a single page of 
  1346.  committed memory. This is made possible by using the heap management functions 
  1347.  of OS/2. In using a heap, you allocate a block of memory and indicate to OS/2 
  1348.  that the block is to be managed as a heap. OS/2 will then satisfy memory 
  1349.  requests from this heap by suballocating portions of this memory and returning 
  1350.  the address to the application. OS/2 takes care of making sure the pages of 
  1351.  memory are committed as necessary and of freeing them as they become 
  1352.  available. Your application should never call DosSetMem to change any 
  1353.  attribute of the memory used for suballocation, as this will cause 
  1354.  unpredictable results. As an alternative, it is also possible for your 
  1355.  application to commit the pages of the heap and avoid having the heap 
  1356.  functions do any memory commitment. 
  1357.  
  1358.  The first step in using memory suballocation (heaps) is to allocate a block of 
  1359.  memory for this purpose. This is done by using the DosAllocMem function. This 
  1360.  allocated memory is initialized for memory suballocation with the DosSubSetMem 
  1361.  API, as follows: 
  1362.  
  1363.   APIRET DosSubSetMem (PVOID pOffset, ULONG ulFlags, ULONG ulSize)
  1364.  
  1365.  PVOID  pOffset                     Base address of memory object. 
  1366.  ULONG  ulFlags                     Memory suballocation flags: 
  1367.       DOSSUB_INIT              Initializes the memory for suballocation. 
  1368.       DOSSUB_SPARSE_OBJ        Tells OS/2 to manage the commitment of the 
  1369.                                pages. 
  1370.       DOSSUB_GROW              Increases the size of the memory used for 
  1371.                                suballocation. 
  1372.       DOSSUB_SERIALIZE         More than one process will be suballocating 
  1373.                                memory from this block of memory. 
  1374.  
  1375.  The suballocation management for the heap uses 64 bytes of this memory to 
  1376.  maintain control information. In addition, all suballocation requests are 
  1377.  satisfied in multiples of 8 bytes. The minimum size that can be set, thus, is 
  1378.  72 bytes. 
  1379.  
  1380.  The DOSSUB_INIT flag is specified on the first call to DosSubSetMem so that 
  1381.  the control information for the heap can be initialized. 
  1382.  
  1383.  Specify the DOSSUB_SPARSE_OBJ flag if you want OS/2 to manage the commitment 
  1384.  of the pages. All pages in the range specified must be initially uncommitted. 
  1385.  If the DOSSUB_SPARSE_OBJ flag is not set, all pages in the range specified 
  1386.  must be committed before the call to DosSubSetMem. Because the heap must be 
  1387.  updated as memory is suballocated, all pages must have minimum access rights 
  1388.  of PAG_READ and PAG_WRITE. 
  1389.  
  1390.  The following example allocates 64K for use as a heap and initializes it such 
  1391.  that OS/2 will manage the commitment of pages: 
  1392.  
  1393.   if ( !(RetCode = DosAllocMem ((PPVOID) &pMem, 0x10000,
  1394.                      PAG_READ | PAG_WRITE)) )
  1395.   {
  1396.       RetCode = DosSubSetMem (pMem,
  1397.                    DOSSUB_INIT | DOSSUB_SPARSE_OBJ, 0x10000);
  1398.   }
  1399.  
  1400.  The DOSSUB_GROW flag can be used to increase the amount of memory available 
  1401.  for suballocation. When using this flag, the setting of the DOSSUB_SPARSE_OBJ 
  1402.  flag must match the setting that was used on the initial call to DosSubSetMem. 
  1403.  The DOSSUB_INIT flag is ignored if DOSSUB_GROW is specified. This example 
  1404.  allocates 128K for use as a heap, but only initializes the heap to use the 
  1405.  first 64K. 
  1406.  
  1407.   if ( !(RetCode = DosAllocMem ((PPVOID) &pMem, 0x20000,
  1408.                      PAG_READ | PAG_WRITE)) )
  1409.   {
  1410.       RetCode = DosSubSetMem ((PVOID) pMem,
  1411.                    DOSSUB_INIT | DOSSUB_SPARSE_OBJ, 0x10000);
  1412.   }
  1413.  
  1414.  Later, the range of memory used for the heap can be increased by calling 
  1415.  DosSubSetMem as follows: 
  1416.  
  1417.   RetCode = DosSubSetMem (pMem,
  1418.                DOSSUB_GROW | DOSSUB_SPARSE_OBJ, 0x20000);
  1419.  
  1420.  Notice that the base address used in the second call to DosSubSetMem must 
  1421.  match that used in the first call. 
  1422.  
  1423.  If more than one process is going to perform memory suballocation from the 
  1424.  same heap, it is necessary to specify the DOSSUB_SERIALIZE flag. Because OS/2 
  1425.  is a multitasking system, the system can interrupt one process, which could be 
  1426.  in the middle of the code that is suballocating memory from the heap, to allow 
  1427.  another process to continue and possibly call to have memory suballocated from 
  1428.  the same heap. Because the first process may be in the middle of making 
  1429.  updates to the control information for the heap and the second process may 
  1430.  make updates as well, when the first process continues, the control 
  1431.  information may be corrupted. Because the heap is then in a corrupted state, 
  1432.  either the request to suballocate memory will never return or both processes 
  1433.  will eventually cause a protection violation. By specifying the 
  1434.  DOSSUB_SERIALIZE flag, OS/2 creates a semaphore for the heap and every request 
  1435.  to suballocate or free memory from the heap starts with a request to gain 
  1436.  access to the semaphore and releases it when it is done. This prevents more 
  1437.  than one process from executing within the heap management code at the same 
  1438.  time. 
  1439.  
  1440.  The first process to create the heap must allocate the memory as shared memory 
  1441.  (discussed later) and must use the DOSSUB_INIT and DOSSUB_SERIALIZE flags. 
  1442.  Other processes that want to share the heap must specify the DOSSUB_SERIALIZE 
  1443.  flags without the DOSSUB_INIT flag. We will use this in an example later when 
  1444.  we discuss shared memory. 
  1445.  
  1446.  When the heap has been initialized for suballocation, we can use the 
  1447.  DosSubAllocMem API to request memory: 
  1448.  
  1449.   APIRET DosSubAllocMem (PVOID pOffset, PPVOID ppBlockOffset,
  1450.                          ULONG ulSize)
  1451.  
  1452.  PVOID  pOffset                     Base address of the heap. 
  1453.  PPVOID  ppBlockOffset              Address of pointer to receive memory 
  1454.                                     address. 
  1455.  ULONG  ulSize                      Amount of memory for use by the heap. 
  1456.  
  1457.  All memory requests are rounded up to the next multiple of 8 bytes. The 
  1458.  following example requests 22 bytes from the heap allocated previously: 
  1459.  
  1460.   PBYTE  pSubMem;
  1461.   APIRET RetCode;
  1462.   RetCode = DosSubAllocMem (pMem, (PPVOID) &pSubMem, 22);
  1463.  
  1464.  When the suballocate memory is no longer needed, you can release it with the 
  1465.  DosSubFreeMem API: 
  1466.  
  1467.   APIRET DosSubFreeMem (PVOID pMem, PVOID pBlockOffset, ULONG ulSize)
  1468.  
  1469.  PVOID  pMem                        Base address of the heap. 
  1470.  PVOID  pBlockOffset                Address of pointer to receive memory 
  1471.                                     address. 
  1472.  ULONG  ulSize                      Size of memory to suballocate. 
  1473.  
  1474.  The amount of memory specified in ulSize will be rounded up to the next 
  1475.  multiple of 8 bytes and, after rounding, must match the amount actually 
  1476.  suballocated. The following example frees the memory requested in the previous 
  1477.  example: 
  1478.  
  1479.   RetCode = DosSubFreeMem (pMem, pSubMem, 24);
  1480.  
  1481.  When you are done with the heap, you must call the DosSubUnsetMem API to 
  1482.  enable OS/2 to free the resources it has allocated to manage the heap: 
  1483.  
  1484.   APIRET DosSubUnsetMem (PVOID pMem)
  1485.  
  1486.  PVOID  pMem                        Base address of the heap. 
  1487.  
  1488.  All calls to DosSubSetMem must be matched with an equivalent call to 
  1489.  DosSubUnsetMem. The memory used by the heap can then be freed with a call to 
  1490.  DosFreeMem after DosSubUnsetMem has been called. The following example ends 
  1491.  the use of the heap and frees the memory we allocated earlier: 
  1492.  
  1493.   if ( !(RetCode = DosSubUnsetMem ((PVOID) pMem)) )
  1494.   {
  1495.       RetCode = DosFreeMem ((PVOID) pMem);
  1496.   }
  1497.  
  1498.  
  1499. ΓòÉΓòÉΓòÉ 8.7. Shared Memory ΓòÉΓòÉΓòÉ
  1500.  
  1501. Until now we have talked about memory allocated for the private use of a 
  1502. process. Shared memory is memory that can be addressed by multiple processes. 
  1503. Shared memory is used when two or more processes need to share data or when 
  1504. data is copied to or from the OS/2 clipboard. While memory is allocated from 
  1505. the shared memory arena and the address space is reserved in the process 
  1506. address space of all processes, a process must explicitly gain access to the 
  1507. memory in order to access it. 
  1508.  
  1509. Once access to shared memory is obtained, the processes must coordinate among 
  1510. themselves whenever the memory is updated. This is usually done using 
  1511. semaphores. No coordination is required when just reading the shared memory. 
  1512.  
  1513. Shared memory is initially allocated by one process. So how do other 
  1514. applications know the address of the shared memory in order to access it? There 
  1515. are two methods for doing this. The first is to use named shared memory. In 
  1516. this case, shared memory is allocated, and a unique name is assigned to the 
  1517. memory. At that point, any application knowing the name of this memory can 
  1518. access it by referring to the same name. The second method is to use .i.unnamed 
  1519. shared memory;unnamed shared memory. In this case, shared memory is allocated, 
  1520. and the address of this memory is passed to the other applications. At that 
  1521. point, the other processes can access the memory. It is also possible for a 
  1522. process with access to a shared memory object to give access to another 
  1523. process. 
  1524.  
  1525. When each process with access to shared memory is finished using the memory, 
  1526. each process must free the shared memory. This is because the shared memory 
  1527. object maintains a count of the number of processes that have gained access to 
  1528. it, and the physical memory assigned to the shared memory object is not freed 
  1529. until all processes using the memory have freed it. Failure of each process to 
  1530. free the shared memory will result in reducing the address space available for 
  1531. shared memory. 
  1532.  
  1533. Shared memory is allocated by using the DosAllocSharedMem API: 
  1534.  
  1535.  APIRET APIENTRY DosAllocSharedMem (PPVOID ppb, PSZ pszName,
  1536.                ULONG cb, ULONG flag)
  1537.  
  1538.  PPVOID  ppb                        Address of pointer variable to receive the 
  1539.                                     memory address. 
  1540.  PSZ   pszName                      Name of the named shared memory object. 
  1541.                                     This name has the form \SHAREMEM\name. name 
  1542.                                     can be any name that meets the criteria for 
  1543.                                     a valid OS/2 filename. 
  1544.  ULONG  cb                          Maximum size of the memory object to be 
  1545.                                     allocated. 
  1546.  ULONG  flag                        Memory allocation flags: 
  1547.       PAG_READ            Allows read access. 
  1548.       PAG_EXECUTE         Allows execute access (executable code). 
  1549.       PAG_WRITE           Allows write access (includes read and execute 
  1550.                           access). 
  1551.       PAG_COMMIT          Commit pages when allocated. 
  1552.       OBJ_TILE            Allocate on 64K boundary. 
  1553.       OBJ_GETTABLE        Memory is gettable by other processes. 
  1554.       OBJ_GIVEABLE        Memory is giveable to other processes. 
  1555.  
  1556.  This function operates the same way as the DosAllocMem API, except that memory 
  1557.  is allocated from the shared address space and there are some additional 
  1558.  memory flags. To allocate named shared memory, the pszName field is set to the 
  1559.  name of the object. The OBJ_GETTABLE and OBJ_GIVEABLE memory allocation flags 
  1560.  are not allowed for named shared memory. To allocate unnamed shared memory, 
  1561.  the pszName field is set to NULL and at least one of the OBJ_GETTABLE or 
  1562.  OBJ_GIVEABLE flags must be specified. There are some macros defined in the 
  1563.  BSEMEMF.H header file, which is included by the BSEDOS.H header file: 
  1564.  
  1565.   #define fSHARE     (OBJ_GETTABLE + OBJ_GIVEABLE)
  1566.   #define fPERM      (PAG_EXECUTE + PAG_READ + PAG_WRITE)
  1567.   #define fALLOCSHR  (OBJ_TILE + PAG_COMMIT + fSHARE + fPERM)
  1568.   #define fGETNMSHR  (fPERM)
  1569.   #define fGETSHR    (fPERM)
  1570.   #define fGIVESHR   (fPERM)
  1571.  
  1572.  After shared memory has been committed, the protection flags and commit state 
  1573.  of the pages of memory can be changed with the DosSetMem API just as they were 
  1574.  for nonshared memory. Shared memory can also be queried as before using the 
  1575.  DosQuerymem API. If a page of shared memory has been committed, the additional 
  1576.  flag of PAG_SHARED will be returned for the shared pages when DosQueryMem is 
  1577.  used. Once a page of shared memory has been committed, it cannot be 
  1578.  decommitted. 
  1579.  
  1580.  For named shared memory, the DosGetNamedSharedMem API is used by other 
  1581.  processes to obtain access to the memory object: 
  1582.  
  1583.   APIRET APIENTRY DosGetNamedSharedMem (PPVOID ppBaseAddress,
  1584.                 PSZ pszSharedMemName, ULONG ulAttributeFlags)
  1585.  
  1586.  PPVOID  ppBaseAddress              Address of pointer to receive memory 
  1587.                                     address. 
  1588.  PSZ   pszSharedMemName             Name of the named shared memory object. 
  1589.                                     This name has the form \SHAREMEM\name. name 
  1590.                                     can be any name that meets the criteria for 
  1591.                                     a valid OS/2 filename. 
  1592.  ULONG  ulAttributeFlags            Desired access protection for the shared 
  1593.                                     memory: 
  1594.       PAG_READ            Read access. 
  1595.       PAG_EXECUTE         Execute access (executable code). 
  1596.       PAG_WRITE           Write access (includes read and execute access). 
  1597.  
  1598.  If a named shared memory object with the specified name exists, the process is 
  1599.  given access to the memory, and its address is returned in ppBaseAddress. The 
  1600.  following example shows one process allocating 32K of named shared memory and 
  1601.  another process gaining access to it. 
  1602.  
  1603.  Process 1: 
  1604.  
  1605.   PVOID pMem;
  1606.  
  1607.   if (!DosAllocSharedMem (&pMem, "\\SHAREMEM\\OBJECT1", 0x8000L,
  1608.                  fPERM | PAG_COMMIT | OBJ_TILE))
  1609.   {
  1610.        strcpy ((PSZ)pMem, "Hello Process 2");
  1611.   }
  1612.  
  1613.  Process 2: 
  1614.  
  1615.   PVOID pMem;
  1616.   if (!DosGetNamedSharedMem (&pMem, "\\SHAREMEM\\OBJECT1", fPERM))
  1617.   {
  1618.        strcpy ((PSZ)pMem, "Hello to you Process 1");
  1619.   }
  1620.  
  1621.  For unnamed shared memory, there are two ways that memory access can be 
  1622.  obtained by a second process. The first is for the second process to use the 
  1623.  DosGetSharedMem API: 
  1624.  
  1625.   APIRET APIENTRY DosGetSharedMem (PVOID pBaseAddress,
  1626.              ULONG ulAttributeFlags)
  1627.  
  1628.  PVOID  pBaseAddress                The base address of the shared memory 
  1629.                                     object. 
  1630.  ULONG  ulAttributeFlags            Desired access protection for the shared 
  1631.                                     memory: 
  1632.       PAG_READ            Read access. 
  1633.       PAG_EXECUTE         Execute access (executable code). 
  1634.       PAG_WRITE           Write access (includes read and execute access). 
  1635.  
  1636.  In order for the DosGetSharedMem request to succeed, the memory object must 
  1637.  have been allocated with the OBJ_GETTABLE flag, and the requested 
  1638.  ulAttributeFlags must be compatible with the current protection flags for the 
  1639.  memory object. Note that the address passed in pBaseAddress must be the base 
  1640.  address of the memory object. The following example shows one process 
  1641.  allocating 32K of unnamed shared memory, passing the address to the second 
  1642.  process, and the second process gaining access to it. 
  1643.  
  1644.  Process 1: 
  1645.  
  1646.   #define WM_USER_SHARED_MEM    WM_USER+1
  1647.  
  1648.   PVOID pMem;
  1649.   HWND  hWndProcess2;
  1650.  
  1651.   if (!DosAllocSharedMem (&pMem, NULL, 0x8000L,
  1652.   fPERM | PAG_COMMIT | OBJ_TILE | OBJ_GETTABLE |
  1653.   OBJ_GIVEABLE))
  1654.   {
  1655.        strcpy ((PSZ)pMem, "Hello Process 2");
  1656.        WinSendMsg (hWndProcess2, WM_USER_SHARED_MEM, (MPARAM)pMem, 0L);
  1657.   }
  1658.  
  1659.  Process 2: 
  1660.  
  1661.   #define WM_USER_SHARED_MEM    WM_USER+1
  1662.   PVOID pMem;
  1663.   MRESULT EXPENTRY MainWndProcProc (HWND hWnd, ULONG msg,
  1664.               MPARAM mp1, MPARAM mp2)
  1665.   {
  1666.        switch (msg)
  1667.        {
  1668.             ...
  1669.           case WM_USER_SHARED_MEM:
  1670.           pMem = (PVOID)mp1;
  1671.   if (!DosGetSharedMem (pMem, fPERM))
  1672.           strcpy ((PSZ)pMem, "Hello to you Process 1");
  1673.           return (0L);
  1674.   ...
  1675.        }
  1676.   return (WinDefWindowProc (hWnd, msg, mp1, mp2));
  1677.   }
  1678.  
  1679.  In this example, we used a message (WM_USER_SHARED_MEM) to pass the address of 
  1680.  the memory object to Process 2. It could also have been done other ways using 
  1681.  interprocess communication or through global data in a DLL using a single data 
  1682.  segment. 
  1683.  
  1684.  The second way for a process to gain access to unnamed shared memory is to 
  1685.  have a process that currently has access to explicitly give access to another 
  1686.  process. This is accomplished with the DosGiveSharedMem API: 
  1687.  
  1688.   APIRET APIENTRY DosGiveSharedMem (PVOID pBaseAddress,
  1689.                PID idProcessID, ULONG ulAttributeFlags)
  1690.  
  1691.  PVOID  pBaseAddress                The base address of the shared memory 
  1692.                                     object. 
  1693.  PID   idProcessID                  Process identifier of process to be given 
  1694.                                     access. 
  1695.  ULONG  ulAttributeFlags            Desired access protection for the shared 
  1696.                                     memory: 
  1697.       PAG_READ            Read access. 
  1698.       PAG_EXECUTE         Execute access (executable code). 
  1699.       PAG_WRITE           Write access (includes read and execute access). 
  1700.  
  1701.  In order for the DosGiveSharedMem request to succeed, the memory object must 
  1702.  have been allocated with the OBJ_GIVEABLE flag, and the requested 
  1703.  ulAttributeFlags must be compatible with the current protection flags for the 
  1704.  memory object. Note again that the address passed in pBaseAddress must be the 
  1705.  base address of the memory object. The following example shows one process 
  1706.  allocating 32K of unnamed shared memory, giving access of it to another 
  1707.  process, and then passing the address to the second process. 
  1708.  
  1709.  Process 1: 
  1710.  
  1711.   #define WM_USER_SHARED_MEM    WM_USER+1
  1712.  
  1713.   PVOID pMem;
  1714.   PID   pidProcess2;
  1715.   HWND  hWndProcess2;
  1716.  
  1717.   if (!DosAllocSharedMem (&pMem, NULL, 0x8000L,
  1718.   fPERM | PAG_COMMIT | OBJ_TILE | OBJ_GETTABLE |
  1719.   OBJ_GIVEABLE))
  1720.   {
  1721.        strcpy ((PSZ)pMem, "Hello Process 2");
  1722.   if (!DosGiveSharedMem (pMem, pidProcess2, fPERM)) WinSendMsg
  1723.      (hWndProcess2, WM_USER_SHARED_MEM, (MPARAM)pMem, 0L);
  1724.        else
  1725.             DosFreeMem (pMem);
  1726.   }
  1727.  
  1728.  Process 2: 
  1729.  
  1730.   #define WM_USER_SHARED_MEM    WM_USER+1
  1731.   PVOID pMem;
  1732.   MRESULT EXPENTRY MainWndProcProc (HWND hWnd, ULONG msg,
  1733.               MPARAM mp1, MPARAM mp2)
  1734.   {
  1735.        switch (msg)
  1736.        {
  1737.             ...
  1738.           case WM_USER_SHARED_MEM:
  1739.           pMem = (PVOID)mp1;
  1740.   strcpy ((PSZ)pMem, "Hello to you Process 1"); return (0L);
  1741.             ...
  1742.        }
  1743.   return (WinDefWindowProc (hWnd, msg, mp1, mp2));
  1744.   }
  1745.  
  1746.  Again, in this example, we used a message (WM_USER_SHARED_MEM) to pass the 
  1747.  address of the memory object to Process 2. Process 2 does not have to do 
  1748.  anything to the memory object in order to use it since Process 1 has already 
  1749.  given it access. The identifier for Process 2 must have been passed to Process 
  1750.  1 by using interprocess communication or through global data in a DLL by using 
  1751.  a single data segment. 
  1752.  
  1753.  It is important to note again that each process is responsible for calling 
  1754.  DosFreeMem for each shared memory object it has access to when it is done 
  1755.  using the memory. 
  1756.  
  1757.  We showed in an earlier section how to improve the memory allocation 
  1758.  performance and reduce the amount of memory management overhead on the 
  1759.  application by using suballocated memory. Suballocated memory can also be used 
  1760.  for shared memory objects, but you should use the DOSSUB_SERIALIZE flag when 
  1761.  allocating the shared memory object. OS/2 creates a semaphore specifically for 
  1762.  the shared memory object and automatically requests access to the semaphore 
  1763.  for all memory suballocation requests and free operations. Following is an 
  1764.  example of creating a shared memory object for use by memory suballocation and 
  1765.  what is required by each process sharing this memory. 
  1766.  
  1767.  Process 1 allocates a 128K block of shared memory and initializes it for 
  1768.  memory suballocation. 
  1769.  
  1770.  Process 1: 
  1771.  
  1772.   PVOID pHeap;
  1773.  
  1774.   if (!DosAllocSharedMem (&pHeap, NULL, 0x20000L,
  1775.                           fPERM | OBJ_GETTABLE) &&
  1776.   !DosSubSet (pHeap, DOSSUB_INIT | DOSSUB_SPARSE_OBJ |
  1777.   DOSSUB_SERIALIZE,
  1778.           0x20000L)
  1779.   {
  1780.        PVOID pSubMem;
  1781.  
  1782.        if (!DosSubAlloc (pHeap, &pSubMem, 0x1000L,))
  1783.        {
  1784.             ...
  1785.           DosSubFree (pHeap, pSubMem, 0x1000L);
  1786.        }
  1787.   }
  1788.  
  1789.  Any processes wanting to share this memory and use the suballocation must 
  1790.  first gain access to the memory and then call DosSubSet. The call to DosSubSet 
  1791.  does not reinitialize the memory for suballocation but does give the process 
  1792.  access to the semaphore created by OS/2 for serializing requests to the memory 
  1793.  object. 
  1794.  
  1795.  Process 2: 
  1796.  
  1797.   PVOID pHeap;
  1798.  
  1799.   if (!DosGetSharedMem (pHeap, fPERM) &&
  1800.        !DosSubSet (pHeap, DOSSUB_SPARSE_OBJ | DOSSUB_SERIALIZE))
  1801.   {
  1802.        PVOID pSubMem;
  1803.  
  1804.        if (!DosSubAlloc (pHeap, &pSubMem, 0x1000L,))
  1805.        {
  1806.             ...
  1807.   DosSubFree (pHeap, pSubMem, 0x1000L);
  1808.        }
  1809.   }
  1810.  
  1811.  When each process is finished with the shared memory object, it must first 
  1812.  call DosSubUnsetMem to release its access to the semaphore that OS/2 created. 
  1813.  It must then call DosFreeMem to free the shared memory for the process. 
  1814.  
  1815.  Process 1: 
  1816.  
  1817.   /* Termination code for process */
  1818.   DosSubUnsetMem (pHeap);
  1819.   DosFreeMem (pHeap);
  1820.   ...
  1821.  
  1822.  Process 2: 
  1823.  
  1824.   /* Termination code for process */
  1825.   DosSubUnsetMem (pHeap);
  1826.   DosFreeMem (pHeap);
  1827.   ...
  1828.  
  1829.  
  1830. ΓòÉΓòÉΓòÉ 8.8. Converting from Unshared to Shared Memory ΓòÉΓòÉΓòÉ
  1831.  
  1832. There are many times when you have a memory object that is allocated as a 
  1833. private memory object, and you need to pass the information to another process 
  1834. or even copy it to the clipboard. In those circumstances, it is necessary to 
  1835. move the data to shared memory. The following function shows the steps to take 
  1836. a private memory object and convert it to a shared memory object. This process 
  1837. simply requires us to determine the size of the private memory object, allocate 
  1838. a shared memory object of the same size, and copy the data. The function 
  1839. ConvertToSharedMemory assumes that the committed pages of the private data 
  1840. object consist of contiguous pages starting at the base address. 
  1841.  
  1842. PVOID ConvertToSharedMemory (PVOID pPrivateMem, BOOL bFree) {
  1843. /* Convert the private memory pointed to by pPrivateMem to shared
  1844.    memory. If bFree is specified, free the memory pointed
  1845.    to by pPrivateMem after creating the shared memory
  1846.    object. Return NULL if the convert fails.      */
  1847.  
  1848.      PVOID pSharedMem = NULL;
  1849.      ULONG ulSize;
  1850.      ULONG ulFlags;
  1851.  
  1852.      ulSize = 0xFFFFFFFFL;
  1853.  
  1854. if ( !DosQueryMem (pPrivateMem, &ulSize, &ulFlag) &&
  1855.                     (ulFlag & PAG_COMMIT) &&
  1856. !DosAllocSharedMem (&pSharedMem, NULL, ulSize,
  1857.                     (ulFlag & fALLOC) | fSHARE) )
  1858.      {
  1859. memcpy (pSharedMem, pPrivateMem, ulSize);
  1860.                if (bFree)
  1861.                          DosFreeMem (pPrivateMem);
  1862.      }
  1863.  
  1864.      return (pSharedMem);
  1865. }
  1866.  
  1867. In order to successfully convert the pointer, there must be committed memory in 
  1868. the private memory object, and the shared memory object must be successfully 
  1869. allocated: 
  1870.  
  1871. if ( !DosQueryMem (pPrivateMem, &ulSize, &ulFlag) &&
  1872.                     (ulFlag & PAG_COMMIT) &&
  1873. !DosAllocSharedMem (&pSharedMem, NULL, ulSize,
  1874.                      (ulFlag & fALLOC) | fSHARE) )
  1875.  
  1876. The flags used for the DosAllocSharedMem call are the existing flags for the 
  1877. private memory object (including the PAG_COMMIT) plus the fSHARE flags. 
  1878.  
  1879.  
  1880. ΓòÉΓòÉΓòÉ 8.9. The MEMMAP Application ΓòÉΓòÉΓòÉ
  1881.  
  1882. This sample application demonstrates most features and API calls needed to 
  1883. query memory within OS/2. 
  1884.  
  1885.  
  1886. ΓòÉΓòÉΓòÉ 8.10. MEMMAP's Files ΓòÉΓòÉΓòÉ
  1887.  
  1888. The files necessary to build the MEMMAP application are the following: 
  1889.  
  1890.       MEMMAP.DEF 
  1891.       MEMMAP.DLG 
  1892.       MEMMAP.C 
  1893.       MEMMAP.H 
  1894.       MEMMAP.RC 
  1895.       MEMMAP.ICO 
  1896.  
  1897.  
  1898. ΓòÉΓòÉΓòÉ 8.11. MEMMAP.C ΓòÉΓòÉΓòÉ
  1899.  
  1900. /* ----------------------------------------------------------------
  1901.                            MemMap Program
  1902.                               Chapter 9
  1903.                     Real-World Programming for OS/2 2.1
  1904.              Copyright (c) 1993 Blain, Delimon, and English
  1905. ---------------------------------------------------------------- */
  1906.  
  1907. #define INCL_WIN
  1908. #define INCL_GPI
  1909. #define INCL_DOSERRORS
  1910. #include <os2.h>
  1911. #include <stdio.h>
  1912. #include "memmap.h"
  1913. #include "..\..\common\about.h"
  1914.  
  1915. /* Exported Functions */
  1916.  
  1917. MRESULT EXPENTRY MainDlgProc (HWND,ULONG,MPARAM,MPARAM);
  1918.  
  1919. /* Local Functions */
  1920.  
  1921. VOID  CenterWindow (HWND);
  1922. VOID  MemError (PSZ);
  1923. ULONG ParseItem (PSZ,ULONG);
  1924. VOID  QueryMemory (VOID);
  1925.  
  1926. HAB   hab;
  1927. CHAR  szTitle[64];
  1928. HWND  hWndFrame;
  1929. HWND  hWndMemList;
  1930. HWND  hWndStartAddress;
  1931. ULONG ulStartAddress    = 0L;
  1932. CHAR  szStartAddress[9] = "00000000";
  1933. PVOID pStartAddress     = (PVOID)szStartAddress;
  1934.  
  1935. /* Undocumented menu message */
  1936. #define MM_QUERYITEMBYPOS      0x01f3
  1937. #define MAKE_16BIT_POINTER(p)  \
  1938.             ((PVOID)MAKEULONG(LOUSHORT(p),(HIUSHORT(p) << 3) | 7))
  1939.  
  1940. int main()
  1941. {
  1942.   HMQ   hmq;
  1943.   QMSG  qmsg;
  1944.  
  1945.   hab = WinInitialize (0);
  1946.   hmq = WinCreateMsgQueue (hab, 0);
  1947.  
  1948.   WinLoadString (hab, 0, ID_APPNAME, sizeof(szTitle), szTitle);
  1949.  
  1950.   hWndFrame = WinLoadDlg (HWND_DESKTOP, HWND_DESKTOP,
  1951.       MainDlgProc, 0, ID_APPNAME, NULL);
  1952.   WinSendMsg (hWndFrame, WM_SETICON,
  1953.       (MPARAM)WinLoadPointer (HWND_DESKTOP, 0, ID_APPNAME), NULL);
  1954.  
  1955.   while (WinGetMsg (hab, &qmsg, 0, 0, 0))
  1956.     WinDispatchMsg (hab, &qmsg);
  1957.  
  1958.   WinDestroyWindow (hWndFrame);
  1959.   WinDestroyMsgQueue (hmq);
  1960.   WinTerminate (hab);
  1961.   return (0);
  1962. }
  1963.  
  1964. VOID AddAboutToSystemMenu(HWND hWndFrame)
  1965. {
  1966.   MENUITEM mi;
  1967.   HWND     hWndSysSubMenu;
  1968.  
  1969.   WinSendMsg (WinWindowFromID (hWndFrame, FID_SYSMENU),
  1970.        MM_QUERYITEMBYPOS, 0L, MAKE_16BIT_POINTER(&mi));
  1971.   hWndSysSubMenu = mi.hwndSubMenu;
  1972.   mi.iPosition   = MIT_END;
  1973.   mi.afStyle     = MIS_SEPARATOR;
  1974.   mi.afAttribute = 0;
  1975.   mi.id          = -1;
  1976.   mi.hwndSubMenu = 0;
  1977.   mi.hItem       = 0;
  1978.   WinSendMsg (hWndSysSubMenu, MM_INSERTITEM, MPFROMP (&mi), NULL);
  1979.   mi.afStyle     = MIS_TEXT;
  1980.   mi.id          = IDM_ABOUT;
  1981.   WinSendMsg (hWndSysSubMenu, MM_INSERTITEM, MPFROMP (&mi),
  1982.       "About...");
  1983.   return;
  1984. }
  1985.  
  1986. VOID CenterWindow (HWND hWnd)
  1987. {
  1988.   ULONG ulScrWidth, ulScrHeight;
  1989.   RECTL Rectl;
  1990.  
  1991.   ulScrWidth  = WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN);
  1992.   ulScrHeight = WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN);
  1993.   WinQueryWindowRect (hWnd,&Rectl);
  1994.   WinSetWindowPos (hWnd, HWND_TOP, (ulScrWidth-Rectl.xRight)/2,
  1995.       (ulScrHeight-Rectl.yTop)/2, 0, 0, SWP_MOVE | SWP_ACTIVATE);
  1996.   return;
  1997. }
  1998.  
  1999. VOID MemError (PSZ pszMessage)
  2000. {
  2001.   WinMessageBox (HWND_DESKTOP, hWndFrame, pszMessage,
  2002.       "Memory Map", 0, MB_ERROR | MB_OK);
  2003.   return;
  2004. }
  2005.  
  2006. ULONG ParseItem (PSZ szItem, ULONG CurPos)
  2007. {
  2008.   ULONG EndPos = CurPos + 8;
  2009.   ULONG ulMem  = 0;
  2010.   for (; CurPos < EndPos; CurPos++)
  2011.   {
  2012.     if (szItem[CurPos] != ' ')
  2013.       ulMem = ulMem*16 +
  2014.           ((szItem[CurPos] <= '9') ? (szItem[CurPos] - '0') :
  2015.                                      (szItem[CurPos] - 'A' + 10));
  2016.   }
  2017.   return (ulMem);
  2018. }
  2019.  
  2020. VOID QueryMemory ()
  2021. {
  2022.   char   szText[90];
  2023.   ULONG  ulAddress,
  2024.          ulEndAddress,
  2025.          ulPage,
  2026.          ulSize,
  2027.          ulFlags;
  2028.   APIRET RetCode;
  2029.  
  2030.   WinSetPointer (HWND_DESKTOP,
  2031.       WinQuerySysPointer (HWND_DESKTOP, SPTR_WAIT, FALSE));
  2032.   WinEnableWindowUpdate (hWndMemList, FALSE);
  2033.   ulAddress    = ulStartAddress;
  2034.   ulEndAddress = ulStartAddress + 0x02000000;  /* 32 MB max */
  2035.   if (ulEndAddress > 0x20000000)
  2036.     ulEndAddress = 0x20000000;
  2037.   ulPage       = 0L;
  2038.   sprintf (szText, "%08lx  . . . . . . . . . . . . . . . .         ",
  2039.       ulAddress);
  2040.   WinUpper (hab, 0, 0, szText);
  2041.   while (ulAddress < ulEndAddress)
  2042.   {
  2043.     ulSize = 0xFFFFFFFF;
  2044.     if (!(RetCode = DosQueryMem ((PVOID)ulAddress, &ulSize,
  2045.                         &ulFlags)))
  2046.     {
  2047.       if (ulFlags == PAG_FREE)
  2048.         ulSize = 0x1000;
  2049.       else
  2050.         ulSize = (ulSize + 0xFFF) & 0xFFFFF000;
  2051.       if (ulFlags & PAG_BASE)
  2052.         szText[42] = '*';
  2053.       while (ulSize && (ulAddress < 0x20000000))
  2054.       {
  2055.         if (ulFlags & PAG_COMMIT)
  2056.           szText[10 + ulPage*2] = 'C';
  2057.         else if (!(ulFlags & PAG_FREE))
  2058.           szText[10 + ulPage*2] = 'A';
  2059.         ulAddress += 0x1000;
  2060.         ulSize    -= 0x1000;
  2061.         ulPage++;
  2062.         if (ulPage == 16)
  2063.         {
  2064.           if (ulFlags & PAG_SHARED)
  2065.             sprintf (&szText[43], "%s", "Shared ");
  2066.           else if (ulFlags & PAG_FREE)
  2067.             sprintf (&szText[43], "%s", "Free   ");
  2068.           else
  2069.             sprintf (&szText[43], "%s", "Private");
  2070.           if (WinInsertLboxItem (
  2071.                   WinWindowFromID (hWndFrame, IDL_MEMLIST),
  2072.                   LIT_END, szText) < 0)
  2073.             break;
  2074.           ulPage = 0;
  2075.           sprintf (szText,
  2076.               "%08lx  . . . . . . . . . . . . . . . .         ",
  2077.               ulAddress);
  2078.           WinUpper (hab, 0, 0, szText);
  2079.         }
  2080.       }
  2081.     }
  2082.     else if (RetCode == ERROR_INVALID_ADDRESS)
  2083.     {
  2084.       ulAddress += 0x10000;
  2085.       sprintf (&szText[43], "%s", "Invalid");
  2086.       WinInsertLboxItem (WinWindowFromID (hWndFrame, IDL_MEMLIST),
  2087.           LIT_END, szText);
  2088.       sprintf (szText,
  2089.           "%08lx  . . . . . . . . . . . . . . . .         ",
  2090.           ulAddress);
  2091.       WinUpper (hab, 0, 0, szText);
  2092.     }
  2093.     else
  2094.     {
  2095.       sprintf (szText, "Error querying memory address %08lx",
  2096.           ulAddress);
  2097.       MemError (szText);
  2098.       break;
  2099.     }
  2100.   }
  2101.   WinSetPointer (HWND_DESKTOP,
  2102.       WinQuerySysPointer (HWND_DESKTOP,SPTR_ARROW,FALSE));
  2103.   WinEnableWindowUpdate (hWndMemList, TRUE);
  2104. }
  2105.  
  2106.  
  2107. MRESULT EXPENTRY MainDlgProc (HWND hWnd, ULONG msg,
  2108.                               MPARAM mp1, MPARAM mp2)
  2109. {
  2110.   BOOL    bHandled = TRUE;
  2111.   MRESULT mReturn  = 0;
  2112.  
  2113.   switch (msg)
  2114.   {
  2115.     case WM_INITDLG:
  2116.       CenterWindow (hWnd);
  2117.  
  2118.       /* Add the About menu item to the system menu */
  2119.       AddAboutToSystemMenu (hWnd);
  2120.  
  2121.       hWndMemList      = WinWindowFromID (hWnd, IDL_MEMLIST);
  2122.       hWndStartAddress = WinWindowFromID (hWnd, IDB_STARTADDRESS);
  2123.  
  2124.       WinSendMsg (hWndStartAddress, SPBM_SETTEXTLIMIT,
  2125.           (MPARAM)8, (MPARAM)0);
  2126.       WinSendMsg (hWndStartAddress, SPBM_SETARRAY,
  2127.           (MPARAM)&pStartAddress, (MPARAM)1L);
  2128.       WinSendMsg (hWndStartAddress, SPBM_SETCURRENTVALUE,
  2129.           (MPARAM)0L, (MPARAM)0L);
  2130.       WinSetFocus (HWND_DESKTOP, hWndStartAddress);
  2131.       WinPostMsg (hWnd, WM_COMMAND, (MPARAM)IDB_REFRESH, 0L);
  2132.       break;
  2133.  
  2134.     case WM_CONTROL:
  2135.       switch (LOUSHORT(mp1))
  2136.       {
  2137.         case IDL_MEMLIST:
  2138.           if (HIUSHORT(mp1) == LN_SELECT)
  2139.           {
  2140.             WinQueryLboxItemText (hWndMemList,
  2141.                  WinQueryLboxSelectedItem((HWND)mp2),
  2142.                  szStartAddress,9);
  2143.             ulStartAddress = ParseItem (szStartAddress, 0);
  2144.             WinSendMsg (hWndStartAddress, SPBM_SETARRAY,
  2145.                 (MPARAM)&pStartAddress, (MPARAM)1L);
  2146.           }
  2147.           break;
  2148.  
  2149.         case IDB_STARTADDRESS:
  2150.           if (HIUSHORT(mp1) == SPBN_UPARROW)
  2151.             ulStartAddress = (ulStartAddress + 0x10000) & 0x1FFFFFFF;
  2152.           else if (HIUSHORT(mp1) == SPBN_DOWNARROW)
  2153.             ulStartAddress = (ulStartAddress - 0x10000) & 0x1FFFFFFF;
  2154.           sprintf (szStartAddress,"%08lx",ulStartAddress);
  2155.           WinUpper (hab, 0, 0, szStartAddress);
  2156.           WinSendMsg (hWndStartAddress, SPBM_SETARRAY,
  2157.               (MPARAM)&pStartAddress, (MPARAM)1L);
  2158.           break;
  2159.       }
  2160.       break;
  2161.  
  2162.     case WM_COMMAND:
  2163.     case WM_SYSCOMMAND:
  2164.       switch (LOUSHORT(mp1))
  2165.       {
  2166.         case IDB_REFRESH:
  2167.           WinSendDlgItemMsg (hWndFrame, IDL_MEMLIST, LM_DELETEALL,
  2168.               0L, 0L);
  2169.           QueryMemory ();
  2170.           WinSendMsg (hWndMemList, LM_SELECTITEM,
  2171.               (MPARAM)0, (MPARAM)TRUE);
  2172.           break;
  2173.  
  2174.         case IDM_ABOUT:
  2175.           DisplayAbout (hWnd, szTitle);
  2176.           break;
  2177.  
  2178.         case SC_CLOSE:
  2179.           WinPostMsg (hWnd, WM_QUIT, 0L, 0L);
  2180.           break;
  2181.  
  2182.         default:
  2183.           bHandled = (msg == WM_COMMAND);
  2184.       }
  2185.       break;
  2186.  
  2187.     default:
  2188.       bHandled = FALSE;
  2189.       break;
  2190.   }
  2191.  
  2192.   if (!bHandled)
  2193.     mReturn = WinDefDlgProc (hWnd, msg, mp1, mp2);
  2194.  
  2195.   return (mReturn);
  2196. }
  2197.  
  2198.  
  2199. ΓòÉΓòÉΓòÉ 8.12. MEMMAP.H ΓòÉΓòÉΓòÉ
  2200.  
  2201. /* ----------------------------------------------------------------
  2202.                          MemMap Header File
  2203.                               Chapter 9
  2204.                     Real-World Programming for OS/2 2.1
  2205.              Copyright (c) 1993 Blain, Delimon, and English
  2206. ---------------------------------------------------------------- */
  2207.  
  2208. #define ID_APPNAME         1
  2209.  
  2210. #define IDL_MEMLIST       10
  2211. #define IDB_REFRESH       11
  2212. #define IDT_PAGES         12
  2213. #define IDB_STARTADDRESS  13
  2214.  
  2215. #define IDM_ABOUT        100
  2216.  
  2217.  
  2218. ΓòÉΓòÉΓòÉ 8.13. MEMMAP.RC ΓòÉΓòÉΓòÉ
  2219.  
  2220. /* ----------------------------------------------------------------
  2221.                         MemMap Resource File
  2222.                               Chapter 9
  2223.                     Real-World Programming for OS/2 2.1
  2224.              Copyright (c) 1993 Blain, Delimon, and English
  2225. ---------------------------------------------------------------- */
  2226.  
  2227. #include <os2.h>
  2228. #include "memmap.h"
  2229.  
  2230. ICON ID_APPNAME MEMMAP.ICO
  2231.  
  2232. STRINGTABLE LOADONCALL MOVEABLE
  2233. BEGIN
  2234.     ID_APPNAME      "Memory Map Application"
  2235. END
  2236.  
  2237. rcinclude memmap.dlg
  2238. rcinclude ..\..\common\about.dlg
  2239.  
  2240.  
  2241. ΓòÉΓòÉΓòÉ 8.14. MEMMAP.DLG ΓòÉΓòÉΓòÉ
  2242.  
  2243. /* ----------------------------------------------------------------
  2244.                             MemMap Dialog
  2245.                               Chapter 9
  2246.                     Real-World Programming for OS/2 2.1
  2247.              Copyright (c) 1993 Blain, Delimon, and English
  2248. ---------------------------------------------------------------- */
  2249.  
  2250. DLGTEMPLATE ID_APPNAME LOADONCALL MOVEABLE DISCARDABLE
  2251. BEGIN
  2252.  DIALOG  "Memory Map", ID_APPNAME, 36, 17, 302, 165,
  2253.   WS_VISIBLE | FS_DLGBORDER,
  2254.   FCF_SYSMENU | FCF_TITLEBAR | FCF_DLGBORDER |
  2255.   FCF_TASKLIST | FCF_ICON;
  2256.  BEGIN
  2257.   LTEXT      "Address", -1, 15, 145, 37, 8
  2258.   LTEXT      "Page", -1, 139, 154, 24, 8
  2259.   LTEXT      "0 1 2 3 4 5 6 7 8 9 A B C D E F", IDT_PAGES,
  2260.              64, 145, 174, 8
  2261.              PRESPARAMS PP_FONTNAMESIZE, "10.System Monospaced"
  2262.   LTEXT      "Type", -1, 248, 145, 22, 8
  2263.   LTEXT      ". = Free  A = Allocated  C = Committed  * = Base",
  2264.              -1, 77, 6, 207, 8
  2265.   LISTBOX    IDL_MEMLIST, 10, 36, 282, 107
  2266.              PRESPARAMS PP_FONTNAMESIZE, "10.System Monospaced"
  2267.   PUSHBUTTON "Refresh", 11, 8, 4, 45, 14
  2268.   LTEXT      "Start Address", DID_CANCEL, 9, 23, 60, 8
  2269.   CONTROL    "", IDB_STARTADDRESS, 73, 20, 64, 12, WC_SPINBUTTON,
  2270.              SPBS_ALLCHARACTERS | SPBS_READONLY |
  2271.              SPBS_MASTER | SPBS_JUSTRIGHT |
  2272.              SPBS_FASTSPIN | WS_GROUP | WS_TABSTOP | WS_VISIBLE
  2273.              PRESPARAMS PP_FONTNAMESIZE, "10.System Monospaced"
  2274.  END
  2275. END
  2276.  
  2277.  
  2278. ΓòÉΓòÉΓòÉ 8.15. Using MEMMAP ΓòÉΓòÉΓòÉ
  2279.  
  2280. Add the MEMMAP application icon to a window and open the program. You should 
  2281. see a display similar to Figure 9.5. 
  2282.  
  2283. The MEMMAP application merely displays a map of the memory available to the 
  2284. MEMMAP process. The memory will be marked Free, Allocated, Committed, or Base. 
  2285. Figure 9.5. MEMMAP application.
  2286.  
  2287. Remember base memory is the starting address of a block of memory. If a process 
  2288. allocated two pages of memory, the first page will be marked as base, the 
  2289. second will not. Take a look at the memory map that MEMMAP displays. Each 
  2290. asterisk signals the beginning of a new allocated block. Gaps indicate large 
  2291. blocks of memory. 
  2292.  
  2293. Because the only memory available to the MEMMAP application is that which has 
  2294. been allocated for its own process, the map will not change much between 
  2295. differing instances of the application. 
  2296.  
  2297.  
  2298. ΓòÉΓòÉΓòÉ 8.16. Understanding MEMMAP's Code ΓòÉΓòÉΓòÉ
  2299.  
  2300. The code for MEMMAP is similar to that of the MEMORY sample application, which 
  2301. is detailed following the MEMMAP application. The major difference lies in the 
  2302. QueryMemory function, which is detailed in following text. Work through 
  2303. understanding this smaller portion of both applications before going on to 
  2304. tackle the MEMORY application. 
  2305.  
  2306. The QueryMemory function will query 32M of memory starting at ulStartAddress. 
  2307. We stop at 32M because our list box can only hold so many entries. This 
  2308. function will check for all the features of paged memory allocation, as well as 
  2309. correct for a couple of OS/2 quirks. 
  2310.  
  2311. We begin by calculating our ending address and ensuring it is less than our 
  2312. 512M limit. We now loop until we have reached the end of our range. The call to 
  2313. DosQueryMem queries the maximum memory size starting at our current address. 
  2314. Remember that if the address queried is the first page of a memory object, the 
  2315. PAG_BASE flag is set. If the page is not currently allocated, the PAG_FREE flag 
  2316. is set. Also, the DosQueryMem call will query pages until it finds a page with 
  2317. a memory flag different from the first page queried or until it finds the first 
  2318. page of the next allocated memory object. 
  2319.  
  2320. Each call to DosQueryMem will start at the address in ulAddress and return the 
  2321. size of the memory pages that have the same flags as the first page at 
  2322. ulAddress. The ulFlags variable will contain those flags. Here, we discover a 
  2323. quirk in the DosQueryMem function. If the first page queried is free memory 
  2324. (PAG_FREE), the size of the memory object returned is not a believable value. 
  2325. In other words, we can be sure that only one page is marked as PAG_FREE. Do not 
  2326. use the size returned in ulSize as the size of contiguous PAG_FREE pages. For 
  2327. this reason, if the PAG_FREE bit is set, we reset ulSize to one 4K page; 
  2328. otherwise, we round the size to a 4K page boundary. At this point, we loop 
  2329. through the memory size returned, setting the appropriate page flags for 
  2330. allocated and committed pages. 
  2331.  
  2332. We also output the type of memory object each 64K block of memory represents 
  2333. (Shared, Free, or Private). At this point ulAddress contains the address of the 
  2334. first page past the memory object just processed. If the return code from 
  2335. DosQueryMem is ERROR_INVALID_ADDRESS, we are unable to query that address, so 
  2336. we skip that memory object and go to the next 64K block. 
  2337.  
  2338. Remember that a program can query memory only for the current process. It does 
  2339. not have access to another process's address space. This function, thus, only 
  2340. queries the memory allocated for the MemMap program. You, however, can use this 
  2341. function and add it to any program to query its allocated and committed memory. 
  2342.  
  2343.  
  2344. ΓòÉΓòÉΓòÉ 8.17. The MEMORY Application ΓòÉΓòÉΓòÉ
  2345.  
  2346. This sample application demonstrates allocating, committing, freeing, and 
  2347. changing the access rights to blocks of memory.  It also utilizes the 
  2348. techniques from the MEMMAP program to display the status of each page of an 
  2349. allocated memory object. 
  2350.  
  2351.  
  2352. ΓòÉΓòÉΓòÉ 8.18. MEMORY's Files ΓòÉΓòÉΓòÉ
  2353.  
  2354. The files necessary to build the MEMORY application are the following: 
  2355.  
  2356.       MEMORY.C 
  2357.       MEMORY.H 
  2358.       MEMORY.DEF 
  2359.       MEMORY.RC 
  2360.       ALLOCATE.DLG 
  2361.       MEMORY.DLG 
  2362.       MEMORY.ICO 
  2363.  
  2364.  
  2365. ΓòÉΓòÉΓòÉ 8.19. MEMORY.C ΓòÉΓòÉΓòÉ
  2366.  
  2367. /* --------------------------------------------------------------------
  2368.                            Memory Program
  2369.                               Chapter 9
  2370.                     Real-World Programming for OS/2 2.1
  2371.              Copyright (c) 1993 Blain, Delimon, and English
  2372. ------------------------------------------------------------------ */
  2373.  
  2374. #define INCL_WIN
  2375. #include <os2.h>
  2376. #include <stdio.h>
  2377. #include "memory.h"
  2378. #include "..\..\common\about.h"
  2379.  
  2380. #define WAIT_POINTER  WinSetPointer (HWND_DESKTOP, \
  2381.                   WinQuerySysPointer (HWND_DESKTOP,SPTR_WAIT,FALSE));
  2382. #define ARROW_POINTER WinSetPointer (HWND_DESKTOP, \
  2383.                   WinQuerySysPointer (HWND_DESKTOP,SPTR_ARROW,FALSE));
  2384.  
  2385. /* Exported Functions */
  2386.  
  2387. MRESULT EXPENTRY AllocateDlgProc (HWND,ULONG,MPARAM,MPARAM);
  2388. MRESULT EXPENTRY MainDlgProc (HWND,ULONG,MPARAM,MPARAM);
  2389.  
  2390. /* Local Functions */
  2391.  
  2392. VOID  CenterWindow (HWND);
  2393. VOID  ChangeAccessRights (USHORT);
  2394. VOID  ChangeCommitState (BOOL);
  2395. PSZ   FormatMemListItem (PVOID,LONG,ULONG,ULONG);
  2396. PSZ   FormatPageListItem (PVOID,ULONG);
  2397. VOID  MemError (PSZ);
  2398. ULONG ParseItem (PSZ,ULONG);
  2399. VOID  QueryMemory (SHORT);
  2400.  
  2401. HAB   hab;
  2402. CHAR  szTitle[64];
  2403. char  szListItem[40];
  2404. char  szPageItem[20];
  2405. HWND  hWndFrame;            /* Application Frame window handle */
  2406. HWND  hWndMemList;          /* Memory List box window handle    */
  2407. HWND  hWndPageList;            /* Page List box window handle      */
  2408. BOOL  bCommitted = FALSE;   /* Current settings in list box     */
  2409. BOOL  bShared    = FALSE;
  2410. BOOL  bRead      = TRUE;
  2411. BOOL  bWrite     = TRUE;
  2412. BOOL  bExecute   = TRUE;
  2413. BOOL  bTiled     = FALSE;
  2414.  
  2415. #define FONTNAMELEN 21   /* length + 1 */
  2416. CHAR  szListboxFont[] = "10.System Monospaced";
  2417.  
  2418. /* Undocumented menu message */
  2419. #define MM_QUERYITEMBYPOS      0x01f3
  2420. #define MAKE_16BIT_POINTER(p)  \
  2421.             ((PVOID)MAKEULONG(LOUSHORT(p),(HIUSHORT(p) << 3) | 7))
  2422.  
  2423. int main()
  2424. {
  2425.   HMQ   hmq;
  2426.   QMSG  qmsg;
  2427.  
  2428.   hab = WinInitialize (0);
  2429.   hmq = WinCreateMsgQueue (hab, 0);
  2430.  
  2431.   WinLoadString (hab, 0, ID_APPNAME, sizeof(szTitle), szTitle);
  2432.  
  2433.   hWndFrame = WinLoadDlg (HWND_DESKTOP, HWND_DESKTOP,
  2434.       MainDlgProc, 0, ID_APPNAME, NULL);
  2435.   WinSendMsg (hWndFrame, WM_SETICON,
  2436.       (MPARAM)WinLoadPointer (HWND_DESKTOP, 0, ID_APPNAME), NULL);
  2437.  
  2438.   while (WinGetMsg (hab, &qmsg, 0, 0, 0))
  2439.     WinDispatchMsg (hab, &qmsg);
  2440.  
  2441.   WinDestroyWindow (hWndFrame);
  2442.   WinDestroyMsgQueue (hmq);
  2443.   WinTerminate (hab);
  2444.   return (0);
  2445. }
  2446.  
  2447. VOID AddAboutToSystemMenu(HWND hWndFrame)
  2448. {
  2449.   MENUITEM mi;
  2450.   HWND     hWndSysSubMenu;
  2451.  
  2452.   WinSendMsg (WinWindowFromID (hWndFrame, FID_SYSMENU),
  2453.       MM_QUERYITEMBYPOS, 0L, MAKE_16BIT_POINTER(&mi));
  2454.   hWndSysSubMenu = mi.hwndSubMenu;
  2455.   mi.iPosition   = MIT_END;
  2456.   mi.afStyle     = MIS_SEPARATOR;
  2457.   mi.afAttribute = 0;
  2458.   mi.id          = -1;
  2459.   mi.hwndSubMenu = 0;
  2460.   mi.hItem       = 0;
  2461.   WinSendMsg (hWndSysSubMenu, MM_INSERTITEM, MPFROMP (&mi), NULL);
  2462.   mi.afStyle     = MIS_TEXT;
  2463.   mi.id          = IDM_ABOUT;
  2464.   WinSendMsg (hWndSysSubMenu, MM_INSERTITEM, MPFROMP (&mi),
  2465.       "About...");
  2466.   return;
  2467. }
  2468.  
  2469. VOID CenterWindow (HWND hWnd)
  2470. {
  2471.   ULONG ulScrWidth, ulScrHeight;
  2472.   RECTL Rectl;
  2473.  
  2474.   ulScrWidth  = WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN);
  2475.   ulScrHeight = WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN);
  2476.   WinQueryWindowRect (hWnd,&Rectl);
  2477.   WinSetWindowPos (hWnd, HWND_TOP, (ulScrWidth-Rectl.xRight)/2,
  2478.       (ulScrHeight-Rectl.yTop)/2, 0, 0, SWP_MOVE | SWP_ACTIVATE);
  2479.  return;
  2480. }
  2481.  
  2482. PSZ FormatMemListItem (PVOID pMem, LONG lAllocRequest,
  2483.                        ULONG ulAllocated, ULONG ulCommitted)
  2484. {
  2485.   sprintf (szListItem,"%08lx %8lx %8lx %8lx",
  2486.       (ULONG)pMem, (ULONG)lAllocRequest, ulAllocated, ulCommitted);
  2487.   WinUpper (hab, 0, 0, szListItem);
  2488.   return (szListItem);
  2489. }
  2490.  
  2491. PSZ FormatPageListItem (PVOID pMem, ULONG ulFlags)
  2492. {
  2493.   sprintf (szPageItem, "%08lx       ", pMem);
  2494.   szPageItem[9]  = (CHAR)(ulFlags & PAG_READ    ? 'R' : ' ');
  2495.   szPageItem[10] = (CHAR)(ulFlags & PAG_WRITE   ? 'W' : ' ');
  2496.   szPageItem[11] = (CHAR)(ulFlags & PAG_EXECUTE ? 'E' : ' ');
  2497.   szPageItem[12] = (CHAR)(ulFlags & PAG_COMMIT  ? 'C' : ' ');
  2498.   szPageItem[13] = (CHAR)(ulFlags & PAG_SHARED  ? 'S' : ' ');
  2499.   WinUpper (hab, 0, 0, szPageItem);
  2500.   return (szPageItem);
  2501. }
  2502.  
  2503. VOID MemError (PSZ pszMessage)
  2504. {
  2505.   WinMessageBox (HWND_DESKTOP, hWndFrame, pszMessage,
  2506.       "Memory Allocation", 0, MB_ERROR | MB_OK);
  2507.   return;
  2508. }
  2509.  
  2510. ULONG ParseItem (PSZ szItem, ULONG CurPos)
  2511. {
  2512.   ULONG EndPos = CurPos + 8;
  2513.   ULONG ulMem  = 0;
  2514.   for (; CurPos < EndPos; CurPos++)
  2515.   {
  2516.     if (szItem[CurPos] != ' ')
  2517.       ulMem = ulMem*16 +
  2518.           ((szItem[CurPos] <= '9') ? (szItem[CurPos] - '0') :
  2519.                                      (szItem[CurPos] - 'A' + 10));
  2520.   }
  2521.   return (ulMem);
  2522. }
  2523.  
  2524. VOID ChangeAccessRights (USHORT usRights)
  2525. {
  2526.   ULONG ulAddress;
  2527.   SHORT sSel    = -1;
  2528.   ULONG ulFlags = 0L;
  2529.   BOOL  bError  = FALSE;
  2530.  
  2531.   WAIT_POINTER
  2532.   ulFlags = (ULONG)(usRights & 0x0007);
  2533.   while ((sSel = (SHORT)WinSendMsg (hWndPageList,
  2534.       LM_QUERYSELECTION, MPFROMSHORT(sSel),(MPARAM)NULL)) != LIT_NONE)
  2535.   {
  2536.     WinQueryLboxItemText (hWndPageList, sSel, szPageItem, 20);
  2537.     ulAddress = ParseItem(szPageItem, 0);
  2538.     if (!DosSetMem ((PVOID)ulAddress, 0x1000, ulFlags))
  2539.     {
  2540.       ULONG ulNewFlags;
  2541.       ULONG ulSize = 0x1000;
  2542.       DosQueryMem ((PVOID)ulAddress, &ulSize, &ulNewFlags);
  2543.       WinSetLboxItemText (hWndPageList, sSel,
  2544.           FormatPageListItem ((PVOID)ulAddress, ulNewFlags));
  2545.     }
  2546.     else
  2547.     {
  2548.       char szError[40];
  2549.       if (szPageItem[12] != 'C')
  2550.       {
  2551.         if (!bError)
  2552.           MemError (
  2553.               "Cannot change access rights of decommitted pages");
  2554.         bError = TRUE;
  2555.       }
  2556.       else
  2557.       {
  2558.         sprintf (szError, "Unable to change rights for page %08lx",
  2559.             ulAddress);
  2560.         MemError (szError);
  2561.         break;
  2562.       }
  2563.     }
  2564.   }
  2565.   ARROW_POINTER
  2566.   return;
  2567. }
  2568.  
  2569. VOID ChangeCommitState (BOOL bCommit)
  2570. {
  2571.   ULONG ulAddress;
  2572.   ULONG ulFlags;
  2573.   ULONG ulCommitted;
  2574.   SHORT sSel = -1;
  2575.  
  2576.   WAIT_POINTER
  2577.   ulCommitted = ParseItem(szListItem, 27);
  2578.   while ((sSel = (SHORT)WinSendMsg (hWndPageList,
  2579.       LM_QUERYSELECTION, MPFROMLONG(sSel),(MPARAM)NULL)) != LIT_NONE)
  2580.   {
  2581.     WinQueryLboxItemText (hWndPageList, sSel, szPageItem, 20);
  2582.     ulAddress = ParseItem(szPageItem,0);
  2583.     if (bCommit)
  2584.     {
  2585.       /* If already committed nothing to do */
  2586.       if (szPageItem[12] == 'C')
  2587.         continue;
  2588.       ulFlags = PAG_COMMIT;
  2589.       if (szPageItem[9] == 'R')
  2590.         ulFlags |= PAG_READ;
  2591.       if (szPageItem[10] == 'W')
  2592.         ulFlags |= PAG_WRITE;
  2593.       if (szPageItem[11] == 'E')
  2594.         ulFlags |= PAG_EXECUTE;
  2595.     }
  2596.     else
  2597.     {
  2598.       /* If already decommitted nothing to do */
  2599.       if (szPageItem[12] == ' ')
  2600.         continue;
  2601.       ulFlags = PAG_DECOMMIT;
  2602.     }
  2603.     if (!DosSetMem ((PVOID)ulAddress, 0x1000, ulFlags))
  2604.     {
  2605.       /* Requery the item.  Decommitting causes flags to be reset
  2606.          to default (flags defined when memory was allocated) */
  2607.       ULONG ulSize = 0x1000;
  2608.       DosQueryMem ((PVOID)ulAddress, &ulSize, &ulFlags);
  2609.       WinSetLboxItemText (hWndPageList, sSel,
  2610.           FormatPageListItem ((PVOID)ulAddress, ulFlags));
  2611.       if (bCommit)
  2612.         ulCommitted += 0x1000;
  2613.       else
  2614.         ulCommitted -= 0x1000;
  2615.     }
  2616.     else
  2617.     {
  2618.       char szError[40];
  2619.       sprintf (szError, "Unable to %s page %08lx",
  2620.           bCommit ? "commit" : "decommit", ulAddress);
  2621.       MemError (szError);
  2622.       break;
  2623.     }
  2624.   }
  2625.   sprintf (&szListItem[27], "%8lx", ulCommitted);
  2626.   WinUpper (hab, 0, 0, szListItem);
  2627.   WinSetLboxItemText (hWndMemList,
  2628.       WinQueryLboxSelectedItem(hWndMemList), szListItem);
  2629.   ARROW_POINTER
  2630.   return;
  2631. }
  2632.  
  2633. VOID QueryMemory (SHORT sSel)
  2634. {
  2635.   ULONG ulAddress,
  2636.         ulAllocated,
  2637.         ulCommitted,
  2638.         ulSize,
  2639.         ulFlags;
  2640.   BOOL  bError = FALSE;
  2641.   BOOL  bFirst = TRUE;
  2642.  
  2643.   WAIT_POINTER
  2644.   WinQueryLboxItemText (hWndMemList, sSel, szListItem, 40);
  2645.   WinEnableWindowUpdate (hWndPageList, FALSE);
  2646.   WinSendMsg (hWndPageList, LM_DELETEALL, 0L, 0L);
  2647.  
  2648.   ulAddress   = ParseItem (szListItem, 0);
  2649.   ulCommitted = 0L;
  2650.   ulAllocated = 0L;
  2651.   ulSize      = 0xFFFFFFFF;
  2652.   while (!DosQueryMem ((PVOID)ulAddress, &ulSize, &ulFlags) &&
  2653.          (bFirst || !(ulFlags & (PAG_BASE | PAG_FREE))))
  2654.   {
  2655.     bFirst       = FALSE;
  2656.     ulAllocated += ulSize;
  2657.     if (ulFlags & PAG_COMMIT)
  2658.       ulCommitted += ulSize;
  2659.     while (ulSize)
  2660.     {
  2661.       if (WinInsertLboxItem (hWndPageList, LIT_END,
  2662.               FormatPageListItem ((PVOID)ulAddress, ulFlags)) < 0)
  2663.       {
  2664.         if (!bError)
  2665.             MemError ("Unable to add any more list items");
  2666.         bError = TRUE;
  2667.       }
  2668.       ulAddress += 0x1000;
  2669.       ulSize    -= 0x1000;
  2670.     }
  2671.     ulSize      = 0xFFFFFFFF;
  2672.   }
  2673.   WinEnableWindowUpdate (hWndPageList, TRUE);
  2674.   WinSendMsg (hWndPageList, LM_SELECTITEM, (MPARAM)0L, (MPARAM)TRUE);
  2675.   sprintf (&szListItem[18], "%8lx %8lx", ulAllocated, ulCommitted);
  2676.   WinUpper (hab, 0, 0, szListItem);
  2677.   WinSetLboxItemText (hWndMemList, sSel, szListItem);
  2678.   ARROW_POINTER
  2679.  
  2680.   return;
  2681. }
  2682.  
  2683. MRESULT EXPENTRY AllocateDlgProc (HWND hWnd, ULONG msg,
  2684.                                   MPARAM mp1, MPARAM mp2)
  2685. {
  2686.   LONG lMemAlloc;
  2687.  
  2688.   switch (msg)
  2689.   {
  2690.     case WM_INITDLG:
  2691.       CenterWindow (hWnd);
  2692.       WinCheckButton (hWnd,
  2693.           (bCommitted ? IDB_COMMITTED : IDB_UNCOMMITTED), TRUE);
  2694.       WinCheckButton (hWnd,
  2695.           (bShared    ? IDB_SHARED    : IDB_NONSHARED), TRUE);
  2696.       WinCheckButton (hWnd, IDB_READ,    bRead);
  2697.       WinCheckButton (hWnd, IDB_WRITE,   bWrite);
  2698.       WinCheckButton (hWnd, IDB_EXECUTE, bExecute);
  2699.       WinCheckButton (hWnd, IDB_TILED,   bTiled);
  2700.       WinSendDlgItemMsg (hWnd, IDB_NUMBYTES, SPBM_SETTEXTLIMIT,
  2701.           (MPARAM)7, (MPARAM)0);
  2702.       WinSendDlgItemMsg (hWnd, IDB_NUMBYTES, SPBM_SETLIMITS,
  2703.           (MPARAM)0x00100000,(MPARAM)1L);
  2704.       WinSendDlgItemMsg (hWnd, IDB_NUMBYTES, SPBM_SETCURRENTVALUE,
  2705.           (MPARAM)1,(MPARAM)0L);
  2706.       WinSendDlgItemMsg (hWnd, IDB_REPEAT, SPBM_SETTEXTLIMIT,
  2707.           (MPARAM)4, (MPARAM)0);
  2708.       WinSendDlgItemMsg (hWnd, IDB_REPEAT, SPBM_SETLIMITS,
  2709.           (MPARAM)9999L,(MPARAM)1L);
  2710.       WinSendDlgItemMsg (hWnd, IDB_REPEAT, SPBM_SETCURRENTVALUE,
  2711.           (MPARAM)1,(MPARAM)0L);
  2712.       WinSetFocus (HWND_DESKTOP,
  2713.           WinWindowFromID (hWnd, IDB_NUMBYTES));
  2714.       return ((MRESULT)TRUE);
  2715.  
  2716.     case WM_COMMAND:
  2717.       switch (LOUSHORT(mp1))
  2718.       {
  2719.         case DID_OK:
  2720.           WinSendDlgItemMsg (hWnd, IDB_NUMBYTES, SPBM_QUERYVALUE,
  2721.               (MPARAM)&lMemAlloc, (MPARAM)0L);
  2722.           if (lMemAlloc)
  2723.           {
  2724.             ULONG flags = 0L;
  2725.             BOOL  bOkay;
  2726.             PVOID pMem;
  2727.             ULONG ulRepeat;
  2728.  
  2729.             if (lMemAlloc < 0)
  2730.               lMemAlloc = -lMemAlloc;
  2731.             bCommitted = WinQueryButtonCheckstate (hWnd,
  2732.                              IDB_COMMITTED);
  2733.             bShared    = WinQueryButtonCheckstate (hWnd, IDB_SHARED);
  2734.             bRead      = WinQueryButtonCheckstate (hWnd, IDB_READ);
  2735.             bWrite     = WinQueryButtonCheckstate (hWnd, IDB_WRITE);
  2736.             bExecute   = WinQueryButtonCheckstate (hWnd, IDB_EXECUTE);
  2737.             bTiled     = WinQueryButtonCheckstate (hWnd, IDB_TILED);
  2738.             if (bCommitted)
  2739.               flags |= PAG_COMMIT;
  2740.             if (bShared)
  2741.               flags |= OBJ_GETTABLE | OBJ_GIVEABLE;
  2742.             if (bRead)
  2743.               flags |= PAG_READ;
  2744.             if (bWrite)
  2745.               flags |= PAG_WRITE;
  2746.             if (bExecute)
  2747.               flags |= PAG_EXECUTE;
  2748.             if (bTiled)
  2749.               flags |= OBJ_TILE;
  2750.  
  2751.             WinSendDlgItemMsg (hWnd, IDB_REPEAT, SPBM_QUERYVALUE,
  2752.                 (MPARAM)&ulRepeat, (MPARAM)0L);
  2753.  
  2754.             while (ulRepeat--)
  2755.             {
  2756.               if (!bShared)
  2757.                 bOkay = !DosAllocMem ((PPVOID)&pMem, lMemAlloc,
  2758.                              flags);
  2759.               else
  2760.                 bOkay = !DosAllocSharedMem ((PPVOID)&pMem, NULL,
  2761.                              lMemAlloc, flags);
  2762.               if (bOkay)
  2763.               {
  2764.                 SHORT sSel;
  2765.                 sSel = (SHORT)WinInsertLboxItem (hWndMemList,
  2766.                     LIT_SORTASCENDING,
  2767.                     FormatMemListItem (pMem, lMemAlloc, 0L, 0L));
  2768.                 QueryMemory (sSel);
  2769.                 WinSendMsg (hWndMemList, LM_SELECTITEM,
  2770.                     (MPARAM)sSel, (MPARAM)TRUE);
  2771.               }
  2772.               else
  2773.               {
  2774.                 MemError ("Unable to allocate memory");
  2775.                 break;
  2776.               }
  2777.             }
  2778.           }
  2779.  
  2780.         /* FALL THROUGH */
  2781.  
  2782.         case DID_CANCEL:
  2783.           WinDismissDlg (hWnd, TRUE);
  2784.           return (0);
  2785.       }
  2786.       break;
  2787.   }
  2788.   return (WinDefDlgProc (hWnd, msg, mp1, mp2));
  2789. }
  2790.  
  2791.  
  2792. MRESULT EXPENTRY MainDlgProc (HWND hWnd, ULONG msg,
  2793.                               MPARAM mp1, MPARAM mp2)
  2794. {
  2795.   SHORT   sSel;
  2796.   RECTL   Rectl;
  2797.   BOOL    bHandled       = TRUE;
  2798.   MRESULT mReturn        = 0;
  2799.  
  2800.   static  HWND hMenus[4] = { 0, 0, 0, 0 };
  2801.  
  2802.   switch (msg)
  2803.   {
  2804.     case WM_INITDLG:
  2805.       CenterWindow (hWnd);
  2806.       hWndMemList  = WinWindowFromID (hWnd, IDL_MEMLIST);
  2807.       hWndPageList = WinWindowFromID (hWnd, IDL_PAGELIST);
  2808.  
  2809.       /* Set the system monospaced font for the listboxes */
  2810.       WinSetPresParam (hWndMemList,
  2811.           PP_FONTNAMESIZE, FONTNAMELEN, szListboxFont);
  2812.       WinSetPresParam (hWndPageList,
  2813.           PP_FONTNAMESIZE, FONTNAMELEN, szListboxFont);
  2814.  
  2815.       /* Load the popup menus */
  2816.       hMenus[0] = WinLoadMenu (HWND_OBJECT, 0, FREE_MENU);
  2817.       hMenus[1] = WinLoadMenu (HWND_OBJECT, 0, SELECT_MENU);
  2818.       hMenus[2] = WinLoadMenu (HWND_OBJECT, 0, STATE_MENU);
  2819.       hMenus[3] = WinLoadMenu (HWND_OBJECT, 0, RIGHTS_MENU);
  2820.  
  2821.       /* Add the About menu item to the system menu */
  2822.       AddAboutToSystemMenu (hWnd);
  2823.       break;
  2824.  
  2825.     case WM_CONTROL:
  2826.       switch (LOUSHORT(mp1))
  2827.       {
  2828.         case IDL_MEMLIST:
  2829.           if (HIUSHORT(mp1) == LN_SELECT)
  2830.             QueryMemory ((SHORT)WinQueryLboxSelectedItem((HWND)mp2));
  2831.           break;
  2832.       }
  2833.       break;
  2834.  
  2835.     case WM_COMMAND:
  2836.     case WM_SYSCOMMAND:
  2837.       switch (LOUSHORT(mp1))
  2838.       {
  2839.         case IDB_ALLOCATE:
  2840.           WinDlgBox (HWND_DESKTOP, hWnd, AllocateDlgProc,
  2841.               0, IDD_ALLOCATE, NULL);
  2842.           break;
  2843.  
  2844.         case IDB_SELECT:
  2845.         case IDB_FREE:
  2846.         case IDB_STATE:
  2847.         case IDB_RIGHTS:
  2848.           WinQueryWindowRect (WinWindowFromID(hWnd, LOUSHORT(mp1)),
  2849.               &Rectl);
  2850.           WinMapWindowPoints (WinWindowFromID(hWnd, LOUSHORT(mp1)),
  2851.               hWnd, (PPOINTL)&Rectl, 2);
  2852.           WinPopupMenu (hWnd, hWnd,
  2853.               hMenus[LOUSHORT(mp1) / 100 - 1],
  2854.               Rectl.xLeft, Rectl.yTop,
  2855.               LOUSHORT(mp1) + 1,
  2856.               PU_HCONSTRAIN | PU_VCONSTRAIN | PU_KEYBOARD |
  2857.               PU_MOUSEBUTTON1 | PU_SELECTITEM);
  2858.           break;
  2859.  
  2860.         case IDM_SELECT_NONE:
  2861.           WinSendMsg (hWndPageList, LM_SELECTITEM, (MPARAM)LIT_NONE,
  2862.               0L);
  2863.           break;
  2864.  
  2865.         case IDM_SELECT_ALL:
  2866.           {
  2867.             SHORT sCount;
  2868.             sCount = (SHORT)WinQueryLboxCount (hWndPageList);
  2869.             while (sCount--)
  2870.               WinSendMsg (hWndPageList, LM_SELECTITEM, (MPARAM)sCount,
  2871.                   (MPARAM)TRUE);
  2872.           }
  2873.           break;
  2874.  
  2875.         case IDM_COMMIT_SELECTED:
  2876.         case IDM_DECOMMIT_SELECTED:
  2877.           ChangeCommitState (LOUSHORT(mp1) == IDM_COMMIT_SELECTED);
  2878.           break;
  2879.  
  2880.         case IDM_READ:
  2881.         case IDM_WRITE:
  2882.         case IDM_EXECUTE:
  2883.         case IDM_READWRITE:
  2884.         case IDM_READEXECUTE:
  2885.         case IDM_WRITEEXECUTE:
  2886.         case IDM_READWRITEEXECUTE:
  2887.           ChangeAccessRights (LOUSHORT(mp1));
  2888.           break;
  2889.  
  2890.         case IDM_FREE_SELECTED:
  2891.           if ( (sSel=(SHORT)WinQueryLboxSelectedItem (hWndMemList)) !=
  2892.                   LIT_NONE)
  2893.           {
  2894.             char szMem[9];
  2895.             ULONG ulMem;
  2896.  
  2897.             WinQueryLboxItemText (hWndMemList, sSel, szMem, 9);
  2898.             ulMem = ParseItem (szMem,0);
  2899.             if (!DosFreeMem ((PVOID)ulMem))
  2900.             {
  2901.               WinDeleteLboxItem (hWndMemList, sSel);
  2902.               WinSendMsg (hWndPageList, LM_DELETEALL, 0L, 0L);
  2903.               if (sSel >= (SHORT)WinQueryLboxCount(hWndMemList))
  2904.                 sSel--;
  2905.               WinSendMsg (hWndMemList, LM_SELECTITEM, (MPARAM)sSel,
  2906.                   (MPARAM)TRUE);
  2907.             }
  2908.             else
  2909.               MemError ("Error freeing memory");
  2910.           }
  2911.           break;
  2912.  
  2913.         case IDM_FREE_ALL:
  2914.         {
  2915.           char szMem[9];
  2916.           ULONG ulMem;
  2917.           while (WinQueryLboxItemText (hWndMemList, 0, szMem, 9) > 0)
  2918.           {
  2919.             ulMem = ParseItem (szMem,0);
  2920.             if (!DosFreeMem ((PVOID)ulMem))
  2921.               WinDeleteLboxItem (hWndMemList, 0);
  2922.             else
  2923.             {
  2924.               MemError ("Error freeing memory");
  2925.               break;
  2926.             }
  2927.           }
  2928.           WinSendMsg (hWndPageList, LM_DELETEALL, 0L, 0L);
  2929.           break;
  2930.         }
  2931.  
  2932.         case IDM_ABOUT:
  2933.           DisplayAbout (hWnd, szTitle);
  2934.           break;
  2935.  
  2936.         case SC_CLOSE:
  2937.           WinDestroyWindow (hMenus[0]);
  2938.           WinDestroyWindow (hMenus[1]);
  2939.           WinDestroyWindow (hMenus[2]);
  2940.           WinDestroyWindow (hMenus[3]);
  2941.           WinPostMsg (hWnd, WM_COMMAND, (MPARAM)IDM_FREE_ALL, 0L);
  2942.           WinPostMsg (hWnd, WM_QUIT, 0L, 0L);
  2943.           break;
  2944.  
  2945.         default:
  2946.           bHandled = (msg == WM_COMMAND);
  2947.       }
  2948.       break;
  2949.  
  2950.     default:
  2951.       bHandled = FALSE;
  2952.       break;
  2953.   }
  2954.  
  2955.   if (!bHandled)
  2956.     mReturn = WinDefDlgProc (hWnd, msg, mp1, mp2);
  2957.  
  2958.   return (mReturn);
  2959. }
  2960.  
  2961.  
  2962. ΓòÉΓòÉΓòÉ 8.20. MEMORY.H ΓòÉΓòÉΓòÉ
  2963.  
  2964. /* --------------------------------------------------------------------
  2965.                          Memory Header File
  2966.                               Chapter 9
  2967.                     Real World Programming for OS/2
  2968.              Copyright (c) 1993 Blain, Delimon, and English
  2969. -------------------------------------------------------------------- */
  2970.  
  2971. #define ID_APPNAME              1
  2972. #define IDD_ALLOCATE            2
  2973.  
  2974. #define IDL_MEMLIST            10
  2975. #define IDL_PAGELIST           11
  2976. #define IDB_ALLOCATE           12
  2977. #define IDB_FREE              100
  2978. #define IDB_SELECT            200
  2979. #define IDB_STATE             300
  2980. #define IDB_RIGHTS            400
  2981.  
  2982. #define IDB_NUMBYTES           20
  2983. #define IDB_COMMITTED          21
  2984. #define IDB_UNCOMMITTED        22
  2985. #define IDB_SHARED             23
  2986. #define IDB_NONSHARED          24
  2987. #define IDB_READ               25
  2988. #define IDB_WRITE              26
  2989. #define IDB_EXECUTE            27
  2990. #define IDB_TILED              28
  2991. #define IDB_REPEAT             29
  2992.  
  2993. #define FREE_MENU             100
  2994. #define SELECT_MENU           200
  2995. #define STATE_MENU            300
  2996. #define RIGHTS_MENU           400
  2997.  
  2998. #define IDM_FREE_SELECTED     101
  2999. #define IDM_FREE_ALL          102
  3000. #define IDM_SELECT_ALL        201
  3001. #define IDM_SELECT_NONE       202
  3002. #define IDM_COMMIT_SELECTED   301
  3003. #define IDM_DECOMMIT_SELECTED 302
  3004. #define IDM_READ              401
  3005. #define IDM_WRITE             402
  3006. #define IDM_READWRITE         403
  3007. #define IDM_EXECUTE           404
  3008.  
  3009.  
  3010. ΓòÉΓòÉΓòÉ 8.21. MEMORY.RC ΓòÉΓòÉΓòÉ
  3011.  
  3012. /* --------------------------------------------------------------
  3013.                         Memory Resource File
  3014.                               Chapter 9
  3015.                     Real-World Programming for OS/2 2.1
  3016.              Copyright (c) 1993 Blain, Delimon, and English
  3017. -------------------------------------------------------------- */
  3018.  
  3019. #include <os2.h>
  3020. #include "memory.h"
  3021.  
  3022. ICON ID_APPNAME MEMORY.ICO
  3023.  
  3024. STRINGTABLE LOADONCALL MOVEABLE
  3025. BEGIN
  3026.     ID_APPNAME      "Memory Allocation Program"
  3027. END
  3028.  
  3029. rcinclude memory.dlg
  3030. rcinclude allocate.dlg
  3031. rcinclude ..\..\common\about.dlg
  3032.  
  3033.  
  3034. ΓòÉΓòÉΓòÉ 8.22. ALLOCATE.DLG ΓòÉΓòÉΓòÉ
  3035.  
  3036. /* ------------------------------------------------------------------
  3037.                        Memory Allocation Dialog
  3038.                               Chapter 9
  3039.                     Real-World Programming for OS/2 2.1
  3040.              Copyright (c) 1993 Blain, Delimon, and English
  3041. ------------------------------------------------------------------ */
  3042.  
  3043. DLGTEMPLATE IDD_ALLOCATE LOADONCALL MOVEABLE DISCARDABLE
  3044. BEGIN
  3045.   DIALOG  "Allocate Memory", IDD_ALLOCATE, -5, 53, 264, 72, WS_VISIBLE, FCF_SYSMENU |
  3046.         FCF_TITLEBAR
  3047.   BEGIN
  3048.     LTEXT           "Number of bytes", -1, 3, 58, 72, 8
  3049.     CONTROL         "", IDB_NUMBYTES, 76, 56, 64, 12, WC_SPINBUTTON,
  3050.                     SPBS_NUMERICONLY | SPBS_MASTER |
  3051.                     SPBS_JUSTRIGHT | SPBS_FASTSPIN | WS_TABSTOP
  3052.                     | WS_VISIBLE
  3053.     LTEXT           "Repeat", -1, 144, 58, 36, 8
  3054.     CONTROL         "", IDB_REPEAT,  181, 56, 30, 12, WC_SPINBUTTON,
  3055.                     SPBS_NUMERICONLY | SPBS_MASTER |
  3056.                     SPBS_JUSTRIGHT | SPBS_FASTSPIN | WS_TABSTOP
  3057.                     | WS_VISIBLE
  3058.     GROUPBOX        "Type",          -1, 3, 24, 87, 31
  3059.     AUTORADIOBUTTON "Committed",   IDB_COMMITTED, 9, 37, 58, 10,
  3060.                     WS_TABSTOP
  3061.     AUTORADIOBUTTON "Uncommitted", IDB_UNCOMMITTED, 9, 27, 68, 10,
  3062.                     WS_TABSTOP |
  3063.     GROUPBOX        "Shareability",  -1, 97, 24, 77, 31
  3064.     AUTORADIOBUTTON "Shared",      IDB_SHARED, 101, 37, 44, 10,
  3065.                     WS_TABSTOP
  3066.     AUTORADIOBUTTON "NonShared",   IDB_NONSHARED, 101, 27, 61, 10,
  3067.                     WS_TABSTOP
  3068.     GROUPBOX        "Access Rights", -1, 181, 15, 77, 40
  3069.     AUTOCHECKBOX    "Read",        IDB_READ, 186, 37, 40, 10
  3070.     AUTOCHECKBOX    "Write",       IDB_WRITE, 186, 27, 40, 10
  3071.     AUTOCHECKBOX    "Execute",     IDB_EXECUTE, 186, 17, 46, 10
  3072.     AUTOCHECKBOX    "Tiled",       IDB_TILED, 102, 7, 34, 10, WS_GROUP
  3073.     DEFPUSHBUTTON   "OK",          DID_OK, 4, 4, 40, 14, WS_GROUP
  3074.     PUSHBUTTON      "Cancel",      DID_CANCEL, 47, 4, 40, 14
  3075.   END
  3076. END
  3077.  
  3078.  
  3079. ΓòÉΓòÉΓòÉ 8.23. MEMORY.DLG ΓòÉΓòÉΓòÉ
  3080.  
  3081. /* ----------------------------------------------------------------
  3082.                             Memory Dialog
  3083.                               Chapter 9
  3084.                     Real-World Programming for OS/2 2.1
  3085.              Copyright (c) 1993 Blain, Delimon, and English
  3086. ---------------------------------------------------------------- */
  3087.  
  3088. MENU FREE_MENU PRELOAD
  3089. BEGIN
  3090.   MENUITEM "Free Selected Item", IDM_FREE_SELECTED
  3091.   MENUITEM "Free All Items",     IDM_FREE_ALL
  3092. END
  3093.  
  3094. MENU SELECT_MENU PRELOAD
  3095. BEGIN
  3096.   MENUITEM "Select All",   IDM_SELECT_ALL
  3097.   MENUITEM "Select None",  IDM_SELECT_NONE
  3098. END
  3099.  
  3100. MENU STATE_MENU PRELOAD
  3101. BEGIN
  3102.   MENUITEM "Commit Selected Pages",   IDM_COMMIT_SELECTED
  3103.   MENUITEM "Decommit Selected Pages", IDM_DECOMMIT_SELECTED
  3104. END
  3105.  
  3106. MENU RIGHTS_MENU PRELOAD
  3107. BEGIN
  3108.   MENUITEM "Read",               IDM_READ
  3109.   MENUITEM "Write",              IDM_WRITE
  3110.   MENUITEM "Execute",            IDM_EXECUTE
  3111.   MENUITEM "Read/Write",         IDM_READWRITE
  3112.   MENUITEM "Read/Execute",       IDM_READEXECUTE
  3113.   MENUITEM "Write/Execute",      IDM_WRITEEXECUTE
  3114.   MENUITEM "Read/Write/Execute", IDM_READWRITEEXECUTE
  3115. END
  3116.  
  3117. DLGTEMPLATE ID_APPNAME LOADONCALL MOVEABLE DISCARDABLE
  3118. BEGIN
  3119.   DIALOG  "Memory Allocation", ID_APPNAME, 5, 11, 330, 153,
  3120.           WS_VISIBLE | FS_DLGBORDER,
  3121.           FCF_SYSMENU | FCF_TITLEBAR | FCF_DLGBORDER |
  3122.           FCF_TASKLIST | FCF_ICON;
  3123.   BEGIN
  3124.     LTEXT           "Address",    -1,   9, 137, 37, 8
  3125.     LTEXT           "Requested",  -1,  55, 137, 49, 8
  3126.     LTEXT           "Allocated",  -1, 109, 137, 41, 8
  3127.     LTEXT           "Committed",  -1, 156, 137, 48, 8
  3128.     LTEXT           "Address",    -1, 223, 137, 37, 8
  3129.     LTEXT           "Flags",      -1, 283, 137, 26, 8
  3130.     LISTBOX         IDL_MEMLIST,  5, 22, 208, 114, WS_GROUP
  3131.                     | WS_TABSTOP
  3132.     DEFPUSHBUTTON   "Allocate", IDB_ALLOCATE,   4, 4, 50, 14,
  3133.                     WS_GROUP | WS_TABSTOP
  3134.     PUSHBUTTON      "Free",     IDB_FREE,      57, 4, 50, 14,
  3135.                     WS_TABSTOP
  3136.     LISTBOX         IDL_PAGELIST, 222, 22, 102, 114,
  3137.                     WS_GROUP | WS_TABSTOP | LS_MULTIPLESEL
  3138.                     | LS_EXTENDEDSEL
  3139.     PUSHBUTTON      "Select",   IDB_SELECT,   171, 4, 50, 14,
  3140.                     WS_GROUP | WS_TABSTOP
  3141.     PUSHBUTTON      "State",    IDB_STATE,    224, 4, 50, 14,
  3142.                     WS_TABSTOP
  3143.     PUSHBUTTON      "Rights",   IDB_RIGHTS,   277, 4, 50, 14,
  3144.                     WS_TABSTOP
  3145.   END
  3146. END
  3147.  
  3148.  
  3149. ΓòÉΓòÉΓòÉ 8.24. MEMORY.DEF ΓòÉΓòÉΓòÉ
  3150.  
  3151. NAME          MEMORY   WINDOWAPI
  3152. DESCRIPTION   'Memory Program (c) Blain, Delimon, & English, 1993'
  3153. PROTMODE
  3154. HEAPSIZE      4096
  3155. STACKSIZE     16384
  3156. EXPORTS       MainDlgProc
  3157.               AllocateDlgProc
  3158.  
  3159.  
  3160. ΓòÉΓòÉΓòÉ 8.25. Using the MEMORY Sample Application ΓòÉΓòÉΓòÉ
  3161.  
  3162. The MEMORY application demonstrates committing, freeing, and changing the 
  3163. access rights to blocks of memory. Its use is also fairly explanatory. Remember 
  3164. though that you are making the changes only within a block of memory that is 
  3165. available to the MEMORY application. After starting the memory application, 
  3166. press the allocate button to allocate blocks of memory. The display for the 
  3167. allocated memory will appear similar to that shown in Figure 9.6. 
  3168. Figure 9.6. MEMORY application.
  3169.  
  3170. Practice allocating both committed and uncommitted blocks of memory. Notice 
  3171. what state a particular block of memory must be in before its access rights can 
  3172. be changed. Notice also that the successive addresses for committed blocks of 
  3173. memory that are not shared grow upward. Addresses for successive blocks of 
  3174. shared memory grow downward. This behavior is in keeping with how these blocks 
  3175. of memory are allocated by the system. 
  3176.  
  3177.  
  3178. ΓòÉΓòÉΓòÉ 8.26. Understanding MEMORY's Code ΓòÉΓòÉΓòÉ
  3179.  
  3180. Two macros will be used to set our current pointer. When we begin a 
  3181. time-consuming process, we will set the pointer to the SPTR_WAIT pointer and, 
  3182. when done, reset it to the SPTR_ARROW pointer: 
  3183.  
  3184. #define WAIT_POINTER  WinSetPointer (HWND_DESKTOP, \
  3185.                        WinQuerySysPointer (HWND_DESKTOP,SPTR_WAIT,FALSE));
  3186. #define ARROW_POINTER WinSetPointer (HWND_DESKTOP, \
  3187.                        WinQuerySysPointer (HWND_DESKTOP,SPTR_ARROW,FALSE));
  3188.  
  3189. The CenterWindow function merely centers the dialog in the middle of the 
  3190. screen: 
  3191.  
  3192. VOID CenterWindow (HWND hWnd)
  3193. {
  3194.     ULONG ulScrWidth, ulScrHeight;
  3195.     RECTL Rectl;
  3196.  
  3197.     ulScrWidth  = WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN);
  3198.     ulScrHeight = WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN);
  3199.     WinQueryWindowRect (hWnd,&Rectl);
  3200.     WinSetWindowPos (hWnd, HWND_TOP, (ulScrWidth-Rectl.xRight)/2,
  3201.            (ulScrHeight-Rectl.yTop)/2, 0, 0, SWP_MOVE | SWP_ACTIVATE);
  3202.     return;
  3203. }
  3204.  
  3205. To format our memory list items in the list box, the FormatMemListItem function 
  3206. takes the memory address, amount of memory originally requested, amount of 
  3207. memory actually allocated, and amount of memory currently committed and formats 
  3208. them using the sprintf function: 
  3209.  
  3210. PSZ FormatMemListItem (PVOID pMem, LONG lAllocRequest,
  3211.                        ULONG ulAllocated, ULONG ulCommitted)
  3212. {
  3213.     sprintf (szListItem,"%08lx %8lx %8lx %8lx",
  3214.         (ULONG)pMem, (ULONG)lAllocRequest, ulAllocated, ulCommitted);
  3215.     WinUpper (hab, 0, 0, szListItem);
  3216.     return (szListItem);
  3217. }
  3218.  
  3219. Likewise, the FormatPageListItem function takes the memory address and current 
  3220. page flags and formats them using the sprintf function. The memory page flags 
  3221. are checked individually and set in the string: 
  3222.  
  3223. PSZ FormatPageListItem (PVOID pMem, ULONG ulFlags)
  3224. {
  3225.     sprintf (szPageItem, "%08lx       ", pMem);
  3226.     szPageItem[9]  = (CHAR)(ulFlags & PAG_READ    ? 'R' : ' ');
  3227.     szPageItem[10] = (CHAR)(ulFlags & PAG_WRITE   ? 'W' : ' ');
  3228.     szPageItem[11] = (CHAR)(ulFlags & PAG_EXECUTE ? 'E' : ' ');
  3229.     szPageItem[12] = (CHAR)(ulFlags & PAG_COMMIT  ? 'C' : ' ');
  3230.     szPageItem[13] = (CHAR)(ulFlags & PAG_SHARED  ? 'S' : ' ');
  3231.     WinUpper (hab, 0, 0, szPageItem);
  3232.     return (szPageItem);
  3233. }
  3234. The MemError function is merely a consistent way for us to output our error 
  3235. messages using the WinMessageBox function: 
  3236.  
  3237. VOID MemError (PSZ pszMessage)
  3238. {
  3239.     WinMessageBox (HWND_DESKTOP, hWndFrame, pszMessage,
  3240.         "Memory Allocation", 0, MB_ERROR | MB_OK);
  3241.     return;
  3242. }
  3243.  
  3244. When a list box item is selected, we need to determine what memory address has 
  3245. been selected. Because each list box item is formatted as a string, the 
  3246. ParseItem function can be used to convert any portion of a string from its 
  3247. hexadecimal string to an equivalent binary value. The first parameter szItem is 
  3248. the string to be parsed. The second parameter CurPos is the offset in szItem to 
  3249. start the conversion. The maximum size of our hexadecimal substrings is eight 
  3250. characters, so we look at the eight characters starting at position CurPos: 
  3251.  
  3252. ULONG ParseItem (PSZ szItem, ULONG CurPos)
  3253. {
  3254.     ULONG EndPos = CurPos + 8;
  3255.     ULONG ulMem  = 0;
  3256.     for (; CurPos < EndPos; CurPos++)
  3257.     {
  3258.         if (szItem[CurPos] != ' ')
  3259.             ulMem = ulMem*16 +
  3260.                 ((szItem[CurPos] <= '9') ? (szItem[CurPos] - '0') :
  3261.                                            (szItem[CurPos] - 'A' + 10));
  3262.     }
  3263.     return (ulMem);
  3264. }
  3265.  
  3266. The ChangeAccessRights function is used to set the access rights of the 
  3267. selected memory pages. The only parameter to this function is the new access 
  3268. rights to be set. Our menu items have conveniently been defined such that the 
  3269. low byte of their identifier is the new access rights, so we can just AND this 
  3270. identifier with 0x0007 to get the new access rights. We then loop, querying the 
  3271. next selected item in the memory page list until there are no more selected. 
  3272. Querying the text for each item, we call ParseItem to retrieve the memory 
  3273. address for the selected page. The call to DosSetMem will attempt to set the 
  3274. access rights of the page. Because we can change the access rights only for a 
  3275. committed page, the DosSetMem call will fail if the page is not committed. If 
  3276. the DosSetMem call is successful, we query the access rights of the page and 
  3277. reformat the item to be updated in the list box. It is necessary to query the 
  3278. memory again because decommitting a page will reset the access rights to those 
  3279. defined when the memory was allocated. 
  3280.  
  3281. The ChangeCommitState function is used either to commit or decommit the 
  3282. selected memory pages. The only parameter is a flag indicating if the memory is 
  3283. to be committed or decommitted. Because the list box text for the memory list 
  3284. box has already been retrieved in QueryMemory, we can just call ParseItem on 
  3285. szListItem to get the current amount of committed memory for the selected item. 
  3286. This enables us to update the amount of committed memory as we make the 
  3287. updates. 
  3288.  
  3289. We then loop, querying the next selected item in the memory page list until 
  3290. there are no more selected. Querying the text for each item, we call ParseItem 
  3291. to retrieve the memory address for the selected page. Because we want to leave 
  3292. the access rights unchanged for the page, if we are committing memory, we must 
  3293. set the access rights to their current settings. We can either call DosQueryMem 
  3294. to get them or look at the cutrent flags in the list box string. The call to 
  3295. DosSetMem will attempt to commit or decommit the page. If the call to DosSetMem 
  3296. is successful, we query the memory to get its new flags. When a page is 
  3297. decommitted, its access rights are reset to those defined when the memory was 
  3298. allocated. We then update the amount of committed memory. When all selected 
  3299. pages have been processed, we must update the amount of committed memory in the 
  3300. memory list box. 
  3301.  
  3302. The QueryMemory function is used to retrieve the current flags for each page of 
  3303. memory for each allocated memory object. The input to this function is the 
  3304. index in the list box of the selected memory object. We begin by querying the 
  3305. text for the selected item and deleting all the items in the page list box. The 
  3306. call to WinEnableWindowUpdate tells PM not to repaint the list box as we are 
  3307. making our updates. This prevents the window from repainting every time we add 
  3308. a new item. When we are done, we will reenable the painting of the list box. 
  3309.  
  3310. The call to ParseItem converts the address portion of the string, so we have 
  3311. the base address for the memory object. We then repeatedly make calls to 
  3312. DosQueryMem to query the memory flags. Remember, if the address queried is the 
  3313. first page of a memory object, the PAG_BASE flag is set. If the page is not 
  3314. currently allocated, the PAG_FREE flag is set. Also, the DosQueryMem call will 
  3315. query pages until it finds a page with a different memory flag than the first 
  3316. page queried or it finds the first page of the next allocated memory object. 
  3317. Our loop will, thus, repeat until we either reach the end of the currently 
  3318. allocated object (PAG_FREE) or we reach the beginning of the next allocated 
  3319. memory object (PAG_BASE). We want to ignore the check for PAG_BASE on the first 
  3320. page because it will have the PAG_BASE flag set. 
  3321.  
  3322. Each call to DosQueryMem will start at the address in ulAddress and return the 
  3323. size of the memory pages that have the same flags as the first page at 
  3324. ulAddress. The ulFlags variable will contain those flags. Our total allocated 
  3325. count can be incremented by ulSize, and ulCommitted is incremented if the 
  3326. PAG_COMMIT flag is set. We then add a page entry to the pages list box for each 
  3327. page in the queried memory. When the memory object has been completely queried, 
  3328. we reenable the list box updates and select the first item in the list box. We 
  3329. also update the allocated and committed totals in the memory list box. 
  3330.  
  3331. AllocateDlgProc is the dialog function for the memory allocation dialog. When 
  3332. we receive the WM_INITDLG message, we can initialize all the controls in the 
  3333. dialog window. Because we save the last settings of each button from the last 
  3334. time the dialog was displayed, we use those values to either check or uncheck 
  3335. the buttons. Our spinners are initialized for their size, limits, and current 
  3336. value. Our dialog enables you to specify the amount of memory to allocate and 
  3337. its access rights, whether to commit the memory when it is allocated, whether 
  3338. it is private or shared memory, and whether it should be allocated out of the 
  3339. tiled arena. We also have the ability to repeat the memory request up to 9,999 
  3340. times. When the WM_COMMAND message is received with the OK button pressed, we 
  3341. query the values input and current state of the buttons. Then, for each memory 
  3342. allocation request (the repeat count), we make the call to either DosAllocMem 
  3343. (private memory allocation) or DosAllocSharedMem (shared memory allocation). If 
  3344. the allocation is successful, we add an entry to the memory list box and call 
  3345. QueryMemory to fill the pages list box. When all memory requests have been 
  3346. made, we exit the dialog. 
  3347.  
  3348. MainDlgProc is the dialog function for the main dialog of this program. When we 
  3349. receive the WM_INITDLG message, we query the handles and set the font for our 
  3350. two list boxes. We set the font to a monospaced font so that the columns in the 
  3351. list box align properly. The four different pop-up menus are also loaded at 
  3352. this time. If we receive a WM_CONTROL message from the memory list box and an 
  3353. item has been selected, we call QueryMemory to update the pages list box with 
  3354. the pages for the selected memory object. We receive a WM_COMMAND message for 
  3355. each button pressed in the dialog. If the command is IDB_ALLOCATE, we display 
  3356. the memory allocation dialog. If the command is IDB_SELECT, IDB_FREE, 
  3357. IDB_STATE, or IDB_RIGHTS, we display the pop-up menu directly above the button. 
  3358. The identifiers for the buttons and menus are the same. If IDM_SELECT_NONE is 
  3359. selected, we send the LM_SELECTITEM message to the pages list box with LIT_NONE 
  3360. specified so that no items are selected. If IDM_SELECT_ALL is selected, we send 
  3361. the LM_SELECTITEM message to the pages list box for each item in the list box. 
  3362. If one of the commit options is selected, we call ChangeCommitState. If one of 
  3363. the access rights options is selected, we call ChangeAccessRights. If 
  3364. IDM_FREE_SELECTED is selected, we call DosFreeMem on the selected memory object 
  3365. and remove it from the list box. After deleting the item, we select a new item. 
  3366. If IDM_FREE_ALL is selected, we call DosFreeMem on each item in the list box 
  3367. and remove it from the list box.