home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / CNRDTL.ZIP / CNRDTLA.TXT < prev   
Text File  |  1992-10-17  |  50KB  |  1,303 lines

  1. Column Name: Advanced PM Programming
  2. Column Title: Introducing Containers
  3.  
  4. by: Guy Scharf
  5. (c) Copyright 1992 Software Architects, Inc.
  6.  
  7.  
  8. Introducing Containers
  9.  
  10. OS/2 2.0 introduces four new controls-slider, value set,
  11. notebook, and container.  This month we will take a first
  12. look at containers.
  13.  
  14. First, what is a container?  You have seen containers-lots
  15. of them. The container control is one of the key
  16. components of the Workplace Shell.  A container displays
  17. to the user the items, or objects, in contains in a visual
  18. way.  Virtually everything you see on the OS/2 desktop
  19. before starting a program or opening a settings view is a
  20. container.
  21.  
  22. If you open the drives folder, select a drive, and open it,
  23. you will see a container showing directories on the drive,
  24. arranged hierarchially.  This representation is called a tree
  25. view.  Select Open from the system menu again, press the
  26. right arrow button, and you can open Settings, Icon view,
  27. Tree view, and Details view.  These three views are all
  28. different ways a container can display the directories and
  29. files on a drive.
  30.  
  31. The container control supports five views of its contents:
  32.  
  33. Icon View     Icons or bitmaps with strings beneath. 
  34.               The Workplace Shell desktop normally
  35.               displays objects this way.
  36.  
  37. Name View     Icons or bitmaps with text to the right.
  38.  
  39. Text View     Text strings without any pictorial
  40.               representation.
  41.  
  42. Tree View     Icons or bitmaps with text to the right
  43.               and with a way to display a hierarchy
  44.               (often indicated by + and - signs).
  45.  
  46. Details View  Icons or bitmaps, text strings, numbers,
  47.               times, and/or dates.
  48.  
  49. Container windows support direct manipulation-the user
  50. can select items with the mouse and drag them around. 
  51. The user can drag items and drop them onto other
  52. containers, applications, or windows.
  53.  
  54. It is the container control that gives OS/2 2.0 and the
  55. Workplace Shell much of its flavor.
  56.  
  57. A container may change the way in which its contents are
  58. displayed by changing the view.  In the Workplace Shell,
  59. different views are typically seen by opening windows with
  60. that alternate view.  It is possible to change the view within
  61. a single window.  Only one view can be displayed in one
  62. container window at a time.
  63.  
  64.  
  65. A Step at a Time
  66.  
  67. As you might imagine, a control that performs all of these
  68. functions and many more and shows data in all of these
  69. views is complex.  The documentation is daunting.  The
  70. CUA Library/2 manual has 34 pages describing the
  71. container control and how it works and 74 pages of
  72. programming reference material.  The documentation for
  73. the container control is larger than that for any of the other
  74. new controls.
  75.  
  76. Here, we will cut the problem down to a simpler case-we
  77. will use the details view of a container to build a multi-
  78. column listbox with scrolling, container and column titles,
  79. and other bells and whistles.  Programmers frequently need
  80. multi-column listboxes for applications.  While you can use
  81. the owner-draw feature of the listbox control to do that, the
  82. container with its details view is easier and more powerful.
  83.  
  84. Figure 1 shows a dialog with a container details view that
  85. is displayed by the sample program.  Look at some of its
  86. features that you could not easily achieve in a list box:
  87.  
  88. o                                                         The container has a two-line, centered heading that
  89.                                                           does not scroll.  This heading is part of the
  90.                                                           container itself; it is not static text outside of the
  91.                                                           container.  A horizontal line is placed beneath the
  92.                                                           heading.
  93.  
  94. o                                                         The columns have headings too.  Some of the
  95.                                                           headings are left justified, some are right justified. 
  96.                                                           These headings also have a horizontal separator
  97.                                                           line beneath them.
  98.  
  99. o                                                         The container has a vertical scroll bar.  The scroll
  100.                                                           bar does not extend to the headings, indicating that
  101.                                                           the headings stay fixed as you scroll the container
  102.                                                           vertically.
  103.  
  104. o      The container has a vertical double line between
  105.        the first and second columns.  Grab the line with
  106.        the mouse and you can drag it left and right.  This
  107.        is called a split bar.  The split bar separates the
  108.        container into two pieces, each of which is
  109.        individually scrolled horizontally.  You can adjust
  110.        the split of the window into two pieces by
  111.        dragging the split bar.
  112.  
  113.        If you scroll the container horizontally, the column
  114.        headings scroll too.
  115.  
  116. o      The data in the columns is formatted.  Text strings
  117.        are left-justified; numeric values and dates have
  118.        correct punctuation as specified by the system
  119.        settings and are right-justified.
  120.  
  121. This looks complex, but is all pretty easy to do.  Let's first
  122. look at the basics of programming a container.
  123.  
  124.  
  125. Container Basics
  126.  
  127. The basic steps for programming a container are the same
  128. as for other controls you are familiar with.  You must
  129. create the container, load it with data, possibly monitor or
  130. modify its operation, possibly retrieve data from the
  131. container, and shut the container down when you are done
  132. with it.  However, the container control requires more
  133. complex setup than older controls.
  134.  
  135.  
  136. Creating a Container
  137.  
  138. As with other control, you create a container by placing a
  139. CONTROL statement in a resource script. 
  140. WC_CONTAINER is the window class name
  141. (CCL_CONTAINER if you are using CUA Library/2). 
  142. You can also create a container programmatically using
  143. WinCreateWindow.
  144.  
  145. In the sample program, the container is in a dialog box.  In
  146. the Workplace Shell drive folders, the containers occupy
  147. the entire window.  That difference is a design choice.  For
  148. the sample program, I wanted the appearance of a list box
  149. in a dialog.
  150.  
  151. The container control supports a small set of style flags. 
  152. We look here only at those that apply to the details view.
  153.  
  154. CCS_READONLY makes the entire container read-only. 
  155. If you don't make the container read-only, the user can
  156. modify the container title and container records.  If you
  157. want to modify some data, but not all, you would omit this
  158. style and later mark container titles, records, column titles,
  159. or column contents that are not to be changed as read-only.
  160.  
  161. CCS_SINGLESEL specifies that only one container item
  162. can be selected at a time.  CCS_MULTIPLESEL allows the
  163. user to select zero or more items.  Both of these are similar
  164. to listbox styles.  The container control also has the
  165. CCS_EXTENDSEL style, which allows the user to select
  166. one or more container items.
  167.  
  168. CCS_MINIRECORDCORE specifies that a smaller record
  169. structure is to be used for this container.  Records are a
  170. key concept of containers.  We examine them in the next
  171. section.
  172.  
  173. Notice that the type of view was not specified as a style,
  174. and other information is not yet known either.  You must
  175. initialize the container programmatically using the
  176. CM_SETCNRINFO message.  We'll look at that later.
  177.  
  178.  
  179. Understanding Container Items and Records
  180.  
  181. A container item is anything the user or programmer might
  182. store in a container.  The container is really a very general-
  183. purpose object, and can hold many different types of items. 
  184. Car, truck, bicycle, and unicycle objects could all be stored
  185. in the same container.
  186.  
  187. Programmatically, the data for each item in the container
  188. is stored in a record.  The container control manages the
  189. records.  The programmer asks the control to allocate
  190. memory for the records, fills in the fields of the record,
  191. and tells the container to insert the records in the container. 
  192. When the container window is closed, the container frees
  193. the memory for the records.
  194.  
  195. All records of a container must have the same structure. 
  196. There are two issues in determining the record format:
  197.  
  198. o                                                         Whether the full-sized record format
  199.                                                           (RECORDCORE) or a small record format
  200.                                                           (MINIRECORDCORE) should be used.
  201.  
  202. o                                                         How much additional space should be included in
  203.                                                           each record for programmer-maintained data.
  204.  
  205. The basic record structure (RECORDCORE or
  206. MINIRECORDCORE) has control information used by the
  207. container to maintain the records.
  208.  
  209. The MINIRECORDCORE structure contains only the
  210. minimum information necessary for a container item: a
  211. pointer to a text string, a handle to an icon, a chain pointer
  212. to the next record, the position of the icon in an icon view,
  213. and some attribute flags.
  214.  
  215. The larger RECORDCORE structure contains the above
  216. information plus more.  RECORDCORE supports different
  217. text strings for text, name, and tree views. 
  218. RECORDCORE is the default data structure.  If you wish
  219. to use MINIRECORDCORE, you must specify the
  220. CCS_MINIRECORDCORE style when creating the
  221. container.  
  222.  
  223. The information in these data structures is sufficient to
  224. control the basic operation of a container, but is usually not
  225. sufficient for an application.  Also, many of the items in
  226. the structure are pointers to strings.  Where are the strings
  227. stored?  If the strings are in memory the programmer has
  228. allocated, then that memory must remain allocated for the
  229. life of the record.  That may not be convenient.
  230.  
  231. The container control allows you to append any information
  232. to the basic record structure.  When you ask the container
  233. to allocate memory, you tell it how many extra bytes you
  234. want allocated in each record.  The usual way to program
  235. this is to declare a C struct.  The first element of the struct
  236. will be RECORDCORE or MINIRECORDCORE.  The
  237. following elements are your data fields.  For example:
  238.  
  239.        typedef struct
  240.        {
  241.               MINIRECORDCORE       RecordCore;
  242.               ULONG                ulMyNumber;
  243.               CHAR                 szMyString[10];
  244.               CDATE                cdate;
  245.        } USERRECORD, *PUSERRECORD;
  246.  
  247. You ask the container to allocate memory for one or more
  248. records by sending a CM_ALLOCRECORD message.  To
  249. be more efficient, allocate many records at the same time.
  250.  
  251. Now, complete the record contents.  Assign values to
  252. elements in both the base record structure and the extra
  253. bytes that follow the base structure.
  254.  
  255. After completing the records, you insert them into the
  256. container by completing a RECORDINSERT structure and
  257. sending the address of it and the first record allocated to
  258. the container with a CM_INSERTRECORD message.
  259.  
  260. When the container terminates, it will free the memory it
  261. allocated for you.  However, if you used malloc() to obtain
  262. any additional space while filling in the records, the
  263. container cannot release that space, since it does not know
  264. about it.  Instead, you will need to examine the records,
  265. perhaps while processing the WM_DESTROY message to
  266. the dialog, and free any additional space you allocated.
  267.  
  268. You may remove or insert additional records in the
  269. container at any time.
  270.  
  271.  
  272. Container Columns
  273.  
  274. The details view shows several columns of information.  As
  275. you might expect, these columns require additional control
  276. information so that the container can manage the columns.
  277.  
  278. In a way similar to managing records, you ask the
  279. container to allocate column control structures with the
  280. CM_ALLOCDETAILFIELDINFO message.  You then
  281. complete the FIELDINFO data structures with information
  282. about each column.  Finally, you construct a
  283. FIELDINFOINSERT structure and insert the column
  284. information with a CM_INSERTDETAILFIELDINFO
  285. message.
  286.  
  287. As with records, you can remove or insert additional
  288. columns at will.
  289.  
  290. Unlike container records, the container does not allow you
  291. to add extra bytes to the column control data.  Instead, the
  292. FIELDINFO structure contains a pUserData field that you
  293. can use to hold a pointer to your information.
  294.  
  295.  
  296. Example Program
  297.  
  298. The example program constructs a details view container
  299. that lists the  states of the Union, their capital cities, their
  300. population according to the 1980 census, and the dates they
  301. were admitted.  The container can be scrolled vertically and
  302. horizontally.  A split bar allows the user to adjust the
  303. amount of space in which the state name is displayed.
  304.  
  305.  
  306. The Resource Script
  307.  
  308. Let's look first at the CNRDTL.RC file.  As usual, all
  309. strings that the user might see are placed in a
  310. STRINGTABLE.  No user-visible text is allowed in the
  311. program code.  All of the strings are container or column
  312. headings.  The \012 in the strings is a new-line character,
  313. forcing that heading to be displayed in two lines.
  314.  
  315. The dialog template contains a CONTROL statement for a
  316. window of WC_CONTAINER class.  The user may select
  317. only one item at a time (CCS_SINGLESEL) and cannot
  318. modify any data (CCS_READONLY).  The program uses
  319. the minimal record structure (CCS_MINIRECORDCORE).
  320.  
  321. A PRESPARAMS statement follows to set the font within
  322. the container to 8 point Helvetica.  A \0 is included at the
  323. end of the font name string.  This is required to make
  324. PRESPARAMS work with OS/2.0.  This extra null is not
  325. required with OS/2 1.3.
  326.  
  327. The container control itself has no margin surrounding it. 
  328. This makes it especially easy to use when the entire client
  329. area of a window is occupied by a container.  We used the
  330. GROUPBOX statement to place a margin around the
  331. container for appearance's sake.  This GROUPBOX
  332. statement should follow the CONTROL statement for the
  333. container itself.
  334.  
  335.  
  336. Main Program
  337.  
  338. First, we define sample state data.  Each record has the
  339. state and capital names, population, and date admitted.
  340.  
  341. Next we define the container record structure, RECORD. 
  342. The first element of this structure must be
  343. MINIRECORDCORE (or RECORDCORE if desired).  We
  344. then add three fields that represent the columns to be
  345. displayed: a pointer to the capital name, population of the
  346. state, and the date admitted.  We'll examine the data types
  347. and the following COLDESC data in the next module.
  348.  
  349. The main program simply runs the example dialog and
  350. terminates; it is of little interest itself.
  351.  
  352. Finally, we come to the dialog procedure,
  353. ExampleDlgProc().  The dialog procedure for this program
  354. is extremely simple.  In WM_INITDLG,
  355. CnCreateDetailsView() defines the columns of the details
  356. view and InitContainer() loads the state data into the
  357. container.  In WM_COMMAND, we dismiss the dialog
  358. when a button is pushed.  In WM_DESTROY,
  359. CnDestroyDetailsView() frees memory allocated for the
  360. container.
  361.  
  362.  
  363. Creating the Details View
  364.  
  365. CnCreateDetailsView() is a utility function in CNFUNC.C
  366. to initialize the details view of a container, based on control
  367. structures passed to it.  This function requires the number
  368. of columns, a pointer to the column control structure, the
  369. column the split bar is to follow, the position of the split
  370. bar as a percentage of the container width, the
  371. STRINGTABLE id of the container heading, and a handle
  372. to the resource module containing the STRINGTABLE.
  373.  
  374. The column information is the COLDESC data in
  375. CNRDTL.C.  The COLDESC data contains an offset to the
  376. data within the record, column attribute flags, a
  377. STRINGTABLE id for the column heading, an optional
  378. width for the column, and an NULL pointer used within
  379. CnCreateDetailsView().
  380.  
  381. The first thing CnCreateDetailsView does is go through the
  382. table of column descriptions, load the column titles from
  383. the resource file, and place pointers to the title text in the
  384. pszTitle field of the structure.
  385.  
  386. Next we initialize the container itself.  We clear the
  387. CNRINFO structure on the stack and set the structure size
  388. in cb.  We set the container attributes field in
  389. cnrinfo.flWindowAttr to CV_DETAIL (details view),
  390. CA_DETAILSVIEWTITLES (we want column titles),
  391. CA_CONTAINERTITLE (we want a title area for the
  392. container itself), and CA_TITLESEPARATOR (we want a
  393. horizontal line under the container title).
  394.  
  395. Then we load the container title from the resource file and
  396. place a pointer to it in cnrinfo.pszCnrTitle.  The title
  397. contains a newline character (\012), which causes the title
  398. to appear as two lines.
  399.  
  400. The CNRINFO structure contains a great many fields. 
  401. When we send the CM_SETCNRINFO structure to the
  402. container, we must tell it what parts of the CNRINFO
  403. structure should be examined.  We tell it this with CMA_*
  404. flags OR'ed together in mp2.  In this case, we say
  405. CMA_FLWINDOWATTR (set window attributes) and
  406. CMA_CNRTITLE (set the title text).  Those are the only
  407. two fields in CNRINFO that we filled in.  If we had
  408. completed other fields, we would have needed to specify
  409. other CMA_* values to ask the container to pay attention
  410. to those fields.
  411.  
  412. Now that we have established the container, we can define
  413. the columns.  First, we use the
  414. CM_ALLOCDETAILFIELDINFO message to ask the
  415. container to allocate the column control structures for the
  416. number of columns we need.  The container returns to us
  417. a pointer to the first FIELDINFO structure.  The other
  418. structures have been allocated and chained to this structure. 
  419. The structures have been initialized as zero except for the
  420. structure length and chain fields.
  421.  
  422. We now loop through the COLDESC array, filling in one
  423. FIELDINFO structure for each COLDESC entry.
  424.  
  425. We copy the field offset and the attributes from
  426. COLDESC.  These attributes are key to the operation of
  427. the column.  You must specify the type of field this is. 
  428. Details view supports CFA_ULONG (offset is to a
  429. ULONG), CFA_DATE (offset is to a CDATE structure),
  430. CFA_TIME (offset is to a CTIME structure),
  431. CFA_BITMAPORICON (offset is to an HPOINTER), or
  432. CFA_STRING (offset is to a PSZ, not to a CHAR array as
  433. the name might suggest).  We can specify the justification
  434. of the data (CFA_LEFT, CFA_RIGHT, CFA_CENTER),
  435. vertical positioning of data in the row (DT_VCENTER,
  436. DT_TOP, DT_BOTTOM), and visual attributes
  437. (CFA_HORZSEPARATOR for a separator below column
  438. headings, CFA_SEPARATOR for a vertical separator to
  439. right of column, CFA_INVISIBLE, CFA_FIREADONLY
  440. for a read-only field, CFA_OWNERDRAW).
  441.  
  442. We don't use any bitmaps or time values in this sample. 
  443. The CDATE and CTIME structures are sets of three
  444. ULONG values.  The container will format them according
  445. to the current system preference settings.
  446.  
  447. We copy the title attribute and mark the title read-only. 
  448. We use CFA_LEFT and CFA_RIGHT on columns to left
  449. or right justify the column headings.  Since the container
  450. has the CCS_READONLY style,
  451. CFA_FITITLEREADONLY does not add anything.  We
  452. have no user data and set the column width to 0.  With a
  453. 0 width, the container will determine the width of the
  454. columns based on the data to be displayed.  We could have
  455. set a width of our own choice if we wished to.
  456.  
  457. Setting the split bar requires modifying the container setup
  458. information.  It is not part of the FIELDINFO information
  459. as such.  We need to set a pointer to the last FIELDINFO
  460. that is left of the splitbar, and specify the position of the
  461. splitbar.  To determine the position, we get the dimensions
  462. of the container window and calculate the percent of that
  463. width that was passed as a parameter.  We set the
  464. calculated x position and the pointer to the last
  465. FIELDINFO in the CNRINFO structure.  Finally, we send
  466. a CM_SETCNRINFO message to the container, specifying
  467. which fields we have set (CMA_XVERTSPLITBAR for the
  468. location, and CMA_PFIELDINFOLAST for the last
  469. column to the left of the split bar).
  470.  
  471. Having completed all FIELDINFO structures, we construct
  472. a FIELDINFOINSERT structure, tell it how many
  473. structures we want to insert, and insert the fields by
  474. sending CM_INSERTDETAILFIELDINFO.
  475.  
  476.  
  477. Loading the Container
  478.  
  479. Now we are ready to load the container using
  480. InitContainer() in CNRDTL.C.  First, we ask the container
  481. to create the records.  The number of extra bytes is the
  482. difference between our RECORD size and the system's
  483. MINIRECORDCORESIZE.  The container allocates the
  484. requested records, initializing them to zero except for the
  485. size and chain fields.
  486.  
  487. All we need to do is to run the chain and our array of state
  488. data, copying information into the RECORD structure.  We
  489. used the pszIcon field, which is the name of the item, as a
  490. pointer to the state name.  We used the pszCapital name we
  491. created for the capital city.  We could have used our own
  492. pointers for both.  We could also have added CHAR fields
  493. for these names in the RECORD structure and copied the
  494. actual strings in.  However, if we had done that, we would
  495. still have had to have PSZ values, as the CFA_STRING
  496. must specify the offset of a PSZ, not the beginning of a
  497. string.
  498.  
  499. Next we create a RECORDINSERT structure, give it the
  500. number of records, tell it where to insert these records, and
  501. insert the records with a CM_INSERTRECORD message.
  502.  
  503. We're done.  The container is now up and running.  Since
  504. this is a read-only display container, we don't have to do
  505. anything until the user terminates the dialog.
  506.  
  507.  
  508. Shutting Down
  509.  
  510. While initializing the container and details view, we
  511. allocated memory with malloc.  When the container closes,
  512. we need to free that memory to prevent a memory leak. 
  513. Upon receipt of WM_DESTROY, the dialog calls
  514. CnDestroyDetailsView().  Here we free the strings loaded
  515. from the resource file.  We read the CNRINFO data and
  516. free the container title text that we allocated.  Next we free
  517. the column data and all records.
  518.  
  519. In this example, freeing the column data and records is not
  520. required, as the container will free that memory. 
  521. However, if we had been doing something else, such as
  522. switching from a details view to a tree view, we might have
  523. wanted to free the column data before the container
  524. terminated.
  525.  
  526.  
  527. Summary
  528.  
  529. There you have it-a multi-column listbox with titles,
  530. column headings, vertical splits, and nice formatting. 
  531. Later, we can add many more features-direct manipulation
  532. (drag/drop), direct editing of column data, and more.
  533.  
  534. The programs in this article are available on the OS2DEV
  535. forum on CompuServe.  GO OS2DEV and download file
  536. CNRDTL.ZIP from library 4, Ver 2.0.
  537.  
  538. ------------------------
  539.  
  540. Guy Scharf is president of Software Architects, Inc., 2163
  541. Jardin Drive, Mountain View, CA 94040.  Software
  542. Architects, Inc. specializes in OS/2 Presentation Manager
  543. software development and consulting.  Guy can be reached
  544. on the CompuServe OS2DEV forum or on CompuServe
  545. Mail at 76702,557 or through Internet at
  546. 76702.557@compuserve.com.
  547.  
  548. LISTING 1.  CNRDTL.C
  549. ====================
  550.  
  551. // cnrdtl.c -- Sample program to demonstrate container detail
  552.  
  553. //--------------------------------------------------------------
  554. //  cnrdtl.c
  555. //
  556. //      Sample program to demonstrate container detail view
  557. //
  558. //  By: Guy Scharf                      (415) 948-9186
  559. //      Software Architects, Inc.       FAX: (415) 948-1620
  560. //      2163 Jardin Drive               
  561. //      Mountain View, CA   94040       
  562. //      CompuServe: 76702,557
  563. //      Internet: 76702.557@compuserve.com
  564. //  (c) Copyright 1992 Software Architects, Inc.  
  565. //
  566. //      All Rights Reserved.
  567. //
  568. //  Software Architects, Inc. develops software products for 
  569. //  independent software vendors using OS/2 and Presentation 
  570. //  Manager.
  571. //--------------------------------------------------------------
  572.  
  573. #define INCL_PM                         // Basic OS/2 PM
  574. #define INCL_BASE                       // components
  575. #include <OS2.H>
  576.  
  577. #include <stdlib.h>                     // C runtime library
  578. #include <stddef.h>
  579. #include <string.h>
  580.  
  581. #include "cnrdtl.h"                     // Container demo defs
  582. #include "cnfunc.h"                     // Container utilities
  583.  
  584.  
  585. //  Sample data
  586.  
  587. typedef struct
  588. {
  589.     SHORT   mm, dd, yy;                 // General date storage
  590. } OURDATE, *POURDATE;
  591.  
  592. typedef struct
  593. {
  594.     PSZ     pszState;                   // Name of state
  595.     PSZ     pszCapital;                 // Name of city
  596.     ULONG   ulPopulation;               // '80 census population
  597.     OURDATE ourdateAdm;                 // Date admitted
  598. }  STATEREC, *PSTATEREC;
  599.  
  600. STATEREC statedata[] =
  601. {
  602.     {"Alabama",     "Montgomery",   3893888, {12, 14, 1819}},
  603.     {"Alaska",      "Juneau",        401851, { 1,  3, 1959}},
  604.     {"Arizona",     "Phoenix",      2718425, { 2,  4, 1912}},
  605.     {"Arkansas",    "Little Rock",  2286435, { 6, 15, 1836}},
  606.     {"California",  "Sacramento",  23667565, { 9,  9, 1850}},
  607.     {"Colorado",    "Denver",       2889735, { 8,  1, 1876}},
  608.     {"Connecticut", "Hartford",     3107576, { 1,  9, 1788}},
  609.     {"Delaware",    "Dover",         594317, {12,  7, 1787}},
  610.     {"Florida",     "Tallahassee",  9746342, { 3,  3, 1845}},
  611.     {"Georgia",     "Atlanta",      5463105, { 1,  2, 1788}},
  612.     {"Hawaii",      "Honolulu",      964691, { 8, 21, 1959}}
  613. };
  614.  
  615. typedef struct                          // Container data record
  616. {
  617.     MINIRECORDCORE  RecordCore;         // MINIRECORDCORE structure
  618.     PSZ         pszCapital;             // Capital city
  619.     ULONG       ulPopulation;           // Population
  620.     CDATE       cdateAdmitted;          // Date admitted
  621. } RECORD, *PRECORD;
  622.  
  623. COLDESC cdState[] =
  624. {
  625.   {offsetof(RECORD, RecordCore.pszIcon), CFA_STRING | CFA_FIREADONLY |
  626.      CFA_HORZSEPARATOR | CFA_LEFT, IDS_HEAD_STATE, 
  627.      CFA_LEFT, 0, NULL},
  628.   {offsetof(RECORD, pszCapital), CFA_STRING | CFA_FIREADONLY |
  629.      CFA_HORZSEPARATOR | CFA_LEFT, IDS_HEAD_CAP, 
  630.      CFA_LEFT, 0, NULL},
  631.   {offsetof(RECORD, ulPopulation), CFA_ULONG | CFA_FIREADONLY | 
  632.      CFA_HORZSEPARATOR | CFA_RIGHT, IDS_HEAD_POP, 
  633.      CFA_RIGHT, 0, NULL},
  634.   {offsetof(RECORD, cdateAdmitted), CFA_DATE | CFA_FIREADONLY | 
  635.      CFA_HORZSEPARATOR | CFA_RIGHT, IDS_HEAD_ADM, 
  636.      CFA_RIGHT, 0, NULL}
  637. };
  638.  
  639. //  Prototypes of procedures
  640.  
  641. static MRESULT EXPENTRY ExampleDlgProc (HWND, MSGID, MPARAM,
  642.                                         MPARAM);
  643.                                         
  644. static MRESULT InitContainer (          // Initialize slider
  645. HWND    hwndDlg,                        // I - Dialog window
  646. USHORT  idContainer,                    // I - Container id
  647. USHORT  cStates,                        // I - Number of states
  648. PSTATEREC pastate);                     // I - State data array
  649.  
  650. //--------------------------------------------------------------
  651. //                                                                          
  652. //  Main program to drive container example
  653. //                                                                          
  654. //--------------------------------------------------------------
  655.  
  656. int main (void)
  657. {
  658.     HAB     hab;                        // Handle to anchor blk
  659.     HMQ     hmqMsgQueue;                // Handle to msg queue
  660. #ifndef OS220
  661.     HMODULE hmodContainer;              // Handle to cntr module
  662. #endif
  663.  
  664.     hab = WinInitialize (0);            // Initialize PM
  665.  
  666.     hmqMsgQueue = WinCreateMsgQueue (hab, 0);// Create msg queue
  667.  
  668. #ifndef OS220
  669.     if (DosLoadModule (NULL, 0, CCL_CONTAINER_DLL, 
  670.                        &hmodContainer))
  671.         return FALSE;
  672. #endif
  673.  
  674.     WinDlgBox (HWND_DESKTOP, HWND_DESKTOP, ExampleDlgProc, 0,
  675.                IDLG_EXAMPLE, NULL);
  676.  
  677. #ifndef OS220
  678.     DosFreeModule (hmodContainer);
  679. #endif
  680.  
  681.     WinDestroyMsgQueue (hmqMsgQueue);   // Shutdown
  682.     WinTerminate       (hab);
  683.     return 0;
  684. }
  685.  
  686. //--------------------------------------------------------------
  687. //                                                                          
  688. //  ExampleDlgProc() -- Show state info
  689. //                                                                          
  690. //--------------------------------------------------------------
  691.  
  692. static MRESULT EXPENTRY ExampleDlgProc (
  693. HWND    hwndDlg,
  694. MSGID   msg,
  695. MPARAM  mp1,
  696. MPARAM  mp2)
  697. {
  698.     switch(msg)
  699.     {
  700.         //------------------------------------------------------
  701.         //  Initialize dialog by defining the details view
  702.         //  in the container, loading records, etc.
  703.         //------------------------------------------------------
  704.         case WM_INITDLG:
  705.  
  706.             CnCreateDetailsView (WinWindowFromID (hwndDlg, 
  707.                                                 IDCN_STATEINFO),
  708.                               sizeof cdState / sizeof (COLDESC),
  709.                               cdState, 
  710.                               0,
  711.                               33,
  712.                               IDS_TITLE,
  713.                               0);
  714.                                                                
  715.             //--------------------------------------------------
  716.             //  Load the container
  717.             //--------------------------------------------------
  718.             InitContainer (hwndDlg, IDCN_STATEINFO,
  719.                            sizeof statedata / sizeof (STATEREC),
  720.                            statedata);
  721.             return 0;
  722.  
  723.         //------------------------------------------------------
  724.         //  Process pushbuttons.  They both just quit dialog.
  725.         //------------------------------------------------------
  726.         case WM_COMMAND:
  727.             switch (SHORT1FROMMP(mp1))
  728.             {
  729.                                         // Cancel pressed
  730.                                         // Dismiss dialog
  731.                 case DID_CANCEL:
  732.                     WinDismissDlg (hwndDlg, FALSE);
  733.                     return 0;
  734.  
  735.                                         // OK button pressed
  736.                 case DID_OK:            // We're done
  737.                     WinDismissDlg (hwndDlg, TRUE);
  738.                     return 0;
  739.             }
  740.             return 0;
  741.         
  742.         //------------------------------------------------------
  743.         //  Recover memory allocated for the container
  744.         //------------------------------------------------------
  745.         case WM_DESTROY:
  746.             CnDestroyDetailsView (WinWindowFromID (hwndDlg, 
  747.                                                 IDCN_STATEINFO),
  748.                               sizeof cdState / sizeof (COLDESC),
  749.                               cdState);
  750.             return 0;
  751.                                    
  752.         //------------------------------------------------------
  753.         //  All other messages go to default window procedure
  754.         //------------------------------------------------------
  755.         default:
  756.             return (WinDefDlgProc (hwndDlg, msg, mp1, mp2));
  757.     }
  758.     return FALSE;
  759. }
  760.  
  761.  
  762.  
  763. //--------------------------------------------------------------
  764. // Function: InitContainer
  765. // Outputs:  none                                               
  766. //                                                              
  767. // This function loads the container with all of the state data.
  768. // See the article for a complete discussion of this function.
  769. //--------------------------------------------------------------
  770.  
  771. static MRESULT InitContainer (          // Initialize slider
  772. HWND    hwndDlg,                        // I - Dialog window
  773. USHORT  idContainer,                    // I - Container id
  774. USHORT  cStates,                        // I - Number of states
  775. PSTATEREC pastate)                      // I - State data array
  776. {
  777.     USHORT      i;                      // Loop counter
  778.     ULONG       cbExtraBytes;           // Extra bytes in record structure */
  779.  
  780.     PRECORD     precord;                // -> container records
  781.     PRECORD     precordFirst;           // -> first container record
  782.  
  783.     RECORDINSERT recordInsert;          // Record insertion control
  784.  
  785.     //----------------------------------------------------------
  786.     //  Allocate memory for all user records
  787.     //----------------------------------------------------------
  788.  
  789.     cbExtraBytes = (ULONG)(sizeof(RECORD) - 
  790.                                          sizeof(MINIRECORDCORE));
  791.     precord = (PRECORD) WinSendDlgItemMsg (hwndDlg, idContainer,
  792.                                   CM_ALLOCRECORD,
  793.                                   MPFROMLONG (cbExtraBytes),
  794.                                   MPFROMSHORT (cStates));
  795.     precordFirst = precord;
  796.                                       
  797.     //----------------------------------------------------------
  798.     //  Initialize all records
  799.     //----------------------------------------------------------
  800.  
  801.     for (i = 0; i < cStates; i++, pastate++)
  802.     {
  803.         //------------------------------------------------------
  804.         //   Initialize the container record control structure
  805.         //------------------------------------------------------
  806.         precord->RecordCore.cb        = sizeof (MINIRECORDCORE);
  807.  
  808.         //------------------------------------------------------
  809.         //  Copy our data to the container record control struct
  810.         //------------------------------------------------------
  811.         precord->RecordCore.pszIcon  = pastate->pszState;
  812.         precord->pszCapital          = pastate->pszCapital;
  813.         precord->ulPopulation        = pastate->ulPopulation;
  814.         precord->cdateAdmitted.month = pastate->ourdateAdm.mm;
  815.         precord->cdateAdmitted.day   = pastate->ourdateAdm.dd;
  816.         precord->cdateAdmitted.year  = pastate->ourdateAdm.yy;
  817.  
  818.                                         // Move to next record
  819.         precord = (PRECORD) precord->RecordCore.preccNextRecord;
  820.     }
  821.  
  822.     //----------------------------------------------------------
  823.     //  Construct record insertion control structure
  824.     //----------------------------------------------------------
  825.  
  826.     memset (&recordInsert, 0, sizeof (RECORDINSERT));
  827.     recordInsert.cb                 = sizeof (RECORDINSERT);
  828.     recordInsert.pRecordParent      = NULL;
  829.     recordInsert.pRecordOrder       = (PRECORDCORE)((ULONG)
  830.                                           MPFROMSHORT(CMA_END));
  831.     recordInsert.zOrder             = (USHORT) CMA_TOP;
  832.     recordInsert.cRecordsInsert     = cStates;
  833.     recordInsert.fInvalidateRecord  = TRUE;
  834.  
  835.     //----------------------------------------------------------
  836.     //  Insert the records
  837.     //----------------------------------------------------------
  838.  
  839.     WinSendDlgItemMsg (hwndDlg, idContainer,
  840.                        CM_INSERTRECORD,
  841.                        MPFROMP (precordFirst),
  842.                        MPFROMP (&recordInsert));
  843.  
  844.     //----------------------------------------------------------
  845.     //  Return to caller
  846.     //----------------------------------------------------------
  847.  
  848.     return 0;
  849. }
  850.  
  851.  
  852.  
  853.  
  854. LISTING 2.  CNFUNC.C
  855. ====================
  856.  
  857. // cnfunc.c -- Container utility functions
  858.  
  859. //--------------------------------------------------------------
  860. //
  861. //  cnfunc.c
  862. //
  863. //      Container utility functions
  864. //
  865. //--------------------------------------------------------------
  866.  
  867. #define INCL_WIN
  868. #include <os2.h>
  869.  
  870. #include <stdlib.h>
  871. #include <string.h>
  872.  
  873. #include "cnfunc.h"
  874.  
  875.  
  876. #define MAXMSGSIZE  255                 // Max size of string
  877.  
  878.  
  879. //--------------------------------------------------------------
  880. //  UtilLoadString - load a string from the resource file
  881. //--------------------------------------------------------------
  882.  
  883. PSZ UtilLoadString (            // Load string from res
  884. USHORT  usStringID,             // I - String identifier
  885. HAB     hab,                    // I - Current HAB
  886. HMODULE hmod)                   // I - Resource module or NULL
  887. {
  888.     PSZ     pszBuf;             // String buffer
  889.  
  890.     pszBuf = malloc (MAXMSGSIZE);
  891.     if (WinLoadString (hab, hmod, usStringID, MAXMSGSIZE, 
  892.                        pszBuf) == 0)
  893.     {
  894.         free (pszBuf);
  895.         return (NULL);
  896.     }
  897.  
  898.     return (pszBuf);            // Return -> string
  899. }
  900.  
  901.  
  902. //--------------------------------------------------------------
  903. //
  904. //  CnCreateDetailsView
  905. //
  906. //      Create the details view of the container.  This requires
  907. //      setting up the column information.
  908. //
  909. //--------------------------------------------------------------
  910.  
  911. USHORT CnCreateDetailsView (            // Create details view
  912. HWND    hwndContainer,                  // I - container window
  913. USHORT  cColumns,                       // I - Number of colums
  914. COLDESC acd[],                          // IO->column descriptor
  915. SHORT   sLastLeftColumn,                // I - Last column in 
  916.                                         // left split window
  917.                                         //     -1 means no split
  918. LONG    lPctSplitBarPos,                // Percent of cntr width 
  919.                                         // to set split bar
  920. USHORT  idTitle,                        // I - container hdg id
  921. HMODULE hmod)                           // I -hmod for resources
  922. {
  923.     USHORT      i;                      // Loop counter
  924.  
  925.     CNRINFO     cnrinfo;                // Cntr info structure
  926.     PFIELDINFO  pFieldInfoHead;         // --> First field
  927.     PFIELDINFO  pFieldInfo;             // --> Current field
  928.     FIELDINFOINSERT FieldInsertInfo;
  929.  
  930.     PCOLDESC    pcd;                    // Column descriptor
  931.  
  932.     //----------------------------------------------------------
  933.     //  Get container text information
  934.     //----------------------------------------------------------
  935.  
  936.     for (pcd = acd, i = 0; i < cColumns; i++, pcd++)
  937.     {
  938.         if (pcd->pszTitle == NULL)
  939.             pcd->pszTitle = UtilLoadString (pcd->idTitle,
  940.                             WinQueryAnchorBlock (hwndContainer),
  941.                                             hmod);
  942.     }
  943.  
  944.  
  945.     //----------------------------------------------------------
  946.     //  Initialize the container for a simple details view
  947.     //----------------------------------------------------------
  948.  
  949.     memset (&cnrinfo, 0, sizeof(CNRINFO));
  950.     cnrinfo.cb = sizeof (CNRINFO);
  951.     
  952.     // Set for Details View, with column titles, with icons and
  953.     // not bitmaps, include a container title, with a separator
  954.     // bar underneath it, and don't let the user change title
  955.     cnrinfo.flWindowAttr = CV_DETAIL            |
  956.                            CA_DETAILSVIEWTITLES |
  957.                            CA_CONTAINERTITLE    |
  958.                            CA_TITLESEPARATOR;
  959.                            
  960.     cnrinfo.pszCnrTitle = UtilLoadString (idTitle,
  961.                             WinQueryAnchorBlock (hwndContainer),
  962.                             hmod);
  963.  
  964.     WinSendMsg (hwndContainer, CM_SETCNRINFO,
  965.                 MPFROMP (&cnrinfo),
  966.                 MPFROMLONG (CMA_FLWINDOWATTR | CMA_CNRTITLE));
  967.     
  968.  
  969.     //----------------------------------------------------------
  970.     //  Get memory for the column information
  971.     //----------------------------------------------------------
  972.  
  973.     pFieldInfoHead = (PFIELDINFO) PVOIDFROMMR (
  974.                             WinSendMsg (hwndContainer,
  975.                                         CM_ALLOCDETAILFIELDINFO,
  976.                                         MPFROMSHORT (cColumns),
  977.                                         0));
  978.  
  979.     pFieldInfo = pFieldInfoHead;        // Start at top of list
  980.  
  981.  
  982.     //----------------------------------------------------------
  983.     //  Load the field info structures
  984.     //----------------------------------------------------------
  985.  
  986.     for (pcd = acd, i = 0; i < cColumns; i++, pcd++)
  987.     {
  988.         pFieldInfo->cb          = sizeof (FIELDINFO);
  989.         pFieldInfo->flData      = pcd->flAttributes;
  990.         pFieldInfo->flTitle     = pcd->flTitle; 
  991.         pFieldInfo->pTitleData  = pcd->pszTitle;
  992.         pFieldInfo->offStruct   = pcd->offField;
  993.         pFieldInfo->pUserData   = NULL;
  994.         pFieldInfo->cxWidth     = pcd->cxWidth;
  995.  
  996.         if (sLastLeftColumn >= 0)
  997.         {
  998.             if (sLastLeftColumn == i)
  999.             {
  1000.                 SWP     swp;
  1001.                 WinQueryWindowPos (hwndContainer, &swp);
  1002.                 cnrinfo.pFieldInfoLast = pFieldInfo;
  1003.                 cnrinfo.xVertSplitbar  = 
  1004.                                (swp.cx * lPctSplitBarPos) / 100;
  1005.                 WinSendMsg (hwndContainer, CM_SETCNRINFO,
  1006.                             MPFROMP (&cnrinfo),
  1007.                             MPFROMLONG (CMA_PFIELDINFOLAST | 
  1008.                                         CMA_XVERTSPLITBAR));
  1009.             }
  1010.         }
  1011.         pFieldInfo = pFieldInfo->pNextFieldInfo;
  1012.     };
  1013.  
  1014.  
  1015.     //----------------------------------------------------------
  1016.     //  Construct the FIELDINFOINSERT structure that describes
  1017.     //  the number of fields to be inserted, where they are to 
  1018.     //  be inserted, etc.
  1019.     //----------------------------------------------------------
  1020.  
  1021.     memset (&FieldInsertInfo, 0, sizeof(FIELDINFOINSERT));
  1022.     FieldInsertInfo.cb               = sizeof (FIELDINFOINSERT);
  1023.     FieldInsertInfo.pFieldInfoOrder  = (PFIELDINFO) CMA_END;
  1024.     FieldInsertInfo.cFieldInfoInsert = cColumns;
  1025.     FieldInsertInfo.fInvalidateFieldInfo = TRUE;
  1026.  
  1027.  
  1028.     //----------------------------------------------------------
  1029.     //  Insert the fields.
  1030.     //----------------------------------------------------------
  1031.  
  1032.     WinSendMsg (hwndContainer, CM_INSERTDETAILFIELDINFO,
  1033.                 MPFROMP (pFieldInfoHead),
  1034.                 MPFROMP (&FieldInsertInfo));
  1035.     return 0;
  1036.  
  1037. }
  1038.  
  1039.  
  1040.  
  1041. //--------------------------------------------------------------
  1042. //
  1043. //  CnDestroyDetailsView
  1044. //
  1045. //      Destroy the details view of the container.  This
  1046. //      requires freeing column information.
  1047. //
  1048. //--------------------------------------------------------------
  1049.  
  1050. USHORT CnDestroyDetailsView (   // Destroy details view
  1051. HWND    hwndContainer,          // I - Handle to cntr window
  1052. USHORT  cColumns,               // I - Number of colums
  1053. COLDESC acd[])                  // IO--> column descriptor
  1054. {
  1055.     USHORT      i;              // Loop counter
  1056.     PCOLDESC    pcd;            // Column descriptor entry
  1057.     CNRINFO     cnrinfo;        // Container info structure
  1058.  
  1059.  
  1060.     //----------------------------------------------------------
  1061.     //  Remove any column titles loaded into memory
  1062.     //----------------------------------------------------------
  1063.     
  1064.     for (pcd = acd, i = 0; i < cColumns; i++, pcd++)
  1065.     {
  1066.         if (    (pcd->pszTitle != NULL)
  1067.              && (pcd->idTitle != 0) )
  1068.         {
  1069.             free (pcd->pszTitle);
  1070.             pcd->pszTitle = NULL;
  1071.         }
  1072.     }
  1073.  
  1074.     
  1075.     //----------------------------------------------------------
  1076.     //  Remove the column heading from memory
  1077.     //----------------------------------------------------------
  1078.  
  1079.     WinSendMsg (hwndContainer,
  1080.                 CM_QUERYCNRINFO,
  1081.                 MPFROMP(&cnrinfo),
  1082.                 MPFROMSHORT (sizeof(CNRINFO)));
  1083.                 
  1084.     free (cnrinfo.pszCnrTitle);
  1085.     
  1086.                 
  1087.     //----------------------------------------------------------
  1088.     //  Remove the column information of the container
  1089.     //----------------------------------------------------------
  1090.  
  1091.     WinSendMsg (hwndContainer,
  1092.                 CM_REMOVEDETAILFIELDINFO,
  1093.                 0,
  1094.                 MPFROM2SHORT (0, CMA_FREE));
  1095.  
  1096.  
  1097.     //----------------------------------------------------------
  1098.     //  Remove any records in the container
  1099.     //----------------------------------------------------------
  1100.  
  1101.     WinSendMsg (hwndContainer,
  1102.                 CM_REMOVERECORD,
  1103.                 0,
  1104.                 MPFROM2SHORT (0, CMA_FREE));
  1105.  
  1106.     return 0;
  1107. }
  1108.  
  1109.  
  1110.  
  1111. LISTING 3.  CNRDTL.H
  1112. ====================
  1113.  
  1114. // cnrdtl.h -- Definitions for cnrdtl demo
  1115.  
  1116. //--------------------------------------------------------------
  1117. //  Change the following as required for target system
  1118. //--------------------------------------------------------------
  1119. #define OS220                           // Define target system
  1120. //#define OS213                         // OS/2 1.3 + CUA Lib/2
  1121.  
  1122. #ifdef OS220
  1123.     #define MSGID   ULONG               // OS/2 2.0
  1124. #else
  1125.     #define MSGID   USHORT              // OS/2 1.3
  1126.     #include <fclcnrp.h>                // CUA Library/2
  1127.     #define WC_CONTAINER CCL_CONTAINER  // Window class
  1128. #endif                               
  1129.  
  1130. //  Defines for dialogs, controls
  1131. #define IDLG_EXAMPLE        100
  1132. #define IDCN_STATEINFO      200
  1133. #define IDS_HEAD_STATE      500
  1134. #define IDS_HEAD_CAP        501
  1135. #define IDS_HEAD_POP        502
  1136. #define IDS_HEAD_ADM        503
  1137. #define IDS_TITLE           504
  1138.  
  1139.  
  1140.  
  1141.  
  1142. LISTING 4.  CNFUNC.H
  1143. ====================
  1144.  
  1145. // cnfunc.h -- Container utility functions
  1146.  
  1147. //--------------------------------------------------------------
  1148. //
  1149. //  cnfunc.h
  1150. //
  1151. //      Container Functions
  1152. //
  1153. //--------------------------------------------------------------
  1154.  
  1155. //--------------------------------------------------------------
  1156. //  Data structure used to describe field information
  1157. //--------------------------------------------------------------
  1158.  
  1159. typedef struct                  // Field (column) descriptors
  1160. {
  1161.     ULONG   offField;           // Offset of field in record
  1162.     ULONG   flAttributes;       // Field attributes
  1163.     USHORT  idTitle;            // Identifier of column title
  1164.     ULONG   flTitle;            // Title Attributes
  1165.     USHORT  cxWidth;            // Column width (0 = auto calc)
  1166.     PSZ     pszTitle;           // Pointer to column title text
  1167. } COLDESC, *PCOLDESC;
  1168.  
  1169.  
  1170. //--------------------------------------------------------------
  1171. //  Function prototypes
  1172. //--------------------------------------------------------------
  1173.  
  1174. USHORT CnCreateDetailsView (    // Create details view
  1175. HWND    hwndContainer,          // I - Handle to container window
  1176. USHORT  cColumns,               // I - Number of colums
  1177. COLDESC acd[],                  // IO--> column descriptor
  1178. SHORT   sLastLeftColumn,        // I - Last column in left split
  1179. LONG    lPctSplitBarPos,        // Percent of container width 
  1180. USHORT  idTitle,                // I - container heading id
  1181. HMODULE hmod);                  // I - handle to resource file
  1182.  
  1183. USHORT CnDestroyDetailsView (   // Destroy details view
  1184. HWND    hwndContainer,          // I - Handle to container window
  1185. USHORT  cColumns,               // I - Number of colums
  1186. COLDESC acd[]);                 // IO--> column descriptor
  1187.  
  1188.  
  1189.  
  1190. LISTING 5.  CNRDTL.RC
  1191. =====================
  1192.  
  1193. #include <os2.h>                        // OS/2 definitions
  1194. #include "cnrdtl.h"                     // Application defs
  1195.  
  1196. STRINGTABLE
  1197. BEGIN
  1198.   IDS_HEAD_STATE, "\012State"
  1199.   IDS_HEAD_CAP,   "\012Capital"
  1200.   IDS_HEAD_POP,   "Population\012(1980 Census)"
  1201.   IDS_HEAD_ADM,   "Entered\012Union"
  1202.   IDS_TITLE,      "State Information Table\012(1987 Almanac)"
  1203. END
  1204.  
  1205. DLGTEMPLATE IDLG_EXAMPLE LOADONCALL MOVEABLE DISCARDABLE
  1206. BEGIN
  1207.   DIALOG  "State Information", IDLG_EXAMPLE, 40, 27, 200, 150, 
  1208.           WS_VISIBLE, FCF_SYSMENU | FCF_TITLEBAR
  1209.   BEGIN
  1210.     CONTROL    "",   IDCN_STATEINFO,
  1211.                      20,  31, 160, 110, WC_CONTAINER,
  1212.                      CCS_SINGLESEL | CCS_READONLY |
  1213.                      CCS_MINIRECORDCORE | 
  1214.                      WS_GROUP | WS_TABSTOP | WS_VISIBLE
  1215.                PRESPARAMS PP_FONTNAMESIZE,"8.Helv\0"
  1216.                
  1217.     GROUPBOX   "", 300, 19, 30, 162, 116
  1218.     
  1219.  DEFPUSHBUTTON "OK",     DID_OK,     15, 9, 48, 13, WS_GROUP
  1220.     PUSHBUTTON "Cancel", DID_CANCEL, 78, 9, 48, 13,
  1221.                NOT WS_TABSTOP
  1222.   END
  1223. END
  1224.  
  1225.  
  1226.  
  1227. LISTING 6.  CNRDTL.MAK
  1228. ======================
  1229.  
  1230. # Make File Creation run in directory:
  1231. #   D:\P\MAGAZINE\CNRDTL;
  1232.  
  1233. .SUFFIXES:
  1234.  
  1235. .SUFFIXES: .c .rc
  1236.  
  1237. ALL: CNRDTL.EXE \
  1238.      CNRDTL.RES
  1239.  
  1240. cnrdtl.exe:  \
  1241.   CNFUNC.OBJ \
  1242.   CNRDTL.OBJ \
  1243.   CNRDTL.RES \
  1244.   CNRDTL.MAK
  1245.    @REM @<<CNRDTL.@0
  1246.      /CO /M /NOL /PM:PM +
  1247.      CNFUNC.OBJ +
  1248.      CNRDTL.OBJ
  1249.      cnrdtl.exe
  1250.      
  1251.      
  1252.      ;
  1253. <<
  1254.    LINK386.EXE @CNRDTL.@0
  1255.    RC CNRDTL.RES cnrdtl.exe
  1256.  
  1257. {.}.rc.res:
  1258.    RC -r .\$*.RC
  1259.  
  1260. {.}.c.obj:
  1261.    ICC.EXE /Ss /Kbger /Ti /W2 /C .\$*.c
  1262.  
  1263. !include CNRDTL.DEP
  1264.  
  1265.  
  1266.  
  1267. LISTING 7.  CNRDTL.DEP
  1268. ======================
  1269.  
  1270.  
  1271. # Make File Creation run in directory:
  1272. #   D:\P\MAGAZINE\CNRDTL;
  1273.  
  1274. # Assumed INCLUDE environment variable path:
  1275. #   C:\TOOLKT20\C\OS2H;
  1276. #   C:\TOOLKT20\ASM\OS2INC;
  1277. #   C:\IBMC\INCLUDE;
  1278. #   E:\GPF\INCLUDE;
  1279.  
  1280.  
  1281. CNRDTL.RES:  CNRDTL.RC  \
  1282. #  {.;$(INCLUDE)}OS2.H  \
  1283.    {.;$(INCLUDE)}CNRDTL.H  \
  1284. #    {.;$(INCLUDE)}FCLCNRP.H  \
  1285.    CNRDTL.MAK
  1286.  
  1287. CNFUNC.OBJ:  CNFUNC.C  \
  1288. #  {$(INCLUDE);}os2.h  \
  1289. #  {$(INCLUDE);}stdlib.h  \
  1290. #  {$(INCLUDE);}string.h  \
  1291.    {.;$(INCLUDE);}cnfunc.h  \
  1292.    CNRDTL.MAK
  1293.  
  1294. CNRDTL.OBJ:  CNRDTL.C  \
  1295. #  {$(INCLUDE);}os2.h  \
  1296. #  {$(INCLUDE);}stdlib.h  \
  1297. #  {$(INCLUDE);}stddef.h  \
  1298. #  {$(INCLUDE);}string.h  \
  1299.    {.;$(INCLUDE);}cnrdtl.h  \
  1300. #    {$(INCLUDE);}fclcnrp.h  \
  1301.    {.;$(INCLUDE);}cnfunc.h  \
  1302.    CNRDTL.MAK
  1303.