home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR24 / EDMI5.ZIP / EDMI1-5.INF (.txt) < prev    next >
OS/2 Help File  |  1993-10-06  |  136KB  |  3,632 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Title Page ΓòÉΓòÉΓòÉ
  3.  
  4.            Welcome to EDM/2 - The Electronic OS/2 Developers Magazine!
  5.            Portions copyright (c) by Steve Luzynski, Larry Salomon Jr.
  6.                                 Volume 1, issue 5
  7.  
  8. Select this to go to the next section 
  9.  
  10.  
  11. ΓòÉΓòÉΓòÉ 2. Copyright Notice (and other Legal Stuff) ΓòÉΓòÉΓòÉ
  12.  
  13. The editors of this electronic magazine are Steve Luzynski and Larry Salomon, 
  14. Jr. 
  15.  
  16. Portions of EDM/2 are copyrighted by the editors.  This publication may be 
  17. freely distributed in electronic form provided that all parts are present in 
  18. their original unmodified form.  A reasonable fee may be charged for the 
  19. physical act of distribution; no fee may be charged for the publication itself. 
  20.  
  21. All articles are copyrighted by their authors. No part of any article may be 
  22. reproduced without permission from the original author. 
  23.  
  24. Neither this publication nor the editors are affiliated with International 
  25. Business Machines Corporation. 
  26.  
  27. OS/2 is a registered trademark of International Business Machines Corporation. 
  28. Other trademarks are property of their respective owners.  Any mention of a 
  29. product in this publication does not constitute an endorsement or affiliation 
  30. unless specifically stated in the text. 
  31.  
  32. Select this to go to the next section 
  33.  
  34.  
  35. ΓòÉΓòÉΓòÉ 3. From the Editors ΓòÉΓòÉΓòÉ
  36.  
  37. After a rather bumpy release of volume 1, issue 4, we have high hopes that 
  38. things will go a bit smoother in the future.  Things that are on the board, so 
  39. to speak, are: 
  40.  
  41. Subscription service 
  42.  
  43. For the Internet-reachable community, we thought that it wouldn't be too 
  44. difficult to write an auto-mailer, especially since the Unix mail program will 
  45. accept everything necessary on the command line. Add a list of people to mail 
  46. to, bake for 30 minutes, and voila! 
  47.  
  48. Unfortunately, things were not that easy; after a first attempt, a SunOS limit 
  49. on the number of processes was reached since mail spawns a copy of sendmail and 
  50. then exits.  Tweeking the process somewhat (pun intended) yielded a 
  51. subscription mailer script that builds the mail header with all of the 
  52. addresses in it and calls sendmail once for each part of the file. 
  53.  
  54. Having verified it with a small file, we have decided to test it for the first 
  55. time with this issue, so we are asking that you please check the (alphabetical) 
  56. list to see if your userid is on it.  If it is and you did not receive the 
  57. magazine automagically, please send us email as soon as possible.  Assuming all 
  58. goes well, an article will be posted to comp.os.os2.programmer.misc describing 
  59. the subscription process, so be patient.  Of course, the magazine will still be 
  60. placed on the nets as before, but adding this service will allow us to keep a 
  61. more accurate size of our reader base as well as allow us to reach other 
  62. networks (like MCIMail) and BBS's with Internet mail links. 
  63.  
  64. New look (somewhat) 
  65.  
  66. Beauty is in the eyes of the beholder, so we've made a few changes to the 
  67. magazine format.  Firstly, the Questions and Answers column is being revamped, 
  68. starting with a name change.  It will now be known as the Scratch Patch and 
  69. will contain not only Questions and Answers, but also the following items: 
  70.  
  71. o Snippet(s) of the Month 
  72.  
  73.   This is for those useful, modular, functions that have been written and found 
  74.   indispensable by their authors.  All submissions are requested (though not 
  75.   required) to be one function whenever possible and thoroughly commented, 
  76.   including a prologue which explains the purpose and the parameters. 
  77.  
  78. o Documentation Chop Shop 
  79.  
  80.   This is for documentation-related submissions dealing with inaccuracies, 
  81.   inconsistencies, and vaguries.  All potential submitters should remember that 
  82.   the goal here is to correct and clarify whenever possible; so, while pointing 
  83.   out the "tar pit" is something to write about, how to grab the vine swinging 
  84.   overhead is much more helpful. 
  85.  
  86. o Want Ads 
  87.  
  88.   As in the past, we always look forward to your comments.  Of particular 
  89.   interest are the requests for specific topics.  Since we do not pretend to 
  90.   know everyone on the Internet, any topics that look appetizing or that have 
  91.   received a number of requests will be noted in this section in hopes that 
  92.   someone reading it will be masochistic enough to want to write an article on 
  93.   one of them.  Don't forget to read the Article Submission Guidelines!!! 
  94.  
  95. Any submissions should be received by the editors by no later than the 25th of 
  96. the month.  And as always, even though it seems redundant, please explicitly 
  97. state your permission for us to use what you have sent. 
  98.  
  99. Secondly, for this and all subsequent issues, we will try to include a 
  100. hypertext link at the end of each section which will take you to the next 
  101. section, so you should only have to repeatedly press ENTER (with an occassional 
  102. TAB) to read the entire magazine. 
  103.  
  104. Thirdly, an installation program will be included with each issue, starting 
  105. with this one.  This Rexx/2 command file searches your entire desktop for a 
  106. folder called "EDM/2" and creates one on the desktop if it cannot find an 
  107. existing one.  After doing this, it creates a shadow object within that folder 
  108. that is linked to the filename of the current issue as distributed in the zip 
  109. file (so if you change the name, it will not work).  Finally, it sets the icon 
  110. of the file to a newspaper so that you can spot it in a crowd. 
  111.  
  112. INSTALL.CMD makes the following assumptions: 
  113.  
  114. o C: is the drive containing the desktop folder hierarchy 
  115. o The desktop root folder is named "d:\OS!2 2.x Desktop" where "x" is the 
  116.   version of the operating system.  Note that if you reset your desktop using 
  117.   the Ctrl-Alt-F1 key combination, the system does not overwrite your existing 
  118.   folder, meaning that the actual desktop folder has another name.  To get 
  119.   around this, you will have to edit the installation file (search for 
  120.   WP_DESKTOP). 
  121.  
  122. Miscellanea 
  123.  
  124. Last month it seems that we forgot to include the CNR2.ZIP file that was 
  125. supposed to accompany the "Programming the Container Control - Part 2" article, 
  126. so we are including it in this issue's zip file. We apologize for the 
  127. inconvenience. 
  128.  
  129. Also, I have been in contact with Gavin Baker, who was the "Introduction to PM" 
  130. columnist and he expressed a desire to continue writing for EDM/2. 
  131. Unfortunately, he was pressed for time and could not complete his column for 
  132. this issue, so we all will be looking forward to that in the next issue. 
  133.  
  134. Finally, as an update, I have also been contacted by David Singer with whom I 
  135. was able to work out the necessary kinks to make EDM/2 available inside of IBM 
  136. on a regular basis.  He will be placing the issues on his Gopher servers (one 
  137. for internal use and one that is reachable via the Internet).  We are very 
  138. thankful for his "contribution to the cause" and hope that by his offer we can 
  139. expand our audience (and thus the number of potential authors).  For more 
  140. information about reaching the Gopher servers, you can contact him at 
  141. singer@almaden.ibm.com. 
  142.  
  143. Enjoy!
  144. The Editors
  145.  
  146. Select this to go to the next section 
  147.  
  148.  
  149. ΓòÉΓòÉΓòÉ <hidden> List of Subscription Testers ΓòÉΓòÉΓòÉ
  150.  
  151. If you are listed below and did not receive the magazine this month via the 
  152. subscription mailer, please send mail to os2man@panix.com. 
  153.  
  154. aaa@atl.hp.com              menieuwp@cs.vu.nl
  155. abaddon@camelot.bradley.edu       mgrice@athena.mit.edu
  156. acmmdj@gsusgi2.gsu.edu          mmc@ehabitat.demon.co.uk
  157. bab%se40@se01.wg2.waii.com        morio@ma2s2.mathematik.uni-karlsruhe.de
  158. bachww@motcid.rtsg.mot.com        mstaedt@va-klaus.va.fh-ulm.de
  159. beaucham@phy.ulaval.ca          mullins@magnum.convex.com
  160. benji@lise.unit.no            pft@master10.zfe.siemens.de
  161. bhenning@wimsey.com           pleitner@cs.curtin.edu.au
  162. bjorn@ludd.luth.se            rcs58639@zach.fit.edu
  163. c878109@id.dth.dk            rdm@csn.org
  164. chandoni@husc.harvard.edu        rickw@umr.edu
  165. coulman@skdad.usask.ca          rik@sci.kun.nl
  166. d2henan@dtek.chalmers.se         rm3@stc06.ctd.ornl.gov
  167. donsmith@vnet.ibm.com          robert.mahoney@f347.n109.z1.fidonet.org
  168. dradhak@unx.ucc.okstate.edu       rodrigc@ecf.toronto.edu
  169. duffy@theory.chem.ubc.ca         roe2@midway.uchicago.edu
  170. evanc@carbon.isis.org          rpr@oce.nl
  171. ghdai@vax1.umkc.edu           satish.movva@uic.edu
  172. gilbert@yalevm.ycc.yale.edu       schaefer@calle2.e.open.de
  173. gogol@diku.dk              schrock@cps.msu.edu
  174. gt7027c@prism.gatech.edu         shawnmac@traider.ersys.edmonton.ab.ca
  175. heederik@fwi.uva.nl           slumos@peewee.cs.unlv.edu
  176. hepner@gourami.nosc.mil         soh3@midway.uchicago.edu
  177. jarlehto@utu.fi             spatel@cs.utexas.edu
  178. jgarzik@pantera.atl.ga.us        stephen.drye@synapse.org
  179. jjs@iedv6.acd.com            timur@seas.gwu.edu
  180. jlauro@umich.edu             visser@sci.kun.nl
  181. jofried@fzi.de              wayne@stidol.mtv.gtegsc.com
  182. johnh@meaddata.com            we44478@is1.bfu.vub.ac.be
  183. kenton+@cmu.edu             whitaker@kean.ucs.mun.ca
  184. kevin@elvis.wicat.com          wjw@eb.ele.tue.nl
  185. kfischer@hurricane.seas.ucla.edu     xtifr@netcom.com
  186.  
  187.  
  188. ΓòÉΓòÉΓòÉ 4. This Issue's Features ΓòÉΓòÉΓòÉ
  189.  
  190. The following articles constitute this issue's features: 
  191.  
  192. o Development of a New Window Class - Part 2 
  193. o The Help Manager and Online Documentation 
  194. o OS/2 Installable File Systems - Part 2 
  195. o Programming the Container Control - Part 3 
  196. o A Review of C++ Compilers 
  197.  
  198.  
  199. ΓòÉΓòÉΓòÉ 4.1. Development of a New Window Class - Part 2 ΓòÉΓòÉΓòÉ
  200.  
  201.                           Written by Larry Salomon, Jr.
  202.  
  203. Select this to go to the next section 
  204.  
  205.  
  206. ΓòÉΓòÉΓòÉ 4.1.1. Recapitulation and Regurgitation ΓòÉΓòÉΓòÉ
  207.  
  208. 0 to 60 MPH in 1 Paragraph 
  209.  
  210. Last issue we discussed the functional and design considerations for the 
  211. development of a loose-leaf paper control.  Decided was the control that the 
  212. application programmer should be able to exert on our window class through 
  213. messages and the notifications that should be sent for different types of 
  214. actions.  Also, it was determined that window words would be needed to store 
  215. instance data for each window of this class. 
  216.  
  217. Is There Anybody Out There? 
  218.  
  219. Aside from defining the interfaces to the users of this control, we can sit in 
  220. our room with the door shut and - assuming someone slips a slice of pizza or 
  221. two under the door every now and then - eventually we will have something 
  222. useable.  So where do we begin?  Even though entering text is the primary 
  223. function of this class, we have to know where to draw the text, so painting the 
  224. control will be our first component to implement. 
  225.  
  226. Select this to go to the next section 
  227.  
  228.  
  229. ΓòÉΓòÉΓòÉ 4.1.2. Painting ΓòÉΓòÉΓòÉ
  230.  
  231. Painting is easier to implement if you can break it down into distinct 
  232. sections; since we defined various components of the paper control last issue, 
  233. we can use those as a starting point. 
  234.  
  235. ΓöÇΓö¼ΓöÇΓöÇ Border
  236.  Γö£ΓöÇΓöÇ Top margin
  237.  Γö£Γö¼ΓöÇ Side margin
  238.  ΓöéΓööΓöÇΓöÇΓöÇ Top, middle, and bottom holes
  239.  ΓööΓö¼ΓöÇ Paper body
  240.  ΓööΓöÇΓöÇΓöÇ One or more text lines
  241.  
  242. Figure 1.  Different parts of the paper control 
  243.  
  244. Above all it most be noted that we cannot make any assumptions about the size 
  245. of the control, unless we force the control to follow sizing constraints (we 
  246. will not).  Our options, therefore, are to paint the control ignoring the size 
  247. or to use an abstract coordinate system based on the size when painting begins. 
  248. Obviously, the latter is the more desireable so this will be implemented. 
  249.  
  250. The breakdown of the painting as I chose it is as follows: 
  251.  
  252. o Paint the border, if it exists 
  253. o Paint the lines, both horizontal and vertical 
  254. o Paint the holes 
  255. o Paint the title text 
  256. o Paint the body text 
  257.  
  258. Paint the border 
  259.  
  260. Since some developers might not want a border, a paper style was added - 
  261. PPS_BORDER - to allow them to control this.  PM defines its window styles (that 
  262. encompass all windows) to be in the upper word of a ULONG, so PPS_BORDER is 
  263. defined to be x'0001'. 
  264.  
  265.    hpsPaint=WinBeginPaint(hwndWnd,NULLHANDLE,&rclPaint);
  266.    WinFillRect(hpsPaint,&rclPaint,CLR_WHITE);
  267.  
  268.    WinQueryWindowRect(hwndWnd,&rclWnd);
  269.  
  270.    //----------------------------------------------------------------
  271.    // Paint the border first
  272.    //
  273.    //               +------------+
  274.    //              +|-----------+|
  275.    //              ||           ||
  276.    //              ||           ||
  277.    //              ||           ||
  278.    // White -----> ||           || <----- Dark gray
  279.    //              ||           ||
  280.    //              |+------------+
  281.    //              +------------+
  282.    //----------------------------------------------------------------
  283.    if ((ulStyle & PPS_BORDER)!=0) {
  284.       GpiSetColor(hpsPaint,CLR_WHITE);
  285.  
  286.       ptlPoint.x=rclWnd.xLeft+1;
  287.       ptlPoint.y=rclWnd.yBottom;
  288.       GpiMove(hpsPaint,&ptlPoint);
  289.  
  290.       ptlPoint.x=rclWnd.xRight;
  291.       ptlPoint.y=rclWnd.yTop-1;
  292.       GpiBox(hpsPaint,DRO_OUTLINE,&ptlPoint,0,0);
  293.  
  294.       GpiSetColor(hpsPaint,CLR_DARKGRAY);
  295.  
  296.       ptlPoint.x=rclWnd.xLeft;
  297.       ptlPoint.y=rclWnd.yBottom+1;
  298.       GpiMove(hpsPaint,&ptlPoint);
  299.  
  300.       ptlPoint.x=rclWnd.xRight-1;
  301.       ptlPoint.y=rclWnd.yTop;
  302.       GpiBox(hpsPaint,DRO_OUTLINE,&ptlPoint,0,0);
  303.  
  304.       WinInflateRect(ppidData->habAnchor,&rclWnd,-2,-2);
  305.    } /* endif */
  306.  
  307. Paint the lines 
  308.  
  309. I don't know why, but it just seemed better sense to paint the vertical line 
  310. first, which was pink, if memory serves me correctly.  This is followed by the 
  311. horizontal lines, which were of a cyan tint.  Here, we added three new styles - 
  312. holes left (PPS_HOLESLEFT x'0000'), holes right (PPS_HOLESRIGHT x'0002'), and 
  313. no holes (PPS_HOLESNONE x'0004') - which we check when drawing the vertical 
  314. line. 
  315.  
  316.    //----------------------------------------------------------------
  317.    // Paint the vertical line.  Check the window style to see what
  318.    // side it is on.
  319.    //----------------------------------------------------------------
  320.    if ((ulStyle & PPS_HOLESNONE)!=0) {
  321.       ptlPoint.x=rclWnd.xLeft+ppidData->fmFont.lAveCharWidth*5;
  322.    } else
  323.    if ((ulStyle & PPS_HOLESRIGHT)!=0) {
  324.       ptlPoint.x=rclWnd.xRight-ppidData->fmFont.lAveCharWidth*5;
  325.    } else {
  326.       ptlPoint.x=rclWnd.xLeft+ppidData->fmFont.lAveCharWidth*5;
  327.    } /* endif */
  328.  
  329.    ptlPoint.y=rclWnd.yBottom;
  330.    GpiMove(hpsPaint,&ptlPoint);
  331.  
  332.    ptlPoint.y=rclWnd.yTop;
  333.    GpiSetColor(hpsPaint,CLR_PINK);
  334.    GpiLine(hpsPaint,&ptlPoint);
  335.  
  336.    //----------------------------------------------------------------
  337.    // Paint the horizontal lines.  Our strategy is to query each
  338.    // line rectangle, and draw a line along the top edge of this
  339.    // rectangle.  This means the bottom edge of the bottom line
  340.    // will not get painted, so explicitly handle this case.
  341.    //----------------------------------------------------------------
  342.    GpiSetColor(hpsPaint,CLR_DARKCYAN);
  343.  
  344.    for (sIndex=0; sIndex<ppidData->sMaxLines; sIndex++) {
  345.       WinSendMsg(hwndWnd,
  346.                  PPM_QUERYLINERECT,
  347.                  MPFROMP(&rclLine),
  348.                  MPFROMSHORT(sIndex));
  349.       ptlPoint.x=rclWnd.xLeft;
  350.       ptlPoint.y=rclLine.yTop;
  351.       GpiMove(hpsPaint,&ptlPoint);
  352.       ptlPoint.x=rclWnd.xRight;
  353.       GpiLine(hpsPaint,&ptlPoint);
  354.    } /* endfor */
  355.  
  356.    ptlPoint.x=rclWnd.xLeft;
  357.    ptlPoint.y=rclLine.yBottom-1;
  358.    GpiMove(hpsPaint,&ptlPoint);
  359.    ptlPoint.x=rclWnd.xRight;
  360.    GpiLine(hpsPaint,&ptlPoint);
  361.  
  362. Paint the holes 
  363.  
  364. In the future, we might want to support four- and seven- hole paper, so we have 
  365. to query the number of holes.  We then loop, drawing each hole, until done. 
  366.  
  367.    //----------------------------------------------------------------
  368.    // Note that if PPS_HOLESNONE was specified, 0 is returned
  369.    //----------------------------------------------------------------
  370.    usMaxHoles=SHORT1FROMMR(WinSendMsg(hwndWnd,PPM_QUERYNUMHOLES,0,0));
  371.  
  372.    for (sIndex=0; sIndex<usMaxHoles; sIndex++) {
  373.       WinSendMsg(hwndWnd,
  374.                  PPM_QUERYHOLERECT,
  375.                  MPFROMP(&rclHole),
  376.                  MPFROMSHORT(sIndex));
  377.  
  378.       ptlPoint.x=rclHole.xLeft+(rclHole.xRight-rclHole.xLeft)/2;
  379.       ptlPoint.y=rclHole.yBottom+(rclHole.yTop-rclHole.yBottom)/2;
  380.       GpiMove(hpsPaint,&ptlPoint);
  381.       GpiSetColor(hpsPaint,CLR_PALEGRAY);
  382.       GpiFullArc(hpsPaint,
  383.                  DRO_FILL,
  384.                  MAKEFIXED(ppidData->fmFont.lAveCharWidth,0));
  385.       GpiSetColor(hpsPaint,CLR_DARKGRAY);
  386.       GpiFullArc(hpsPaint,
  387.                  DRO_OUTLINE,
  388.                  MAKEFIXED(ppidData->fmFont.lAveCharWidth,0));
  389.    } /* endfor */
  390.  
  391. Paint the title text 
  392.  
  393. If there is any title text (set on the WinCreateWindow() call or via 
  394. WinSetWindowText()), we draw it here. 
  395.  
  396.    if (ppidData->pchTitle!=NULL) {
  397.       WinSendMsg(hwndWnd,
  398.                  PPM_QUERYLINERECT,
  399.                  MPFROMP(&rclLine),
  400.                  MPFROMSHORT(0));
  401.       rclLine.yBottom=rclLine.yTop+1;
  402.       rclLine.yTop=rclLine.yBottom+ppidData->fmFont.lMaxBaselineExt;
  403.  
  404.       WinDrawText(hpsPaint,
  405.                   -1,
  406.                   ppidData->pchTitle,
  407.                   &rclLine,
  408.                   ppidData->lForeClr,
  409.                   0,
  410.                   DT_CENTER);
  411.    } /* endif */
  412.  
  413. Paint the body text 
  414.  
  415. Finally, we paint the body text, using the PPM_CONVERTPOINTS message to convert 
  416. the invalid rectangle from world to line coordinates. While this is the only 
  417. optimization of the paint process, we could easily extend this to the other 
  418. components of the control. 
  419.  
  420.    WinSendMsg(hwndWnd,
  421.               PPM_CONVERTPOINTS,
  422.               MPFROMP(&rclPaint),
  423.               MPFROMSHORT(2));
  424.  
  425.    if (rclPaint.yTop<0) {
  426.       rclPaint.yTop=0;
  427.    } /* endif */
  428.  
  429.    if ((rclPaint.yBottom>ppidData->sMaxLines-1) ||
  430.        (rclPaint.yBottom<0)) {
  431.       rclPaint.yBottom=ppidData->sMaxLines-1;
  432.    } /* endif */
  433.  
  434.    while (rclPaint.yTop<=rclPaint.yBottom) {
  435.       WinSendMsg(hwndWnd,
  436.                  PPM_QUERYLINERECT,
  437.                  MPFROMP(&rclLine),
  438.                  MPFROMSHORT(rclPaint.yTop));
  439.  
  440.       if (strlen(ppidData->aachLines[rclPaint.yTop])>0) {
  441.          WinDrawText(hpsPaint,
  442.                      -1,
  443.                      ppidData->aachLines[rclPaint.yTop],
  444.                      &rclLine,
  445.                      ppidData->lBackClr,
  446.                      0,
  447.                      DT_LEFT|DT_BOTTOM);
  448.       } /* endif */
  449.  
  450.       rclPaint.yTop++;
  451.    } /* endwhile */
  452.  
  453.    WinEndPaint(hpsPaint);
  454.  
  455. Select this to go to the next section 
  456.  
  457.  
  458. ΓòÉΓòÉΓòÉ 4.1.3. User Input ΓòÉΓòÉΓòÉ
  459.  
  460. By definition, a window can only receive input when it has the input focus. 
  461. Well, this isn't entirely true, since a window receives mouse movement messages 
  462. regardless of whom has the focus, with the exception of mouse capture, only 
  463. if...All kidding aside, character keystrokes go to the window with the input 
  464. focus and the system notifies a window when it receives and loses the focus, so 
  465. we use this to implement keystroke processing.  Our 1000-foot view shows an 
  466. entryfield that belongs to us, created without ES_BORDER, which we position 
  467. over the line in which keystrokes are entered.  We let the entryfield handle 
  468. the keyboard interface and we need only to initialize it with any text 
  469. currently on the line, and query it when the line is to change. 
  470.  
  471. First, when can the line number be changed?  The answer is ours to define. I 
  472. chose to allow first button clicks to set an absolute line and the up and down 
  473. arrows to change the line by one in either direction. 
  474.  
  475. Second, what happens when the line number changes?  Derived from our 1000-foot 
  476. view, we query the entryfield text and update our internal array of line text, 
  477. determine the world coordinates of the new line, call WinSetWindowPos() to 
  478. change the position of the entryfield to reflect this new position, and finally 
  479. initialize the entryfield via WinSetWindowText() with the text of the new line 
  480. as stored in our internal array. 
  481.  
  482. These two questions translate to the messages WM_BUTTON1DOWN and WM_CHAR. 
  483.  
  484.    case WM_BUTTON1DOWN:
  485.       {
  486.          RECTL rclWnd;
  487.  
  488.          //----------------------------------------------------------------
  489.          // Before we change the line, update the text array from the
  490.          // current line
  491.          //----------------------------------------------------------------
  492.          if (ppidData->sLine>-1) {
  493.             WinQueryWindowText(ppidData->hwndText,
  494.                                sizeof(ppidData->aachLines[ppidData->sLine]),
  495.                                ppidData->aachLines[ppidData->sLine]);
  496.          } /* endif */
  497.  
  498.          //----------------------------------------------------------------
  499.          // Query the line clicked on
  500.          //----------------------------------------------------------------
  501.          rclWnd.xLeft=SHORT1FROMMP(mpParm1);
  502.          rclWnd.yBottom=SHORT2FROMMP(mpParm1);
  503.  
  504.          WinSendMsg(hwndWnd,
  505.                     PPM_CONVERTPOINTS,
  506.                     MPFROMP(&rclWnd.xLeft),
  507.                     MPFROMSHORT(1));
  508.  
  509.          //----------------------------------------------------------------
  510.          // If the place clicked on is one of the lines, set the new
  511.          // entryfield position to that line
  512.          //----------------------------------------------------------------
  513.          if (rclWnd.yBottom>-1) {
  514.             WinSendMsg(hwndWnd,PPM_SETCURRENTLINE,MPFROMP(rclWnd.yBottom),0);
  515.             WinShowWindow(ppidData->hwndText,TRUE);
  516.             WinSetWindowText(ppidData->hwndText,
  517.                              ppidData->aachLines[ppidData->sLine]);
  518.          } else {
  519.             ppidData->sLine=-1;
  520.             WinShowWindow(ppidData->hwndText,FALSE);
  521.          } /* endif */
  522.  
  523.          WinSetFocus(HWND_DESKTOP,hwndWnd);
  524.       }
  525.       break;
  526.    case WM_CHAR:
  527.       if ((CHARMSG(&ulMsg)->fs & (KC_VIRTUALKEY | KC_KEYUP))==
  528.           KC_VIRTUALKEY) {
  529.          switch (CHARMSG(&ulMsg)->vkey) {
  530.          case VK_UP:
  531.             {
  532.                RECTL rclLine;
  533.  
  534.                //----------------------------------------------------------
  535.                // Remember, we can only go up if there is another line
  536.                // above us
  537.                //----------------------------------------------------------
  538.                if (ppidData->sLine>0) {
  539.                   WinQueryWindowText(ppidData->hwndText,
  540.                                      sizeof(ppidData->aachLines[ppidData->sLine]),
  541.                                      ppidData->aachLines[ppidData->sLine]);
  542.  
  543.                   ppidData->sLine--;
  544.  
  545.                   WinSendMsg(hwndWnd,
  546.                              PPM_QUERYLINERECT,
  547.                              MPFROMP(&rclLine),
  548.                              MPFROMSHORT(ppidData->sLine));
  549.                   WinSetWindowPos(ppidData->hwndText,
  550.                                   NULLHANDLE,
  551.                                   rclLine.xLeft,
  552.                                   rclLine.yBottom,
  553.                                   0,
  554.                                   0,
  555.                                   SWP_MOVE);
  556.                   WinSetWindowText(ppidData->hwndText,
  557.                                    ppidData->aachLines[ppidData->sLine]);
  558.  
  559.                   //-------------------------------------------------------
  560.                   // We only invalidate the line we left because the
  561.                   // entryfield paints itself
  562.                   //-------------------------------------------------------
  563.                   WinSendMsg(hwndWnd,
  564.                              PPM_QUERYLINERECT,
  565.                              MPFROMP(&rclLine),
  566.                              MPFROMSHORT(ppidData->sLine+1));
  567.                   WinInvalidateRect(hwndWnd,&rclLine,TRUE);
  568.                   WinUpdateWindow(hwndWnd);
  569.  
  570.                   WinSendMsg(ppidData->hwndOwner,
  571.                              WM_CONTROL,
  572.                              MPFROM2SHORT(WinQueryWindowUShort(hwndWnd,QWS_ID),
  573.                                           PPN_UP),
  574.                              MPFROMSHORT(ppidData->sLine));
  575.                } else
  576.                if (ppidData->sLine==0) {
  577.                   WinSendMsg(ppidData->hwndOwner,
  578.                              WM_CONTROL,
  579.                              MPFROM2SHORT(WinQueryWindowUShort(hwndWnd,QWS_ID),
  580.                                           PPN_BEGINPAGE),
  581.                              MPFROMSHORT(ppidData->sLine));
  582.                } /* endif */
  583.             }
  584.             break;
  585.          //----------------------------------------------------------------
  586.          // We treat newline and enter the same as down arrow
  587.          //----------------------------------------------------------------
  588.          case VK_DOWN:
  589.          case VK_NEWLINE:
  590.          case VK_ENTER:
  591.             {
  592.                RECTL rclLine;
  593.  
  594.                //----------------------------------------------------------
  595.                // Remember, we can only go down if there is another line
  596.                // below us
  597.                //----------------------------------------------------------
  598.                if ((ppidData->sLine>-1) &&
  599.                    (ppidData->sLine<ppidData->sMaxLines-1)) {
  600.                   WinQueryWindowText(ppidData->hwndText,
  601.                                      sizeof(ppidData->aachLines[ppidData->sLine]),
  602.                                      ppidData->aachLines[ppidData->sLine]);
  603.  
  604.                   ppidData->sLine++;
  605.  
  606.                   WinSendMsg(hwndWnd,
  607.                              PPM_QUERYLINERECT,
  608.                              MPFROMP(&rclLine),
  609.                              MPFROMSHORT(ppidData->sLine));
  610.                   WinSetWindowPos(ppidData->hwndText,
  611.                                   NULLHANDLE,
  612.                                   rclLine.xLeft,
  613.                                   rclLine.yBottom,
  614.                                   0,
  615.                                   0,
  616.                                   SWP_MOVE);
  617.                   WinSetWindowText(ppidData->hwndText,
  618.                                    ppidData->aachLines[ppidData->sLine]);
  619.  
  620.                   //-------------------------------------------------------
  621.                   // We only invalidate the line we left because the
  622.                   // entryfield paints itself
  623.                   //-------------------------------------------------------
  624.                   WinSendMsg(hwndWnd,
  625.                              PPM_QUERYLINERECT,
  626.                              MPFROMP(&rclLine),
  627.                              MPFROMSHORT(ppidData->sLine-1));
  628.                   WinInvalidateRect(hwndWnd,&rclLine,TRUE);
  629.                   WinUpdateWindow(hwndWnd);
  630.  
  631.                   WinSendMsg(ppidData->hwndOwner,
  632.                              WM_CONTROL,
  633.                              MPFROM2SHORT(WinQueryWindowUShort(hwndWnd,QWS_ID),
  634.                                           PPN_DOWN),
  635.                              MPFROMSHORT(ppidData->sLine));
  636.                } else
  637.                if (ppidData->sLine==ppidData->sMaxLines-1) {
  638.                   WinSendMsg(ppidData->hwndOwner,
  639.                              WM_CONTROL,
  640.                              MPFROM2SHORT(WinQueryWindowUShort(hwndWnd,QWS_ID),
  641.                                           PPN_ENDPAGE),
  642.                              MPFROMSHORT(ppidData->sLine));
  643.                } /* endif */
  644.             }
  645.             break;
  646.          default:
  647.             return WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  648.          } /* endswitch */
  649.       } else {
  650.          return WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  651.       } /* endif */
  652.       break;
  653.  
  654. Notice the notifications PPN_UP, PPN_DOWN, PPN_BEGINPAGE and PPN_ENDPAGE. 
  655.  
  656. Time Out 
  657.  
  658. You will not notice this now, but if you click on the paper control, the line 
  659. number is supposed to change.  Why do we not get a flashing cursor where the 
  660. "invisible" entryfield exists?  The answer is in the way the system handles 
  661. focus changing. 
  662.  
  663. When the input focus window changes, a number of messages are sent as a result 
  664. to both the window losing the focus and to the window receiving the focus. 
  665. While this messages are being processed, the system considers no one to have 
  666. the focus, so any attempt to change the focus via WinSetFocus() or 
  667. WinFocusChange() will have no effect because the system will "overwrite" the 
  668. focus change as it completes its processing. 
  669.  
  670. The result of this gibberish is that, if we are clicked on, we want the 
  671. entryfield to receive the focus, but since we need to do some processing, we 
  672. cannot just call WinSetFocus(HWND_DESKTOP,ppidData->hwndText) since we will 
  673. never receive any notification. 
  674.  
  675. The result of that gibberish is that we need to get the focus and then somehow 
  676. pass the focus on to the entryfield.  Since we cannot change the focus while 
  677. the system changes the focus, we need a little hocus-pocus to achieve this. 
  678.  
  679.    #define PRVM_SETFOCUS               (WM_USER)
  680.  
  681.    case WM_SETFOCUS:
  682.       WinPostMsg(hwndWnd,PRVM_SETFOCUS,mpParm1,mpParm2);
  683.       break;
  684.    case PRVM_SETFOCUS:
  685.       if (SHORT1FROMMP(mpParm2)) {
  686.          if (ppidData->sLine>-1) {
  687.             WinShowWindow(ppidData->hwndText,TRUE);
  688.             WinFocusChange(HWND_DESKTOP,
  689.                            ppidData->hwndText,
  690.                            FC_NOLOSEACTIVE|FC_NOLOSEFOCUS|FC_NOLOSESELECTION);
  691.          } /* endif */
  692.  
  693.          WinSendMsg(ppidData->hwndOwner,
  694.                     WM_CONTROL,
  695.                     MPFROM2SHORT(WinQueryWindowUShort(hwndWnd,QWS_ID),
  696.                                  PPN_SETFOCUS),
  697.                     0);
  698.       } else {
  699.          //----------------------------------------------------------------
  700.          // If we're losing the focus, update the text array, but leave the
  701.          // entryfield text alone.
  702.          //----------------------------------------------------------------
  703.          if (ppidData->sLine>-1) {
  704.             WinQueryWindowText(ppidData->hwndText,
  705.                                sizeof(ppidData->aachLines[ppidData->sLine]),
  706.                                ppidData->aachLines[ppidData->sLine]);
  707.             WinShowWindow(ppidData->hwndText,FALSE);
  708.          } /* endif */
  709.  
  710.          WinSendMsg(ppidData->hwndOwner,
  711.                     WM_CONTROL,
  712.                     MPFROM2SHORT(WinQueryWindowUShort(hwndWnd,QWS_ID),
  713.                                  PPN_KILLFOCUS),
  714.                     0);
  715.       } /* endif */
  716.       break;
  717.  
  718. In the code above, a couple of things need to be noted: 
  719.  
  720. o The hocus-pocus is in the call to WinPostMsg().  While it is not guaranteed, 
  721.   it is highly likely that our message will get processed after the system 
  722.   finished the focus change.  This will allow us to do any processing necessary 
  723.   and then change the focus again to the entryfield. 
  724.  
  725. o The focus change added two new notifications - PPN_SETFOCUS and 
  726.   PPN_KILLFOCUS.  These have the same semantics as the corresponding entryfield 
  727.   notifications EN_SETFOCUS and EN_KILLFOCUS. 
  728.  
  729. o The call to WinFocusChange() specifies through the use of the FC_* constants 
  730.   that the window with the focus (that's us) should not receive any 
  731.   notification that it is losing the focus.  This is needed so that we don't 
  732.   send the PPN_KILLFOCUS notification. 
  733.  
  734. Select this to go to the next section 
  735.  
  736.  
  737. ΓòÉΓòÉΓòÉ 4.1.4. Owner Notifications ΓòÉΓòÉΓòÉ
  738.  
  739. Last issue, we defined a list of four events that should result in a 
  740. notification to the owner window.  The system allows us to define any 
  741. notification code as a USHORT that we feel is necessary, since there is no 
  742. "standard list" of notifications present for all window classes (versus window 
  743. styles, where there is a common set of styles). 
  744.  
  745. The cursor moves up or down 
  746.  
  747. This is implemented in the processing for WM_CHAR.  The code consists of the 
  748. following call to WinSendMsg(). 
  749.  
  750.    WinSendMsg(ppidData->hwndOwner,
  751.               WM_CONTROL,
  752.               MPFROM2SHORT(WinQueryWindowUShort(hwndWnd,QWS_ID),PPN_UP),
  753.               MPFROMSHORT(ppidData->sLine));
  754.  
  755. Substitute PPN_DOWN for PPN_UP as needed. 
  756.  
  757. Note that if the cursor is on line 1/ppidData->sMaxLines and the user presses 
  758. the up/down arrow, we instead send a PPN_BEGINPAGE/PPN_ENDPAGE notification to 
  759. let the application know that the page boundary was reached. 
  760.  
  761. Any mouse button is clicked or double-clicked 
  762.  
  763. This is implemented in the processing for the various WM_BUTTONxUP and 
  764. WM_BUTTONxDBLCLK messages.  The code is the same as for the PPN_UP/PPN_DOWN 
  765. notifications with the notification code changed as appropriate.  Note that we 
  766. could use the second half of mpParm2 to include which button was pressed, as a 
  767. convenience to the user. 
  768.  
  769. The system-defined sequence for displaying the context menu is pressed 
  770.  
  771. Again, we use the same call to WinSendMsg(), this time from the WM_CONTEXTMENU 
  772. message. 
  773.  
  774. Help is requested 
  775.  
  776. And finally one more WinSendMsg() from the WM_HELP message. 
  777.  
  778. That was easy, wasn't it? 
  779.  
  780. Select this to go to the next section 
  781.  
  782.  
  783. ΓòÉΓòÉΓòÉ 4.1.5. Presentation Parameters ΓòÉΓòÉΓòÉ
  784.  
  785. Processing these is probably the most interesting, because...well, because the 
  786. ability for the user to change the color and font of a window was new with OS/2 
  787. 2.0.  [Get on soapbox] "I remember the days when you didn't have to deal with 
  788. these dad-burned paramitization presentations or whatever the hell they're 
  789. called."[Get off soapbox]. Because the user has the ability, via the color and 
  790. font palettes, to change your presentation parameters, you can no longer avoid 
  791. them when developing a new window class. 
  792.  
  793. Changing a presentation parameter is done for you by the system, providing you 
  794. use a micro-cache'd presentation space in all of your drawing operations 
  795. (obtained through WinBeginPaint() with NULLHANDLE specified as the second 
  796. parameter, or through WinGetPS()).  If you have your own screen presentation 
  797. space which you specify in the call to WinBeginPaint, you will need to 
  798. intercept the WM_PRESPARAMCHANGED message.  Another time this message is needed 
  799. is if you need the size of the current font for other processing or will 
  800. unconditionally set the color to some color but want to restore it for other 
  801. operations. 
  802.  
  803. Gee, aren't those familiar operations? 
  804.  
  805. We intercept this message and if a color was changed, we query the new color 
  806. value and store that in our instance data.  If the font changed, we re-query 
  807. the FONTMETRICS structure values so that we can base our line size on the 
  808. height of the font. 
  809.  
  810.    case WM_PRESPARAMCHANGED:
  811.       switch (LONGFROMMP(mpParm1)) {
  812.       case PP_FOREGROUNDCOLOR:
  813.       case PP_FOREGROUNDCOLORINDEX:
  814.          {
  815.             ULONG ulId;
  816.             LONG lColor;
  817.             HPS hpsWnd;
  818.             SHORT sIndex;
  819.             RECTL rclLine;
  820.  
  821.             WinQueryPresParam(hwndWnd,
  822.                               PP_FOREGROUNDCOLORINDEX,
  823.                               LONGFROMMP(mpParm1),
  824.                               &ulId,
  825.                               sizeof(lColor),
  826.                               &lColor,
  827.                               QPF_NOINHERIT);
  828.  
  829.             if (ulId==PP_FOREGROUNDCOLOR) {
  830.                hpsWnd=WinGetPS(hwndWnd);
  831.                lColor=GpiQueryColorIndex(hpsWnd,0,lColor);
  832.                WinReleasePS(hpsWnd);
  833.             } /* endif */
  834.  
  835.             ppidData->lForeClr=lColor;
  836.  
  837.             for (sIndex=0; sIndex<ppidData->sMaxLines; sIndex++) {
  838.                if (ppidData->aachLines[sIndex][0]!=0) {
  839.                   WinSendMsg(hwndWnd,
  840.                              PPM_QUERYLINERECT,
  841.                              MPFROMP(&rclLine),
  842.                              MPFROMSHORT(sIndex));
  843.                   WinInvalidateRect(hwndWnd,NULL,TRUE);
  844.                } /* endif */
  845.             } /* endfor */
  846.  
  847.             WinUpdateWindow(hwndWnd);
  848.          }
  849.          break;
  850.       case PP_BACKGROUNDCOLOR:
  851.       case PP_BACKGROUNDCOLORINDEX:
  852.          {
  853.             ULONG ulId;
  854.             LONG lColor;
  855.             HPS hpsWnd;
  856.             SHORT sIndex;
  857.             RECTL rclLine;
  858.  
  859.             WinQueryPresParam(hwndWnd,
  860.                               PP_BACKGROUNDCOLORINDEX,
  861.                               LONGFROMMP(mpParm1),
  862.                               &ulId,
  863.                               sizeof(lColor),
  864.                               &lColor,
  865.                               QPF_NOINHERIT);
  866.  
  867.             if (ulId==PP_BACKGROUNDCOLOR) {
  868.                hpsWnd=WinGetPS(hwndWnd);
  869.                lColor=GpiQueryColorIndex(hpsWnd,0,lColor);
  870.                WinReleasePS(hpsWnd);
  871.             } /* endif */
  872.  
  873.             ppidData->lBackClr=lColor;
  874.  
  875.             for (sIndex=0; sIndex<ppidData->sMaxLines; sIndex++) {
  876.                if (ppidData->aachLines[sIndex][0]!=0) {
  877.                   WinSendMsg(hwndWnd,
  878.                              PPM_QUERYLINERECT,
  879.                              MPFROMP(&rclLine),
  880.                              MPFROMSHORT(sIndex));
  881.                   WinInvalidateRect(hwndWnd,NULL,TRUE);
  882.                } /* endif */
  883.             } /* endfor */
  884.  
  885.             WinUpdateWindow(hwndWnd);
  886.          }
  887.          break;
  888.       case PP_FONTNAMESIZE:
  889.       case PP_FONTHANDLE:
  890.          {
  891.             HPS hpsWnd;
  892.             RECTL rclWnd;
  893.  
  894.             hpsWnd=WinGetPS(hwndWnd);
  895.             GpiQueryFontMetrics(hpsWnd,sizeof(FONTMETRICS),&ppidData->fmFont);
  896.             WinReleasePS(hpsWnd);
  897.  
  898.             WinQueryWindowRect(hwndWnd,&rclWnd);
  899.             WinSendMsg(hwndWnd,
  900.                        WM_SIZE,
  901.                        0,
  902.                        MPFROM2SHORT((SHORT)rclWnd.xRight,
  903.                                     (SHORT)rclWnd.yTop));
  904.             WinInvalidateRect(hwndWnd,NULL,TRUE);
  905.             WinUpdateWindow(hwndWnd);
  906.          }
  907.          break;
  908.       default:
  909.          return WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  910.       } /* endswitch */
  911.       break;
  912.  
  913. Again, there are other (better) ways of implementing things.  Here, we could 
  914. query the RGB value of the changed color and use that in our painting to get 
  915. the most accuracy.  This exercise is left up to the programmer. 
  916.  
  917. While it doesn't really belong here, the window text processing has nowhere 
  918. else to go so it is discussed here.  The system's interface to a window class 
  919. for items like this is through the WM_SETWINDOWPARAMS and WM_QUERYWINDOWPARAMS 
  920. messages.  The former is sent when a window parameter changes and the latter is 
  921. sent to query the data from the window.  A window parameter is either the 
  922. window text or the control data (which is specific to a window class) and both 
  923. are bundled in the WNDPARAMS structure. 
  924.  
  925.    typedef struct _WNDPARAMS {
  926.       ULONG fsStatus;
  927.       ULONG cchText;
  928.       PSZ pszText;
  929.       ULONG cbPresParams;
  930.       PVOID pPresParams;
  931.       ULONG cbCtlData;
  932.       PVOID pCtlData;
  933.    } WNDPARAMS, *PWNDPARAMS;
  934.  
  935. fsStatus            For queries by the system, this specifies (as a combination 
  936.                     of WPM_* constants) the parameters to query. 
  937. cchText             This specifies the size of the data pointed to by pszText 
  938. pszText             This points to the window text, terminated by a NULL 
  939.                     character 
  940. cbPresParams        This specifies the size of the data pointed to by 
  941.                     pPresParams 
  942. pPresParams         This points to the presentation parameters 
  943. cbCtlData           This specifies the size of the data pointed to by pCtlData 
  944. pCtlData            This points to the control data 
  945.  
  946. Since we are interested in the text only, we check the fsStatus field for the 
  947. WPM_TEXT constant explicitly and act accordingly. The resulting code is shown 
  948. below: 
  949.  
  950.    case WM_QUERYWINDOWPARAMS:
  951.       {
  952.          PWNDPARAMS pwpParms;
  953.  
  954.          pwpParms=(PWNDPARAMS)PVOIDFROMMP(mpParm1);
  955.  
  956.          if ((pwpParms->fsStatus & WPM_TEXT)!=0) {
  957.             pwpParms->pszText[0]=0;
  958.             strncat(pwpParms->pszText,ppidData->pchTitle,pwpParms->cchText);
  959.             WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  960.             return MRFROMSHORT(TRUE);
  961.          } /* endif */
  962.  
  963.          return WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  964.       }
  965.    case WM_SETWINDOWPARAMS:
  966.       {
  967.          BOOL bProcessed;
  968.          PWNDPARAMS pwpParms;
  969.  
  970.          bProcessed=FALSE;
  971.          pwpParms=(PWNDPARAMS)PVOIDFROMMP(mpParm1);
  972.  
  973.          if ((pwpParms->fsStatus & WPM_TEXT)!=0) {
  974.             if (ppidData->pchTitle!=NULL) {
  975.                free(ppidData->pchTitle);
  976.                ppidData->pchTitle=NULL;
  977.             } /* endif */
  978.  
  979.             if ((pwpParms->pszText!=NULL) && (strlen(pwpParms->pszText)>0)) {
  980.                ppidData->pchTitle=malloc(strlen(pwpParms->pszText)+1);
  981.                strcpy(ppidData->pchTitle,pwpParms->pszText);
  982.             } /* endif */
  983.  
  984.             bProcessed=TRUE;
  985.          } /* endif */
  986.  
  987.          if (bProcessed) {
  988.             WinInvalidateRect(hwndWnd,NULL,TRUE);
  989.             WinUpdateWindow(hwndWnd);
  990.             WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  991.             return MRFROMSHORT(TRUE);
  992.          } else {
  993.             return WinDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  994.          } /* endif */
  995.       }
  996.  
  997. Select this to go to the next section 
  998.  
  999.  
  1000. ΓòÉΓòÉΓòÉ 4.1.6. Summary ΓòÉΓòÉΓòÉ
  1001.  
  1002. Although a lot of code was presented here, all of it is really only the 
  1003. extension of our thoughts from last issue when this new class was being 
  1004. designed.  It cannot be stressed enough the importance of a good design; no one 
  1005. expects you to get it right the first time, but if you think most of it through 
  1006. the rest becomes significantly easier. 
  1007.  
  1008. As a final note, all coordinates that we discussed here were (if not already) 
  1009. mapped to line numbers via the message PPM_CONVERTPOINTS. This allows us to 
  1010. change the size of each line in one place only.  This logic was applied in 
  1011. other places (PPM_QUERYNUMHOLES) to make our maintenance easier and goes way 
  1012. back to Computer Science 101 when code modularity was discussed. 
  1013.  
  1014. Select this to go to the next section 
  1015.  
  1016.  
  1017. ΓòÉΓòÉΓòÉ 4.2. The Help Manager and Online Documentation ΓòÉΓòÉΓòÉ
  1018.  
  1019.                           Written by Larry Salomon, Jr.
  1020.  
  1021. Select this to go to the next section 
  1022.  
  1023.  
  1024. ΓòÉΓòÉΓòÉ 4.2.1. Introduction ΓòÉΓòÉΓòÉ
  1025.  
  1026. More times than I care to remember, I have been asked "How do I add online help 
  1027. to my applications?" or "How can I write online books?"  While the latter takes 
  1028. less time to answer, I often myself talking for 45 minutes or so on everything 
  1029. from what an GML language is to the sequence of events that happen when a user 
  1030. presses the F1 key. 
  1031.  
  1032. Finally, today I got tired of repeating myself (even as much as I love to talk) 
  1033. so I decided to write the article that has been promised for so long. Hopefully 
  1034. after reading this, you should be able to do the following: 
  1035.  
  1036. o Briefly explain what an GML language is and what markup is 
  1037.  
  1038. o List the three components needed when adding context-sensitive help to a PM 
  1039.   application and what each component's purpose is 
  1040.  
  1041. o Describe the sequence of events that occur when a user presses F1 
  1042.  
  1043. o Detail the minimum markup required to create a valid online help file and to 
  1044.   create a valid online book file 
  1045.  
  1046. o Be able to write the markup for headings, paragraphs, lists (all five types), 
  1047.   emphasis, hypertext links, and graphics. 
  1048.  
  1049. o Explain some of the limitations of the IPFC compiler 
  1050.  
  1051. Select this to go to the next section 
  1052.  
  1053.  
  1054. ΓòÉΓòÉΓòÉ 4.2.2. The Basics ΓòÉΓòÉΓòÉ
  1055.  
  1056. GML is an acronym for generalized markup language and describes a group of 
  1057. languages which perform operations on blocks of text. Typically, these 
  1058. languages are used for output formatting but are not limited to this arena. 
  1059. The language consists of control words (called tags) interspersed within blocks 
  1060. of text; these tags have the form 
  1061.  
  1062. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1063. :tag [attribute[=value] [attribute[=value] [...]]].[text]
  1064. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1065. Figure 1.  GML tag syntax 
  1066.  
  1067. The attributes shown above vary from tag to tag and may not exist at all. 
  1068. Likewise, each attribute may or may not accept a value; consult the 
  1069. "Information Presentation Facility" reference guide which comes with the 2.x 
  1070. toolkit for a complete list of the attributes for each tag. 
  1071.  
  1072. Frequently, a tag is used to mark the beginning of a change in formatting and 
  1073. has a corresponding end tag to signify the end of that change. The end tag 
  1074. often is the same as the begin tag prefixed with an "e".  Thus, you use :hp2. 
  1075. to begin emphasis level 2 and :ehp2. to end it. 
  1076.  
  1077. The term markup is used to describe a combination of tags and text in a GML 
  1078. file. 
  1079.  
  1080. Application components 
  1081.  
  1082. There are three help-related components to any PM application, listed below. 
  1083.  
  1084. o Source code - calls to and from the Help Manager from your application 
  1085.  
  1086. o Resources - relationships between focus windows and help panels 
  1087.  
  1088. o Panel definitions - GML source describing the help panels' appearance 
  1089.  
  1090. Select this to go to the next section 
  1091.  
  1092.  
  1093. ΓòÉΓòÉΓòÉ 4.2.3. Source code ΓòÉΓòÉΓòÉ
  1094.  
  1095. This consists of the various calls to Help Manager functions from within your 
  1096. PM application.  The bare minimum exists in your main() function and creates an 
  1097. instance of the Help Manager: 
  1098.  
  1099. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1100. #define INCL_WINHELP
  1101.   :
  1102.  
  1103. INT main(USHORT usArgs,PCHAR apchArgs[])
  1104. {
  1105.      :
  1106.    HELPINIT hiHelp;
  1107.  
  1108.    habAnchor=WinInitialize(0);
  1109.    hmqQueue=WinCreateMsgQueue(habAnchor,0);
  1110.      :
  1111.      : /* Create frame window */
  1112.      :
  1113.    if (hwndFrame!=NULLHANDLE) {
  1114.         :
  1115.         : /* Initialize HELPINIT structure */
  1116.         :
  1117.       hwndHelp=WinCreateHelpInstance(habAnchor,&hiHelp);
  1118.       WinAssociateHelpInstance(hwndHelp,hwndFrame);
  1119.         :
  1120.         : /* Message loop in here somewhere */
  1121.         :
  1122.       WinDestroyHelpInstance(hwndHelp);
  1123.       WinDestroyWindow(hwndFrame);
  1124.    } /* endif */
  1125.  
  1126.    WinDestroyMsgQueue(hmqQueue);
  1127.    WinTerminate(habAnchor);
  1128. }
  1129. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1130. Figure 2.  Help Manager initialization 
  1131.  
  1132. The HELPINIT structure is a rather large conglomeration of configurable items. 
  1133.  
  1134. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1135. typedef struct _HELPINIT {
  1136.    ULONG cb;
  1137.    ULONG ulReturnCode;
  1138.    PSZ pszTutorialName;
  1139.    PHELPTABLE phtHelpTable;
  1140.    HMODULE hmodHelpTableModule;
  1141.    HMODULE hmodAccelActionBarModule;
  1142.    ULONG idAccelTable;
  1143.    ULONG idActionBar;
  1144.    PSZ pszHelpWindowTitle;
  1145.    ULONG fShowPanelId;
  1146.    PSZ pszHelpLibraryName;
  1147. } HELPINIT, *PHELPINIT;
  1148. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1149. Figure 3.  HELPINIT structure 
  1150.  
  1151. cb                  Specifies the size of the structure in bytes 
  1152.  
  1153. ulReturnCode        On exit, contains any error codes returned from the Help 
  1154.                     Manager 
  1155.  
  1156. pszTutorialName     Points to the string specifying the default tutorial name. 
  1157.                     If NULL, there is no default tutorial or it is specified in 
  1158.                     the panel definition file. 
  1159.  
  1160. phtHelpTable        Points to the HELPTABLE to use, or specifies the resource 
  1161.                     id of the HELPTABLE to be loaded from the resource file. 
  1162.                     If this specifies the resource id, it is contained in the 
  1163.                     low word and the high word must be 0xFFFF. 
  1164.  
  1165. hmodHelpTableModule Specifies the handle of the module from whence the 
  1166.                     HELPTABLE is to be loaded. 
  1167.  
  1168. idAccelTable        Specifies the resource id of the accelerator table to be 
  1169.                     used.  A value of 0 specifies that the default is to be 
  1170.                     used. 
  1171.  
  1172. idActionBar         Specifies the resource id of the action bar to be used.  A 
  1173.                     value of 0 specifies that the default is to be used. 
  1174.  
  1175. hmodAccelActionBarModule Specifies the handle of the module from whence the 
  1176.                     accelerator table and action bar are to be loaded. 
  1177.  
  1178. pszHelpWindowTitle  Points to the help window title text. 
  1179.  
  1180. fShowPanelId        Specifies whether or not to show the panel identifier (if 
  1181.                     present).  Valid values are CMIC_SHOW_PANEL_ID and 
  1182.                     CMIC_HIDE_PANEL_ID. 
  1183.  
  1184. pszHelpLibraryName  Points to the filename containing the compiler panel 
  1185.                     definitions. 
  1186.  
  1187. It needs to be noted that even though a valid window handle is returned from 
  1188. WinCreateHelpInstance(), an error might have occurred whose value is specified 
  1189. in the ulReturnCode field of the HELPINIT structure. 
  1190.  
  1191. Messages 
  1192.  
  1193. There will be times when you will want to send messages to the Help Manager and 
  1194. when messages will be received.  The four most frequent messages sent to the 
  1195. Help Manager are listed below: 
  1196.  
  1197. HM_HELP_INDEX       Causes the help index to be displayed 
  1198. HM_EXT_HELP         Causes the extended (general) help panel defined for the 
  1199.                     active window to be displayed (described more later) 
  1200. HM_DISPLAY_HELP     Causes the panel specified by name (in mpParm1) or resource 
  1201.                     id (in mpParm2) to be displayed.  Specifying NULL and 0 for 
  1202.                     these values cause the "Using Help" panel to be displayed. 
  1203. HM_KEYS_HELP        Causes the keys help panel to be displayed.  Since the 
  1204.                     active key set is dependent on the current state of the 
  1205.                     application, this cannot be statically defined in the 
  1206.                     resource tables.  Instead, the Help Manager responds by 
  1207.                     sending your application an HM_QUERY_KEYS_HELP message to 
  1208.                     get the resource id of the keys help panel. 
  1209.  
  1210. The following three messages sent to your application are probably the most 
  1211. widely used: 
  1212.  
  1213. HM_ERROR            Sent whenever an error occurs between the time F1 is 
  1214.                     pressed and the help operation ends.  The error code is 
  1215.                     specified in mpParm1 
  1216. HM_HELPSUBITEM_UNDEFINED Sent whenever help was requested but no entry in the 
  1217.                     HELPSUBTABLE was found. 
  1218. HM_INFORM           Sent whenever a link with the inform attribute is 
  1219.                     encountered. 
  1220.  
  1221. Select this to go to the next section 
  1222.  
  1223.  
  1224. ΓòÉΓòÉΓòÉ 4.2.4. Resources ΓòÉΓòÉΓòÉ
  1225.  
  1226. To make the connection between a window and a help panel, two new resource 
  1227. types were added to PM's resource file definition - HELPTABLEs and 
  1228. HELPSUBTABLEs.  Together, they specify an array of variable length lists that 
  1229. map a window resource id to a help panel resource id. 
  1230.  
  1231. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1232. HELPTABLE RES_CLIENT
  1233. {
  1234.    HELPITEM RES_CLIENT, SUBHELP_CLIENT, GENHELP_CLIENT
  1235.    HELPITEM RES_DIALOG1, SUBHELP_DIALOG1, GENHELP_DIALOG1
  1236.    HELPITEM RES_DIALOG2, SUBHELP_DIALOG2, GENHELP_DIALOG2
  1237.      :
  1238.    HELPITEM RES_DIALOGn, SUBHELP_DIALOGn, GENHELP_DIALOGn
  1239. }
  1240.  
  1241. HELPSUBTABLE SUBHELP_CLIENT
  1242. {
  1243.    HELPSUBITEM WID_WINDOW1, HID_PANEL1
  1244.    HELPSUBITEM WID_WINDOW2, HID_PANEL2
  1245.      :
  1246.    HELPSUBITEM WID_WINDOWn, HID_PANELn
  1247. }
  1248.  
  1249. HELPSUBTABLE SUBHELP_DIALOG1
  1250. {
  1251.    HELPSUBITEM WID_WINDOW1, HID_PANEL1
  1252.    HELPSUBITEM WID_WINDOW2, HID_PANEL2
  1253.      :
  1254.    HELPSUBITEM WID_WINDOWn, HID_PANELn
  1255. }
  1256.  
  1257. HELPSUBTABLE SUBHELP_DIALOG2
  1258. {
  1259.    HELPSUBITEM WID_WINDOW1, HID_PANEL1
  1260.    HELPSUBITEM WID_WINDOW2, HID_PANEL2
  1261.      :
  1262.    HELPSUBITEM WID_WINDOWn, HID_PANELn
  1263. }
  1264.  
  1265. HELPSUBTABLE SUBHELP_DIALOG3
  1266. {
  1267.    HELPSUBITEM WID_WINDOW1, HID_PANEL1
  1268.    HELPSUBITEM WID_WINDOW2, HID_PANEL2
  1269.      :
  1270.    HELPSUBITEM WID_WINDOWn, HID_PANELn
  1271. }
  1272. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1273. Figure 4.  Help Manager resource structures 
  1274.  
  1275. Each HELPITEM specifies the resource id of an active window, the id of the 
  1276. HELPSUBTABLE associated with this window, and the resource id of the General 
  1277. Help panel associated with this window. 
  1278.  
  1279. Each HELPSUBITEM specifies a focus window resource id (WID_*) and a 
  1280. corresponding help panel resource id (HID_*). 
  1281.  
  1282. What are the rules that the Help Manager uses to get from F1 to a help panel 
  1283. id?  To answer that question, we need to know the sequence of events that occur 
  1284. when a user presses F1.  Below, we assume that the application is help-enabled. 
  1285.  
  1286.  1. The user presses F1 
  1287.  
  1288.  2. The Help Manager queries the active window resource id (ID1) and the focus 
  1289.     window id (ID2). 
  1290.  
  1291.  3. ID1 is used in a lookup of the HELPTABLE to determine the HELPSUBTABLE to 
  1292.     use. 
  1293.  
  1294.  4. ID2 is used in a lookup of the HELPSUBTABLE to find the resource id of the 
  1295.     help panel to display. 
  1296.  
  1297.  5. The Help Manager displays the panel. 
  1298.  
  1299. There are two obvious error conditions:  1) there is no HELPSUBTABLE for the 
  1300. active window and 2) there is no HELPSUBITEM for the focus window.  The former 
  1301. is resolved by examining each window in the parent window chain until a window 
  1302. that does have a HELPSUBTABLE is found and then the process continues as 
  1303. normal.  If this still yields nothing, the owner window chain is searched and 
  1304. then if nothing still, an error message is sent to the active window.  The 
  1305. latter is resolved by first sending an HM_HELPSUBITEM_UNDEFINED message to 
  1306. attempt to alleviate the situation.  If the application returns FALSE the 
  1307. general help panel specified on the HELPITEM statement is displayed. 
  1308.  
  1309. Select this to go to the next section 
  1310.  
  1311.  
  1312. ΓòÉΓòÉΓòÉ 4.2.5. Panel definitions ΓòÉΓòÉΓòÉ
  1313.  
  1314. This is, by far, the most time-consuming portion of help-enabling.  Not only do 
  1315. you have to write the text to be displayed, but you must also be aware of 
  1316. formatting options and what effect they have on the output.  At a minimum, you 
  1317. must have the following to create a valid online help file: 
  1318.  
  1319. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1320. :userdoc.
  1321. :h1.Heading 1
  1322. :p.Paragraph 1
  1323. :euserdoc.
  1324. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1325. Figure 5.  Minimum GML markup 
  1326.  
  1327. The tags used above are described below: 
  1328.  
  1329. :userdoc.           Specifies the beginning of a user document. 
  1330.  
  1331. :h1.                Specifies a heading level 1. 
  1332.  
  1333. :p.                 Specifies a new paragraph. 
  1334.  
  1335. :euserdoc.          Specifies the end of the user document. 
  1336.  
  1337. Online book writers must also specify a :title.Document title after the 
  1338. :userdoc. tag. 
  1339.  
  1340. As you can imagine, this file doesn't do much.  In fact, it does nothing since 
  1341. as you can see nowhere are an help panel resource ids specified (even though 
  1342. you don't know how to specify them).  For that matter, what defines a panel? 
  1343.  
  1344. A panel is a block of formatted text beginning with a heading level and ending 
  1345. with the beginning of the next panel displayed in the table of contents or the 
  1346. end of the document body.  (the back matter  of a document can contain an 
  1347. index.)  Heading levels are specifies after the h and can be in the range 1-9; 
  1348. by default, only heading levels 1-3 are displayed in the table of contents, but 
  1349. this is configurable using the :docprof. tag.  A heading may also have 
  1350. attributes; these are the res, id, name, and hide attributes. 
  1351.  
  1352. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1353. :hn [res=value][id=value][name=value][hide].
  1354. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1355. Figure 6.  Heading tag syntax 
  1356.  
  1357. res=value           This specifies a numeric resource id for the panel and is 
  1358.                     used in the HELPSUBITEM definitions and can be used to 
  1359.                     specify the target of a hypertext link. 
  1360. id=value            This specifies an alphanumeric id that can be used to 
  1361.                     specify the target of a hypertext link. 
  1362. name=value          This specifies an alphanumeric id that can be referenced by 
  1363.                     an application. 
  1364. hide                This specifies that, regardless of the heading level, the 
  1365.                     panel should not show up in the table of contents.  This is 
  1366.                     useful for hypertext links. 
  1367.  
  1368. Headings must have data associated with them, i.e. you cannot have an :h1. tag 
  1369. immediately followed by an :h2. tag.  Also, heading levels other than 1 that 
  1370. are ordinally higher than their predecessors must have the next cardinal value. 
  1371. Thus, the first example is valid while the second is not: 
  1372.  
  1373. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1374. :h1.Heading 1
  1375. :p.Blah blah blah
  1376. :h2.Heading 2
  1377. :p.Blah blah blah
  1378. :h1.Heading 1
  1379. :p.Blah blah blah
  1380.  
  1381. :h1.Heading 1
  1382. :p.Blah blah blah
  1383. :h3.Heading 3
  1384. :p.Blah blah blah
  1385. :h1.Heading 1
  1386. :p.Blah blah blah
  1387. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1388. Figure 7.  Heading examples 
  1389.  
  1390. This does not apply to headings that have a lower value than their 
  1391. predecessors. 
  1392.  
  1393. Paragraphs 
  1394.  
  1395. The most frequently used tag is probably the :p. tag, used to begin a new 
  1396. paragraph.  It should be noted that some constructs implictly begin on a new 
  1397. paragraph, so this is not needed.  A paragraph is denoted by ending the current 
  1398. line, inserting a blank line, and continuing on the next line.  The current 
  1399. indentation level (modified by lists, etc.) is not changed. 
  1400.  
  1401. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1402. :p.
  1403. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1404. Figure 8.  Paragraph tag syntax 
  1405.  
  1406. A word here should be mentioned about symbols.  What happens when you want to 
  1407. put a colon (:) in your panels?  How is the compiler going to be able to 
  1408. differentiate between a colon as part of the text or as the beginning of a tag. 
  1409. GML defines a syntax for symbols such that they begin with an ampersand (&) and 
  1410. end with a period with a symbol name in the middle.  Thus, a colon is &colon., 
  1411. and ampersand is &., etc.. Some other commonly used symbols appear below: 
  1412.  
  1413. &lbrk.    Left bracket ([) 
  1414. &rbrk.    Right bracket (]) 
  1415. &lbrc.    Left brace ({) 
  1416. &rbrc.    Right brace (}) 
  1417. &vbar.    Vertical bar (|) 
  1418. &apos.    Apostrophe (') 
  1419. &bsl.     Backslash (\) 
  1420. &odq.     Open double quote (") 
  1421. &cdq.     Close double quote (") 
  1422. &osq.     Open single quote (`) 
  1423. &csq.     Close single quote (') 
  1424.  
  1425. You should use the symbol syntax instead of the actual characters whenever 
  1426. possible to ease the process of translating your IPF source to other languages, 
  1427. should that happen, since the compiler defines the code point to which each 
  1428. symbol is mapped according to the codepage in effect. 
  1429.  
  1430. Lists 
  1431.  
  1432. IPF (Information Presentation Facility - the language definition) defines five 
  1433. types of lists - simple, unordered, ordered, definition, and parameter. All 
  1434. lists consist of a begin tag, one or more list items, and an end tag. 
  1435. Definition and parameter list items are unique in that they consist of two 
  1436. parts. 
  1437.  
  1438. The begin tags/end tags are :sl./:esl., :ul./:eul., :ol./:eol., :dl./:edl., and 
  1439. :parml./:eparml. for simple, unordered, ordered, definition, and parameter 
  1440. lists respectively.  List items for the first three types are specified using 
  1441. the :li. tag. Definition list terms are specified using the :dt. tag, and the 
  1442. corresponding definitions using the :dd. tag.  Parameter list items are 
  1443. specifies using the :pt. tag and - like the definition lists - each item has a 
  1444. corresponding definition specified using the :pd. tag. 
  1445.  
  1446. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1447. :sl [compact].
  1448. :li.text
  1449. :esl.
  1450.  
  1451. :ul [compact].
  1452. :li.text
  1453. :eul.
  1454.  
  1455. :ol [compact].
  1456. :li.text
  1457. :eol.
  1458.  
  1459. :dl [tsize=value][compact][break={ all | none | fit }].
  1460. [:dthd.text]
  1461. [:ddhd.text]
  1462. :dt.text
  1463. :dd.text
  1464. :edl.
  1465.  
  1466. :parml [tsize=value][compact][break={ all | none | fit }].
  1467. :pt.text
  1468. :pd.text
  1469. :eparml.
  1470. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1471. Figure 9.  List tags syntax 
  1472.  
  1473. Below are some examples of lists. 
  1474.  
  1475. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1476. :sl.
  1477. :li.Simple list item 1
  1478. :li.Simple list item 2
  1479. :li.Simple list item 3
  1480. :esl.
  1481.  
  1482. :ul.
  1483. :li.Unordered list item 1
  1484. :li.Unordered list item 2
  1485. :li.Unordered list item 3
  1486. :eul.
  1487.  
  1488. :ol.
  1489. :li.Ordered list item 1
  1490. :li.Ordered list item 2
  1491. :li.Ordered list item 3
  1492. :eol.
  1493.  
  1494. :dl.
  1495. :dt.Term 1
  1496. :dd.Definition 1
  1497. :dt.Term 2
  1498. :dd.Definition 2
  1499. :dt.Term 3
  1500. :dd.Definition 3
  1501. :edl.
  1502.  
  1503. :parml.
  1504. :pt.Parameter 1
  1505. :pd.Definition 1
  1506. :pt.Parameter 2
  1507. :pd.Definition 2
  1508. :pt.Parameter 3
  1509. :pd.Definition 3
  1510. :eparml.
  1511. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1512. Figure 10.  Examples of list markup 
  1513.  
  1514. The above are formatted as: 
  1515.  
  1516. Simple list item 1 
  1517.  
  1518. Simple list item 2 
  1519.  
  1520. Simple list item 3 
  1521.  
  1522. o Unordered list item 1 
  1523.  
  1524. o Unordered list item 2 
  1525.  
  1526. o Unordered list item 3 
  1527.  
  1528.  1. Ordered list item 1 
  1529.  
  1530.  2. Ordered list item 2 
  1531.  
  1532.  3. Ordered list item 3 
  1533.  
  1534. Term 1    Definition 1 
  1535.  
  1536. Term 2    Definition 2 
  1537.  
  1538. Term 3    Definition 3 
  1539.  
  1540. Parameter 1 
  1541.           Definition 1 
  1542.  
  1543. Parameter 2 
  1544.           Definition 2 
  1545.  
  1546. Parameter 3 
  1547.           Definition 3 
  1548.  
  1549. All lists accept the attribute compact which specifies that items should not be 
  1550. separated by blank lines.  Definition and parameter lists also accept the 
  1551. attributes tsize=value and break=[all | fit | none].  tsize specifies the width 
  1552. of the term column in units of the average character width of the current font. 
  1553. break specifies what is to be done when the term exceeds the column width; the 
  1554. default is none and starts the definition after the term preceeded by a space. 
  1555. all specifies that all definitions begin on a new line indented by the term 
  1556. column width. fit specifies that definitions whose terms exceed the column 
  1557. width begin on a new line as in all. 
  1558.  
  1559. Emphasis 
  1560.  
  1561. Emphasis markups consist of a begin and end tag and have the form :hpn.  There 
  1562. are different emphasis levels, ranging from 1 to 9, which is specified as n. 
  1563.  
  1564. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1565. :hpn.
  1566. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1567. Figure 11.  Emphases tag syntax 
  1568.  
  1569. Level               Meaning 
  1570. 1                   Italic 
  1571. 2                   Bold 
  1572. 3                   Italicized bold 
  1573. 4                   Alternate color 1 
  1574. 5                   Underlined 
  1575. 6                   Underlined italic 
  1576. 7                   Underlined bold 
  1577. 8                   Alternate color 2 
  1578. 9                   Alternate color 3 
  1579.  
  1580. Emphasis markup has no attributes. 
  1581.  
  1582. Hypertext 
  1583.  
  1584. Ever since online documentation became all-the-rage, one of the greatest 
  1585. advantages that it touted was the elimination of the phrase "For more 
  1586. information, see page...".  Hypertext - as it was termed - is the ability to 
  1587. jump from one point to another by performing some action (usually a click of 
  1588. the mouse) on a hot-link; these hot-links are usually a word or phrase that has 
  1589. more, related information associated with it that the user will supposedly want 
  1590. to read eventually but without cluttering up the topic already being read. 
  1591.  
  1592. Hypertext in IPF markup is accomplished using the :link. tag and its 
  1593. corresponding end tag. 
  1594.  
  1595. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1596. :link reftype={ fn | hd | launch | inform } [res=value][refid=value]
  1597.    [object='value'][data='value'][x=value y=value cx=value cy=value].
  1598. :elink.
  1599. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1600. Figure 12.  Hypertext tag syntax 
  1601.  
  1602. The type of the link destination is specified by the reftype parameter.  It can 
  1603. have one of the following values: 
  1604.  
  1605. fn                  Footnote.  The footnote must have an id attribute which is 
  1606.                     specified in the refid parameter. 
  1607. hd                  Panel.  The panel must have either an id or a resource id 
  1608.                     specified using the id and res attributes, respectively. 
  1609.                     This identifier is specifies in the refid and res 
  1610.                     attributes of the link tag. 
  1611. launch              Application.  The application, whose full path, name, and 
  1612.                     extension must be specified in the object attribute is 
  1613.                     executed.  Any command line parameters may be specified in 
  1614.                     the data attribute. 
  1615. inform              Message.  This is applicable to online help only.  The 
  1616.                     active window is sent an HM_INFORM message with the value 
  1617.                     of the res attribute passed in mpParm1. 
  1618.  
  1619. Hypertext links can be used to allow access to panels displayed elsewhere or 
  1620. not displayed at all; for example, suppose that you are on heading level 3 and 
  1621. you have some indirectly related information that you want to avoid cluttering 
  1622. the panel with.  You cannot make it a heading level 4 because it won't show up 
  1623. in the table of contents.  Linking makes a lot of sense here; make the target 
  1624. panel heading hidden and level 1 (to avoid nonsensical error messages from the 
  1625. compiler) and then link it to allow the user to read the information only if 
  1626. desired. 
  1627.  
  1628. Graphics 
  1629.  
  1630. Graphics can be included in your documents also; both OS/2 bitmaps and 
  1631. metafiles are supported.  I have found it useful to use a screen capture 
  1632. program to export a bitmap of my application to a file, annotate it with a 
  1633. graphical editor, and then include it in the online help to label the items of 
  1634. interest.  The tag that is used is the :artwork.. tag. 
  1635.  
  1636. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1637. :artwork name='filename' [runin][linkfile='filename']
  1638.    [align={ left | center | right }]
  1639. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1640. Figure 12.  Hypertext tag syntax 
  1641.  
  1642. name specifies the filename containing the bitmap or metafile. runin specifies 
  1643. that the graphic does not force an newline before and after the graphic.  align 
  1644. specifies the justification of the graphic.  linkfile is for graphical linking 
  1645. (called hypergraphics) and will not be discussed. 
  1646.  
  1647. Select this to go to the next section 
  1648.  
  1649.  
  1650. ΓòÉΓòÉΓòÉ 4.2.6. The Extra Mile ΓòÉΓòÉΓòÉ
  1651.  
  1652. Okay, so you've completely enabled your application to use online help...or 
  1653. have you?  Actually, with the exception of rare applications, there is one more 
  1654. area that needs to be covered and that is message box help. 
  1655.  
  1656. Message boxes are modal dialogs that contain information for the user - error 
  1657. messages, usually.  However, there is only so much that you can say in a 
  1658. message box; so, there is a style that you can specify on the call to 
  1659. WinMessageBox() that says to add a Help pushbutton. Fine, so you have a Help 
  1660. pushbutton.  The user selects it.  Nothing happens.  What goes on under the 
  1661. covers? 
  1662.  
  1663. Hooks 
  1664.  
  1665. What goes on is that the message box receives the WM_HELP message and, because 
  1666. it can't determine the window that called WinMessageBox() (for more information 
  1667. on why this is so, read the documentation for WinLoadDlg() and pay attention to 
  1668. the part about determining the real owner of a dialog), it sends the message to 
  1669. the help hook. 
  1670.  
  1671. What is a help hook?  Well, a hook in general is a function that gets called by 
  1672. an application (or, in this case, the system) when specific types of events 
  1673. occur; thus, a help hook is a function that receives notification of 
  1674. help-related events. 
  1675.  
  1676. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1677. BOOL EXPENTRY helpHook(HAB habAnchor,
  1678.                        SHORT sMode,
  1679.                        SHORT sTopic,
  1680.                        SHORT sSubTopic,
  1681.                        PRECTL prclPosition);
  1682. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  1683. Figure 13.  Help hook function prototype 
  1684.  
  1685. habAnchor           Specifies the anchor block of the thread to receive the 
  1686.                     message 
  1687.  
  1688. sMode               Specifies the context of the help request.  The values and 
  1689.                     the contexts are: 
  1690.  
  1691.    HLPM_FRAME          When the parent of the focus window is an FID_CLIENT 
  1692.                        window. sTopic is the frame window id, sSubTopic is the 
  1693.                        focus window id, and prclPosition points to the screen 
  1694.                        coordinates of the focus window. 
  1695.  
  1696.    HLPM_WINDOW         When the parent of the focus window is not an FID_CLIENT 
  1697.                        window.  sTopic is the focus window's parent id, 
  1698.                        sSubTopic and prclPosition have the same meaning as 
  1699.                        HLPM_FRAME. 
  1700.  
  1701.    HLPM_MENU           When the application is in menu mode.  sTopic contains 
  1702.                        the active action bar item id, sSubTopic contains the id 
  1703.                        of the menu item with the cursor, or -1 if the action 
  1704.                        bar has the cursor. 
  1705.  
  1706. In message boxes, the Help pushbutton is not defined with the BS_NOPOINTERFOCUS 
  1707. style, so it has the focus after it is selected. According to the rules, the 
  1708. help hook should get HLPM_WINDOW for the mode and the various identifiers in 
  1709. the other parameters.  However, this is not the case; the help hook does indeed 
  1710. receive HLPM_WINDOW as the mode, but the sTopic parameter is the number 
  1711. specified as the fifth parameter to WinMessageBox() (the help button 
  1712. identifier). sSubTopic always contains the value 1.  I have not verified if 
  1713. prclPosition points to the screen coordinates of the focus window. 
  1714.  
  1715. Before we can utilitize this information, we need to install the help hook 
  1716. using the WinSetHook() function. (Don't forget to uninstall it before the 
  1717. application exits using the WinReleaseHook() function.)  Since the Help Manager 
  1718. works by installing its own help hook, and since WinSetHook() puts the hook at 
  1719. the beginning of the hook chain, you need to remember two things:  1) install 
  1720. your hook after calling WinCreateHelpInstance(), and 2) always return FALSE to 
  1721. insure that the next hook in the chain is called. 
  1722.  
  1723. As an ending note, someone sent me a while back, detailed instructions on a 
  1724. short cut which - if I remember correctly - eliminated the need for help hooks 
  1725. to provide message box help.  Unfortunately, I lost these notes. 
  1726.  
  1727. Select this to go to the next section 
  1728.  
  1729.  
  1730. ΓòÉΓòÉΓòÉ 4.2.7. Epilogue ΓòÉΓòÉΓòÉ
  1731.  
  1732. Now that we have all of the necessary information, we can start developing our 
  1733. online help and documents.  To compile your IPF source, the Developer's Toolkit 
  1734. contains the IPFC compiler.  It takes an IPF source file as input and compiles 
  1735. it to a HLP binary file in the same directory.  For online documents, you need 
  1736. to specify the /INF switch which instead produces an INF binary file in the 
  1737. same directory. 
  1738.  
  1739. You will probably notice some limitations with the compiler. 
  1740.  
  1741. o There is no symbolic substition a la the C preprocessor 
  1742.  
  1743. o Numbers can only be expressed in decimal 
  1744.  
  1745. o All artwork must be in the same directory as the source 
  1746.  
  1747. The first one got so frustrating that I wrote my own IPFC preprocessor which 
  1748. processes C-style include files and allows you to substitute the #define macros 
  1749. in your IPF source as though it were a symbol.  This preprocessor is included, 
  1750. as well as the accompanying User's Guide (in INF format, of course).  The 
  1751. latter two problems could also be resolved by adding functionality to the 
  1752. preprocessor, but those features were never implemented. 
  1753.  
  1754. Select this to go to the next section 
  1755.  
  1756.  
  1757. ΓòÉΓòÉΓòÉ 4.2.8. Summary ΓòÉΓòÉΓòÉ
  1758.  
  1759. Whew!  A lot of information was presented here.  Hopefully, you should be able 
  1760. to reread the objectives of this article and know the answers to the implied 
  1761. questions therein.  The importance of online help cannot be understressed 
  1762. because as computer systems and applications become more complex, the more 
  1763. difficult it becomes to remember every feature that is provided.  Online 
  1764. documentation is also important in that it provides a good vehicle for 
  1765. information dissemination and saves trees. 
  1766.  
  1767. Select this to go to the next section 
  1768.  
  1769.  
  1770. ΓòÉΓòÉΓòÉ 4.3. OS/2 Installable File Systems - Part 2 ΓòÉΓòÉΓòÉ
  1771.  
  1772.                             Written by Andre Asselin
  1773.  
  1774. Select this to go to the next section 
  1775.  
  1776.  
  1777. ΓòÉΓòÉΓòÉ 4.3.1. Introduction ΓòÉΓòÉΓòÉ
  1778.  
  1779. Last time I went over some of the background information needed to write an 
  1780. IFS.  In this article, I'll continue on and examine a framework to write a 
  1781. split ring 0/ring 3 IFS.  This month I'm going to limit myself to just the code 
  1782. that does initialization and communication between ring 0 and ring 3; it's 
  1783. complicated enough to warrant a full article of it own.  The things we will 
  1784. cover are: 
  1785.  
  1786. o How an IFS initializes 
  1787. o How to communicate between ring 0 and ring 3 
  1788. o How a request to the IFS gets handed up to the control program 
  1789.  
  1790. This article is going to assume that you're familiar with the concepts of 
  1791. programming at ring 0.  If this seems a little scary, take heart - the next 
  1792. article will finally get down to implementing the actual FS_* calls, and will 
  1793. concentrate mostly on ring 3 code. 
  1794.  
  1795. Select this to go to the next section 
  1796.  
  1797.  
  1798. ΓòÉΓòÉΓòÉ 4.3.2. Project Layout ΓòÉΓòÉΓòÉ
  1799.  
  1800. The source code for the project is divided up into two directories, RING0 and 
  1801. RING3 (included as IFSR0.ZIP and IFSR3.ZIP - Editor); RING0 holds the ring 0 
  1802. source, and RING3  hold the ring 3 source.  As I mentioned last time, all IFS's 
  1803. must be 16-bit code, so for the source in the RING0 directory, I'm using 
  1804. Borland C++ 3.1.  The ring 3 side is 32-bit code, however, so for it I'm using 
  1805. Borland C++ for OS/2.  I haven't tried this code on any other compilers, but it 
  1806. should be easily portable.  One thing to note is that I'm compiling the code in 
  1807. C++ mode and using the C++ extensions for one line comments and anonymous 
  1808. unions (see for example R0R3SHAR.H).  I also use one Borland #pragma for 
  1809. forcing enumerations to be 16 bits.  With a few modifications, this source 
  1810. should work with any ANSI C compiler. 
  1811.  
  1812. The contents of the RING0 directory are: 
  1813.  
  1814. C0.ASM              Stripped down Borland C++ startup code 
  1815. FSD.H               FS_* call prototypes and data structures 
  1816. FSH.H               FSH_* call prototypes and data structures 
  1817. FSHELPER.LIB        Import library for file system helpers 
  1818. OS216.H             Header file for 16-bit OS/2 Dos APIs 
  1819. R0.CFG              Borland C++ configuration file 
  1820. R0.DEF              Definition file for the linker 
  1821. R0.MAK              Make file for the IFS 
  1822. R0COMM.C            Routines to communicate with the control program 
  1823. R0DEVHLP.ASM        DevHlp interface routines 
  1824. R0DEVHLP.H          Header file for DevHlp interface routines 
  1825. R0GLOBAL.C          Global variable definitions 
  1826. R0GLOBAL.H          Global variable declarations 
  1827. R0INC.H             Main include file 
  1828. R0R3SHAR.H          Shared data structures between the IFS and control program 
  1829. R0STRUCT.H          IFS private structures 
  1830. R0STUBS.C           FS_* stub routines 
  1831.  
  1832. The contents of the RING3 directory are: 
  1833.  
  1834. FSATT.C             Sample attach program 
  1835. FSD.H               FS_ call prototypes and data structures 
  1836. R0R3SHAR.H          Shared data structures between the IFS and control program 
  1837. R3.CFG              Borland C++ configuration file 
  1838. R3.MAK              Make file for the control program 
  1839. R3COMM.C            Routines to communicate with the IFS 
  1840. R3GLOBAL.H          Global variable declarations 
  1841. R3INC.H             Main include file 
  1842. R3STUBS.C           FS_* stub routines 
  1843.  
  1844. The two directories are laid out pretty similarly.  Some notes on the files: 
  1845.  
  1846. o The Rx.MAK file is the make file for the directory, and also generates the 
  1847.   Rx.CFG file, which contains all the compiler switches for the compiler. 
  1848.  
  1849. o RxGLOBAL.H contains declarations for all of the global variables used.  The 
  1850.   IFS side also has R0GLOBAL.C which defines all of the global variables.  The 
  1851.   control program side doesn't have a corresponding R3GLOBAL.C because it only 
  1852.   has one global variable that I thought was better put in R3STUBS.C. 
  1853.  
  1854. o FSD.H and FSH.H are slightly modified versions of the files by the same name 
  1855.   distributed with the IFS documentation.  They are modified slightly to 
  1856.   accommodate C++ and some clashes in naming conventions. 
  1857.  
  1858. o R0R3SHAR.H contains definitions for the data structures that the IFS and 
  1859.   control program share between themselves.  This file is a bit tricky to write 
  1860.   because you have to get the same results no matter if you compile with a 
  1861.   16-bit or 32-bit compiler.  This means for example, that you have to 
  1862.   explicitly declare all your int's long or short so that both compilers do the 
  1863.   same thing. 
  1864.  
  1865. o In order to call the DevHlp's from C, we need to write interface functions 
  1866.   for them.  Files RING0\R0DEVHLP.H and RING0\R0DEVHLP.ASM contain the 
  1867.   prototypes and assembler functions for the DevHlp's that are used in the 
  1868.   code.  The functions use the same parameter ordering as the ones in Steve 
  1869.   Mastrianni's book "Writing OS/2 2.0 Device Drivers in C", although some of 
  1870.   the typedefs and semantics are a bit different.  I'd like to thank him for 
  1871.   graciously allowing me to use the same parameter layouts. 
  1872.  
  1873. Select this to go to the next section 
  1874.  
  1875.  
  1876. ΓòÉΓòÉΓòÉ 4.3.3. Communicating Between Ring 0 and Ring 3 ΓòÉΓòÉΓòÉ
  1877.  
  1878. The easiest and fastest way for ring 0 and ring 3 code to communicate is 
  1879. through shared memory.  The way I implemented it is to have the control program 
  1880. allocate two buffers when it initializes:  one buffer is used to hold all the 
  1881. parameters for a given operation, and the other serves as a data buffer to hold 
  1882. data for operations like FS_WRITE.  After allocating the buffers, it makes a 
  1883. special call to the IFS, which sets up a GDT alias for itself (we need to use 
  1884. GDT selectors because the IFS can be called in the context of any process).  In 
  1885. more detail, what we do is: 
  1886.  
  1887. When the IFS loads 
  1888.  
  1889. Call the AllocGDTSelector DevHlp to allocate two GDT selectors. These will be 
  1890. the selectors used by the IFS to get access to the control program's two 
  1891. buffers.  We allocate them now because GDT selectors can only be allocated at 
  1892. initialization time. 
  1893.  
  1894. When the control program loads 
  1895.  
  1896. o Call DosAllocMem() to allocate memory for the two buffers to communicate 
  1897.   between the IFS and the control program. 
  1898.  
  1899. o Call the IFS via DosFSCtl() and pass the addresses of the two buffers. 
  1900.  
  1901. o The IFS calls the VMLock DevHlp to lock the buffers permanently into memory 
  1902.   (we need to do this because the next call requires it). 
  1903.  
  1904. o Call the LinToGDTSelector DevHlp to map the memory to the GDT selectors we 
  1905.   allocated when the IFS loaded. 
  1906.  
  1907. This isn't the only way we could've implemented this.  We could've had the IFS 
  1908. allocate the memory, for example, instead of the control program.  It really 
  1909. comes down to personal preference, because either works just as well. 
  1910.  
  1911. Select this to go to the next section 
  1912.  
  1913.  
  1914. ΓòÉΓòÉΓòÉ 4.3.4. A Shared Memory Protocol ΓòÉΓòÉΓòÉ
  1915.  
  1916. Once the buffers are allocated and accessible to both the ring 0 and ring 3 
  1917. code, we need to set up some kind of protocol for its use.  The control program 
  1918. needs to know when a valid operation is in the buffers and ready to be 
  1919. performed.  The IFS needs to know when the buffers are in use, and when the 
  1920. buffers contain the results of a completed operation.  Again, there are several 
  1921. ways to implement this.  The method I chose involves using semaphores and 
  1922. captive threads. 
  1923.  
  1924. After the control program allocates the buffers and does any other 
  1925. initialization, it calls the IFS through DosFSCtl().  The IFS sets up the ring 
  1926. 0 GDT aliases for the buffers, and then suspends the control program's thread 
  1927. by making it wait on a semaphore (thus capturing it). To the control program, 
  1928. it just looks like it made a system call that is taking a very long time. 
  1929.  
  1930. When a request comes in to the IFS on another thread, it places the parameters 
  1931. and data into the two buffers and releases the semaphore that the control 
  1932. program's thread is blocked on.  When that thread starts running again, the IFS 
  1933. returns from the DosFSCtl() call to the control program, where it executes the 
  1934. operation and places the results back into the buffer.  It then calls the IFS 
  1935. again, which blocks the control program on the semaphore and starts the whole 
  1936. process over again. 
  1937.  
  1938. The advantage of this approach is that whenever the control program is running, 
  1939. it is guaranteed to have a valid operation in the buffer waiting to be 
  1940. executed.  Thus you never have to worry about semaphores in the control 
  1941. program.  This is especially nice because 16-bit and 32-bit semaphores are 
  1942. incompatible. 
  1943.  
  1944. Select this to go to the next section 
  1945.  
  1946.  
  1947. ΓòÉΓòÉΓòÉ 4.3.5. The Semaphores ΓòÉΓòÉΓòÉ
  1948.  
  1949. Even though the control program doesn't have to worry about semaphores, the IFS 
  1950. certainly does, and in a big way.  It has to worry about serializing all the 
  1951. requests it gets, and handling things like the control program unexpectedly 
  1952. terminating.  To do this, we employ four semaphores: 
  1953.  
  1954. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  1955. ΓöéName                     ΓöéMnemonic                 ΓöéStates                   Γöé
  1956. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1957. ΓöéCPAttached               ΓöéControl Program Attached Γöé-1 = never attached, 0 = Γöé
  1958. Γöé                         Γöé                         Γöénot currently attached, 1Γöé
  1959. Γöé                         Γöé                         Γöé= attached               Γöé
  1960. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1961. ΓöéBufLock                  ΓöéShared buffers are lockedΓöéClear = buffers not      Γöé
  1962. Γöé                         Γöé                         Γöélocked, Set = buffers areΓöé
  1963. Γöé                         Γöé                         Γöélocked                   Γöé
  1964. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1965. ΓöéCmdReady                 ΓöéCommand ready to execute ΓöéClear = command ready,   Γöé
  1966. Γöé                         Γöé                         ΓöéSet = command not ready  Γöé
  1967. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1968. ΓöéCmdComplete              ΓöéCommand is complete      ΓöéClear = command is       Γöé
  1969. Γöé                         Γöé                         Γöécomplete, Set = command  Γöé
  1970. Γöé                         Γöé                         Γöénot complete             Γöé
  1971. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1972.  
  1973. CPAttached is used to indicate whether the control program is currently 
  1974. attached to the IFS.  A value of -1 indicates that it has never attached to the 
  1975. IFS, 0 means it currently is not attached, but has been in the past, and 1 
  1976. means it currently is attached.  This semaphore is unique in that it is not a 
  1977. system semaphore, but an int that is being used as a semaphore. The reason we 
  1978. need to implement it this way will become clear when we start discussing the 
  1979. code. 
  1980.  
  1981. BufLock is used to serialize requests to the IFS.  Whenever the IFS gets a 
  1982. request, the request thread blocks on this semaphore until it's clear, at which 
  1983. time it knows that its OK to use the shared buffers to initiate the next 
  1984. operation. 
  1985.  
  1986. CmdReady is the semaphore used to tell the control program that a request is in 
  1987. the shared buffers and is ready to execute.  The control program thread blocks 
  1988. on this semaphore; a request thread clears this semaphore when a request is 
  1989. ready. 
  1990.  
  1991. CmdComplete indicates to the request thread that the command it initiated is 
  1992. complete and that the results are in the shared buffers.  It is cleared by the 
  1993. control program thread when it calls back into the IFS after it completes an 
  1994. operation. 
  1995.  
  1996. Select this to go to the next section 
  1997.  
  1998.  
  1999. ΓòÉΓòÉΓòÉ 4.3.6. IFS Initialization ΓòÉΓòÉΓòÉ
  2000.  
  2001. When OS/2 is booting and finds an IFS= line in the CONFIG.SYS, it will check 
  2002. that the file specified is a valid DLL and that it exports all of the required 
  2003. entry points for IFS's.  If it is not a valid IFS, OS/2 will put up a message 
  2004. and refuse to load it.  If the IFS is valid, OS/2 will load it into global 
  2005. system memory and then initialize it by calling FS_INIT (note that if the IFS 
  2006. has a LibInit routine, it will be ignored). 
  2007.  
  2008. RING0\R0COMM.C contains the code for the FS_INIT routine.  Just like device 
  2009. drivers, IFS's get initialized in ring 3. Because of the special state of the 
  2010. system, an IFS can make calls to a limited set of Dos APIs (see table 1  for a 
  2011. list of which ones are allowed).  It can also call any of the DevHlp routines 
  2012. that are valid at initialization time, but it cannot call any of the file 
  2013. system helpers. 
  2014.  
  2015. FS_INIT gets passed a pointer to the parameters on the IFS=  line and a pointer 
  2016. to the DevHlp entry point.  The third parameter is used to communicate between 
  2017. the IFS and the system's mini-IFS; we can safely ignore it. 
  2018.  
  2019. The first thing our IFS does is call DosPutMessage() to put up a sign-on 
  2020. message (it's a good idea to put up a message like this while you are still 
  2021. debugging the IFS, but you should take it out in release versions).  After the 
  2022. sign-on banner is printed, we call a special routine to initialize the C 
  2023. runtime environment.  This is a stripped down version of the startup code that 
  2024. comes with Borland C++; all it does is zero the BSS area and call any #pragma 
  2025. startup routines. Strictly speaking, it is probably not necessary. 
  2026.  
  2027. Next we save any parameters that were on the IFS= line in a global buffer and 
  2028. save the address of the DevHlp entry point.  Note that contrary to what the IFS 
  2029. reference says, we have to check the szParm  pointer before using it because it 
  2030. will be NULL if there are no parameters.  The reference leads you to believe 
  2031. that it will point to an empty string, but that isn't true. 
  2032.  
  2033. Next we allocate a small block of memory in the system portion of the linear 
  2034. address space with the VMAlloc DevHlp (the system portion is global to all 
  2035. processes, just like GDT selectors).  This memory will be used to hold the two 
  2036. lock handles that are created by the VMLock DevHlp when we lock down the memory 
  2037. that is shared between the control program and the IFS.  We have to allocate 
  2038. the lock handles in the linear address range because VMLock can only put its 
  2039. lock handles there.  Since our code is 16-bit, the compiler doesn't know what a 
  2040. linear address is.  We deal with them by creating a new typedef, LINADDR, which 
  2041. is just an unsigned long. 
  2042.  
  2043. Next we also allocate two GDT selectors to alias the shared memory on the ring 
  2044. 0 side.  This is done here because according to the PDD reference, you can only 
  2045. allocate GDT selectors at initialization time (in fact, if you do it after 
  2046. initialization, it still works, but why take the chance, right ?).  We then 
  2047. create pointers out of the GDT selectors and assign them to the two global 
  2048. variables used to access the shared buffers.  Note that at this point, no 
  2049. memory is allocated!  We have our pointers set up, but if we were to try and 
  2050. access them, we'd get a TRAP D. We must wait for the control program to start 
  2051. and call the IFS before we can put memory behind those GDT selectors. 
  2052.  
  2053. After that's done, we set CPAttached  to -1, which says that the control 
  2054. program has never attached to the IFS.  We'll see later why its important to 
  2055. distinguish between when it has never attached, and when it has attached but 
  2056. then detached. 
  2057.  
  2058. Select this to go to the next section 
  2059.  
  2060.  
  2061. ΓòÉΓòÉΓòÉ 4.3.7. Control Program Flow ΓòÉΓòÉΓòÉ
  2062.  
  2063. RING3\R3COMM.C contains the code to startup the control program. It first 
  2064. prints a banner, just like the IFS, and then allocates and commits memory for 
  2065. the two buffers.  Once that is done, it puts the pointers to the two blocks of 
  2066. memory in the structure that is passed to the IFS for initialization.  Before 
  2067. we call the IFS, though, we make a copy of the file system name in a temporary 
  2068. buffer.  The DosFSCtl() call can use three different methods to figure out 
  2069. which IFS to call; we want to use the method where we specify the IFS's name. 
  2070. To do that we have to make a temporary copy of the IFS name because DosFSCtl 
  2071. could modify the buffer that contains the IFS name. 
  2072.  
  2073. Once all the preparations are made, the control program calls the IFS to 
  2074. initialize.  To the control program it's really no big deal - just one 
  2075. DosFSCtl() call.  When the DosFSCtl() returns, it will either be because there 
  2076. was an initialization error, or there was an operation waiting in the shared 
  2077. buffers to be executed.  If an error occurred, we just terminate the control 
  2078. program (perhaps a more user friendly error message should be printed, but 
  2079. after all, this is just a framework).  If it returned because an operation is 
  2080. ready, we enter the dispatch loop. 
  2081.  
  2082. The dispatch loop figures out what operation was requested, and calls that 
  2083. routine to execute it.  Right now we only support the attach routine (which is 
  2084. actually just a stub that returns NO_ERROR).  If it gets a request for an 
  2085. operation it doesn't understand, it prints an error message and returns 
  2086. ERROR_NOT_SUPPORTED to the IFS. 
  2087.  
  2088. Once the operation has been executed, we again copy the IFS name into a 
  2089. temporary buffer and make a DosFSCtl() call to indicate that this operation is 
  2090. complete, the results are in the shared buffer, and we're ready for the next 
  2091. request.  When that DosFSCtl() returns, another operation will be waiting in 
  2092. the shared buffer. 
  2093.  
  2094. Select this to go to the next section 
  2095.  
  2096.  
  2097. ΓòÉΓòÉΓòÉ 4.3.8. Ring 0 Side of Control Program Initialization ΓòÉΓòÉΓòÉ
  2098.  
  2099. As mentioned above, the ring 3 side of the control program initialization is 
  2100. very simple.  The ring 0 side is a little more complicated, though. FS_FSCTL in 
  2101. RING0\R0COMM.C contains the code for the initialization.  FS_FSCTL is used to 
  2102. provide an architected way to add IFS specific calls (sort of like the IOCTL 
  2103. interface for devices).  There are three standard calls, which we just ignore 
  2104. for now.  To those we add two new calls, FSCTL_FUNC_INIT and FSCTL_FUNC_NEXT. 
  2105. FSCTL_FUNC_INIT is called by the control program when it initializes. 
  2106. FSCTL_FUNC_NEXT is called when the control program has completed an operation 
  2107. and its ready for the next one. 
  2108.  
  2109. When FSCTL_FUNC_INIT is called, the first thing we do is check to see if the 
  2110. control program is already attached.  If it is, we return an error code (this 
  2111. scenario could happen if the user tries to start a second copy of the control 
  2112. program).  If the control program isn't already running, we wait until the 
  2113. BufLock semaphore is cleared.  We do this because theoretically, we could run 
  2114. into the following situation:  a request comes into the IFS and it starts 
  2115. servicing it.  The control program is then detached, and then a new copy is run 
  2116. and tries to attach.  The IFS is still in the middle of trying to service that 
  2117. request, however, and hasn't yet noticed the control program detached in the 
  2118. first place.  It could be really bad if that ever did happen because the shared 
  2119. buffers would be corrupted, so we explicitly wait until the BufLock semaphore 
  2120. is clear, meaning that there are no threads using the shared buffers.  We have 
  2121. to surround this with a check to see if the control program has ever been 
  2122. attached, because if it hasn't, the BufLock semaphore will not be initialized. 
  2123.  
  2124. Next we verify that the buffer that was passed to us is the proper size and 
  2125. that it is addressable.  We have to check addressability on everything that is 
  2126. passed in from a ring 3 program because if it is not addressable, we bring down 
  2127. the whole entire system. 
  2128.  
  2129. Once addressability has been verified, we lock down the operation parameter 
  2130. area, and put the returned lock into the memory we allocated at FS_INIT time. 
  2131. Once that is done, we map the memory to the GDT selector that we allocated at 
  2132. FS_INIT time.  We then do the same for the data buffer.  Once these operations 
  2133. are complete, the memory can be shared between the IFS and the control program. 
  2134.  
  2135. Once that is complete, we clear the BufLock semaphore to initialize the 
  2136. semaphore that indicates that the shared buffer is not being used by anyone. 
  2137. We then get the process ID of the control program.  This is used by the FS_EXIT 
  2138. routine.  FS_EXIT is called whenever any process terminates.  We have it check 
  2139. the process ID of the process that is terminating against the process ID of the 
  2140. control program, so that if the control program unexpectedly terminates, we 
  2141. detach it properly. 
  2142.  
  2143. After all that initialization is completed, CPAttached is set to 1 to indicate 
  2144. that the control program is attached.  We then fall through to FSCTL_FUNC_NEXT. 
  2145. Since this function will be called every time an operation is completed, we 
  2146. first ensure that the control program is attached. If it's not, we return an 
  2147. error code.  If it is attached, we first set the CmdReady semaphore to indicate 
  2148. that a command is no longer in the shared buffers (instead, results are in the 
  2149. buffers).  We then clear CmdComplete to unblock the requesting thread (letting 
  2150. it know that its results are waiting).  We then wait on the CmdReady semaphore, 
  2151. which will be cleared when a new operation is put into the shared buffers. 
  2152.  
  2153. At any time, any of the semaphore calls could return ERROR_INTERRUPT if the 
  2154. user is trying to kill the control program. If that occurs, we detach the 
  2155. control program before returning the error code. 
  2156.  
  2157. To detach the control program, we have to first set CPAttached to 0. We have to 
  2158. do it first to avoid possible deadlocks.  We then unlock the shared memory 
  2159. buffers; if we don't do this, the control program will appear to die, but you 
  2160. will never be able to get rid of its window.  Finally, we clear the CmdComplete 
  2161. semaphore so that if there is a request in progress, the requesting thread will 
  2162. unblock. 
  2163.  
  2164. Select this to go to the next section 
  2165.  
  2166.  
  2167. ΓòÉΓòÉΓòÉ 4.3.9. An Example Call: Attaching a Drive ΓòÉΓòÉΓòÉ
  2168.  
  2169. Before you can use a drive managed by your IFS, you have to attach it. This 
  2170. creates an association between a drive letter and the IFS. RING3\FSATT.C 
  2171. contains an example program that attaches a drive. It is basically a front end 
  2172. to the DosFSAttach() and DosQueryFSAttach() calls.  With a little help from the 
  2173. Control Program Programming Reference, you should be able to figure it out 
  2174. easily. 
  2175.  
  2176. The part that needs more explaining is the ring 0 side of the interface. When 
  2177. you issue a DosFSAttach() or DosQueryFSAttach(), the file system router calls 
  2178. the IFS's FS_ATTACH entry point (this can be found in RING0\R0STUBS.C).  This 
  2179. code is basically a prototype for all of the FS_* calls that the IFS handles. 
  2180. It serializes access to the control program, does some preliminary validation 
  2181. of the parameters, sets up the argument block and passes it to the control 
  2182. program, waits until the control program executes the operation, and then 
  2183. returns the results of the operation.  Once the details of this call are 
  2184. understood, all the others can be written pretty easily. 
  2185.  
  2186. The first thing FS_ATTACH does is check to see if the control program is 
  2187. attached; if it isn't, it immediately returns an error code. If the control 
  2188. program is attached, it waits until it can get access to the shared buffers. 
  2189. It is possible to time out waiting for this access; if we do, we return an 
  2190. ERROR_NOT_READY return code to the caller. 
  2191.  
  2192. Once we have access to the shared buffers, we wait until the control program 
  2193. completes the last operation it started.  We have to do this because it is 
  2194. possible for a thread to give the control program a request to service, and 
  2195. then time out waiting for it to complete it.  We could then have another thread 
  2196. come along and try to start a new request, but if the control program hasn't 
  2197. finished the last one yet, the shared buffers will get trashed because the IFS 
  2198. will be trying to put a new operation in them, and the control program will be 
  2199. trying to put the results of the last operation in them.  Therefore we must 
  2200. wait until the control program has finished the last operation. 
  2201.  
  2202. Once those verifications are completed, we check to make sure we can access the 
  2203. buffer that was passed in.  For an attach or detach request, all we have to do 
  2204. is check for readability, but for the query attach request, we have to check 
  2205. writability. 
  2206.  
  2207. We then check that the control program is still attached.  This check is 
  2208. crucial because during any of those semaphore or FSH_PROBEBUF calls we could've 
  2209. blocked, and the control program could've terminated. If it did, the shared 
  2210. buffers are no longer valid, and if we try to access them we will trap.  It's 
  2211. for this reason that the CPAttached semaphore is an int and not a system 
  2212. semaphore - the semaphore calls don't guarantee that they won't block (i.e. 
  2213. they could block).  To make absolutely sure, the only thing we can rely on is a 
  2214. semaphore implemented as an int (it's probably worthwhile to refresh your 
  2215. memory here that ring 0 code will never be multitasked - you have to explicitly 
  2216. give up the CPU). 
  2217.  
  2218. Once we have verified that the control program is still attached, and thus our 
  2219. shared buffers are still valid, we setup the shared buffers with the 
  2220. operation's parameters.  You can refer to R0R3SHAR.H (in either RING0 or RING3) 
  2221. for the data structure used.  After that's complete, we clear the CmdReady 
  2222. semaphore to unblock the control program and indicate to it that a request is 
  2223. ready to be executed.  We then block on CmdComplete waiting for the control 
  2224. program to execute our request.  We specify a time-out to the wait so that we 
  2225. never get hung up on a faulty control program (if you never want to time out, 
  2226. you can change the value of MAXCPRESWAIT to -1).  If we should time out, we 
  2227. release our hold on the shared buffer by clearing BufLock, and then return 
  2228. ERROR_NOT_READY. 
  2229.  
  2230. After the wait returns and we check for a time out, we also check to make sure 
  2231. the control program is still attached.  It is possible that while the control 
  2232. program was executing our request that it terminated (maybe we had a bug that 
  2233. caused it to trap).  If so, the shared buffers are no longer accessible, so we 
  2234. return an error code to the caller.  If all went well, we copy the results out 
  2235. of the result buffers.  Note that while we are doing this, we can't do anything 
  2236. that could cause us to yield because the control program could terminate during 
  2237. that time. 
  2238.  
  2239. After we copy the results out, we free up out hold on the shared buffers by 
  2240. clearing the BufLock semaphore and then return the error code that the control 
  2241. program told us to return. 
  2242.  
  2243. Select this to go to the next section 
  2244.  
  2245.  
  2246. ΓòÉΓòÉΓòÉ 4.3.10. And That's About It ΓòÉΓòÉΓòÉ
  2247.  
  2248. That about covers the communications between the ring 0 and ring 3 sides of an 
  2249. IFS.  If you're daring, you now have all the basics to forge ahead and begin 
  2250. implementing this type of IFS.  If this still seems a little scary, don't worry 
  2251. - in the next article I'll fill in all the rest of the routines to give you a 
  2252. true skeleton to work with, and start discussing how to implement the FS_* 
  2253. calls.  I will also provide a state diagram that shows all of the various 
  2254. states the system can be in, along with the states of the semaphores, to show 
  2255. that no deadlocks will occur in the IFS no matter what happens (this is 
  2256. actually very important because a deadlock is extremely difficult to track 
  2257. down, so you're better off investing time up front making sure they will never 
  2258. occur than beating your head against a wall later trying to track one down). 
  2259.  
  2260. I'd like to thank everyone who has written to encourage me to continue the 
  2261. series or with ideas for topics you'd like me to cover.  Since the only pay I 
  2262. receive is your feedback, I hope you'll continue to write. 
  2263.  
  2264. Select this to go to the next section 
  2265.  
  2266.  
  2267. ΓòÉΓòÉΓòÉ <hidden> Dos APIs Callable at Initialization Time ΓòÉΓòÉΓòÉ
  2268.  
  2269. The following Dos APIs are callable by the IFS at initialization time: 
  2270.  
  2271. o DosBeep 
  2272. o DosChgFilePtr 
  2273. o DosClose 
  2274. o DosDelete 
  2275. o DosDevConfig 
  2276. o DosFindClose 
  2277. o DosFindFirst 
  2278. o DosFindNext 
  2279. o DosGetEnv 
  2280. o DosGetInfoSeg 
  2281. o DosGetMessage 
  2282. o DosOpen 
  2283. o DosPutMessage 
  2284. o DosQCurDir 
  2285. o DosQCurDisk 
  2286. o DosQFileInfo 
  2287. o DosQSysInfo 
  2288. o DosRead 
  2289. o DosWrite 
  2290.  
  2291.  
  2292. ΓòÉΓòÉΓòÉ 4.4. Programming the Container Control - Part 3 ΓòÉΓòÉΓòÉ
  2293.  
  2294.                           Written by Larry Salomon, Jr.
  2295.  
  2296. Select this to go to the next section 
  2297.  
  2298.  
  2299. ΓòÉΓòÉΓòÉ 4.4.1. Back at the Batcave ΓòÉΓòÉΓòÉ
  2300.  
  2301. Last month we continued our disection of the container control and how to use 
  2302. it.  The tree view was added to our list of conquests, and we started 
  2303. developing a sample application which we will continue to use.  This month, we 
  2304. will add more meat to the bones of our skeleton by learning about the detail 
  2305. view and direct editing, among other things. 
  2306.  
  2307. Select this to go to the next section 
  2308.  
  2309.  
  2310. ΓòÉΓòÉΓòÉ 4.4.2. Detail View ΓòÉΓòÉΓòÉ
  2311.  
  2312. Back in the first installment of this series, the detail view was described in 
  2313. the following manner. 
  2314.  
  2315. Each object is represented as a detailed description of the object. The 
  2316. information displayed is defined by the application. 
  2317.  
  2318. While I realize that did not say much, it served to illustrate that the detail 
  2319. view is the most flexible of the views, in terms of what can be displayed.  It 
  2320. should be logical then to assume that this means yet more setup on the part of 
  2321. the application. 
  2322.  
  2323. What is the Detail View? 
  2324.  
  2325. To be precise, the detail view is a matrix view of the contents of a container, 
  2326. where each row in the matrix is a separate object and each column is an 
  2327. attribute (called a field) of every object to be displayed. 
  2328.  
  2329. Since the objects are already added using the CM_ALLOCRECORD/CM_INSERTRECORD 
  2330. messages, the columns must be added; this is done using the 
  2331. CM_ALLOCDETAILFIELDINFO/CM_INSERTDETAILFIELDINFO messages.  As with its 
  2332. record-oriented counterpart, the CM_ALLOCDETAILFIELDINFO accepts the number of 
  2333. fields to allocate memory for and returns a pointer to the first FIELDINFO 
  2334. structure in the linked-list. 
  2335.  
  2336. typedef struct _FIELDINFO {
  2337.    ULONG cb;
  2338.    ULONG flData;
  2339.    ULONG flTitle;
  2340.    PVOID pTitleData;
  2341.    ULONG offStruct;
  2342.    PVOID pUserData;
  2343.    struct _FIELDINFO *pNextFieldInfo;
  2344.    ULONG cxWidth;
  2345. } FIELDINFO, *PFIELDINFO;
  2346.  
  2347. Figure 1.  The FIELDINFO structure. 
  2348.  
  2349. cb                  specifies the size of the structure in bytes. 
  2350.  
  2351. flData              specifies flags (CFA_* constants) for the field, especially 
  2352.                     the datatype. 
  2353.  
  2354. flTitle             specifies flags (CFA_* constants) for the column title. 
  2355.  
  2356. pTitleData          points to a string used for the column heading (can be 
  2357.                     NULL). 
  2358.  
  2359. offStruct           specifies the offset of the data in the container record to 
  2360.                     be formatted according to its datatype.  The FIELDOFFSET 
  2361.                     macro (defined in the Toolkit) is very helpful in 
  2362.                     initializing this field. 
  2363.  
  2364.                     When the datatype is CFA_STRING, the field in the container 
  2365.                     record is expected to be a pointer to the string and not 
  2366.                     the string itself.  For example, 
  2367.  
  2368.                                         typedef struct _MYCNRREC {
  2369.                                            MINIRECORDCORE mrcCore;
  2370.                                            CHAR achText[256];
  2371.                                            ULONG ulNumSold;
  2372.                                            float fGrossIncome;
  2373.                                            float fNetIncome;
  2374.                                            float fTotalCost;
  2375.                                            float fNetProfit;
  2376.                                            CHAR achProdName[256];
  2377.                                            PCHAR pchProdName;
  2378.                                         } MYCNRREC, *PMYCNRREC;
  2379.                     we would specify FIELDOFFSET(MYCNRREC,pchProdName) instead 
  2380.                     of FIELDOFFSET(MYCNRREC,achProdName).  The reason for this 
  2381.                     will be clear when we discuss direct editing. 
  2382.  
  2383. pUserData           points to any application-defined data for the field. 
  2384.  
  2385. pNextFieldInfo      points to the next FIELDINFO structure.  This is 
  2386.                     initialized by the CM_ALLOCDETAILFIELDINFO message. 
  2387.  
  2388. cxWidth             specifies the width in pixels of the field.  This is 
  2389.                     initialized by the CM_ALLOCDETAILFIELDINFO message to 0, 
  2390.                     indicating that the field should be wide enough to show the 
  2391.                     widest value.  If the default is not used and the data is 
  2392.                     too wide to fit, it is truncated when displayed. 
  2393.  
  2394. The flData field is initialized using one or more CFA_* constants: 
  2395.  
  2396. Data type 
  2397.  
  2398. CFA_BITMAPORICON    offStruct "points" to the handle of a bitmap or icon, 
  2399.                     depending on whether or not CA_DRAWICON or CA_DRAWBITMAP 
  2400.                     was specified in the flWindowAttr field in the 
  2401.                     CM_SETCNRINFO message (CA_DRAWICON is the default if not 
  2402.                     explicitly changed by the application). 
  2403.  
  2404. CFA_STRING          offStruct "points" to a pointer to the string to be 
  2405.                     displayed.  Only data of this type can be directly edited. 
  2406.  
  2407. CFA_ULONG           offStruct "points" to an unsigned long integer. 
  2408.  
  2409. CFA_DATE            offStruct "points" to a CDATE structure. 
  2410.  
  2411. CFA_TIME            offStruct "points" to a CTIME structure. 
  2412.  
  2413. For the latter three, NLS support is provided automatically by the container. 
  2414. You should note that there is no support for short integers, since they map 
  2415. directly to long integers with no loss in precision, nor is there support for 
  2416. floating point (none of PM uses floating point, so why should they start now). 
  2417. The latter means that you have to also have a string representation of the 
  2418. number (and creates all kinds of headaches if you will allow editing of the 
  2419. value). 
  2420.  
  2421. Alignment 
  2422.  
  2423. CFA_LEFT            Align the data to the left 
  2424.  
  2425. CFA_CENTER          Horizontally center the data 
  2426.  
  2427. CFA_RIGHT           Align the data to the right 
  2428.  
  2429. CFA_TOP             Align the data to the top 
  2430.  
  2431. CFA_VCENTER         Vertically center the data 
  2432.  
  2433. CFA_BOTTOM          Align the data to the bottom 
  2434.  
  2435. Miscellaneous 
  2436.  
  2437. CFA_SEPARATOR       Displays a vertical separator to the right of the field 
  2438.  
  2439. CFA_HORZSEPARATOR   Displays a horizontal separator underneath the column 
  2440.                     heading 
  2441.  
  2442. CFA_OWNER           Enables ownerdraw for this field 
  2443.  
  2444. CFA_INVISIBLE       Prevents display of this column 
  2445.  
  2446. CFA_FIREADONLY      Prevents direct editing of the data if CFA_STRING is the 
  2447.                     datatype 
  2448.  
  2449. The flTitle field is initialized using one or more of the alignment fields 
  2450. and/or one or both of the following 
  2451.  
  2452. Miscellaneous 
  2453.  
  2454. CFA_BITMAPORICON    pTitleData is the handle of a bitmap or icon, depending on 
  2455.                     whether or not CA_DRAWICON or CA_DRAWBITMAP was specified 
  2456.                     in the flWindowAttr field in the CM_SETCNRINFO message 
  2457.                     (CA_DRAWICON is the default if not explicitly changed by 
  2458.                     the application).  If this is not specified, pTitleData is 
  2459.                     expected to point to character data. 
  2460.  
  2461. CFA_FITITLEREADONLY the text of the title is not directly editable. 
  2462.  
  2463. What's Next? 
  2464.  
  2465. Once you have initialized all of the FIELDINFO structures, you can "insert" 
  2466. them into the container using the CM_INSERTDETAILFIELDINFO message.  Again 
  2467. using the parallel of the CM_INSERTRECORD message, it expects a pointer to the 
  2468. first FIELDINFO structure as well as a pointer to a FIELDINFOINSERT structure. 
  2469.  
  2470. typedef struct _FIELDINFOINSERT {
  2471.    ULONG cb;
  2472.    PFIELDINFO pFieldInfoOrder;
  2473.    ULONG fInvalidateFieldInfo;
  2474.    ULONG cFieldInfoInsert;
  2475. } FIELDINFOINSERT, *PFIELDINFOINSERT;
  2476.  
  2477. Figure 2.  The FIELDINFOINSERT structure. 
  2478.  
  2479. cb                  specifies the size of the structure in bytes. 
  2480.  
  2481. pFieldInfoOrder     specifies the FIELDINFO structure to be linked after, or 
  2482.                     CMA_FIRST or CMA_LAST to specify that these FIELDINFO 
  2483.                     structures should go to the head/tail of the list, 
  2484.                     respectively. 
  2485.  
  2486. fInvalidateFieldInfo specifies whether or not the fields are to be invalidated. 
  2487.  
  2488. cFieldInfoInsert    specifies the number of FIELDINFO structures being 
  2489.                     inserted. 
  2490.  
  2491. Finally, changing the view to detail view is as simple as - you guessed it - 
  2492. sending the control a CM_SETCNRINFO message. 
  2493.  
  2494.    CNRINFO ciInfo;
  2495.  
  2496.    ciInfo.flWindowAttr=CV_DETAIL;
  2497.    WinSendMsg(hwndCnr,
  2498.               CM_SETCNRINFO,
  2499.               MPFROMP(&ciInfo),
  2500.               MPFROMLONG(CMA_FLWINDOWATTR));
  2501.  
  2502. Figure 3.  Changing to the detail view. 
  2503.  
  2504. Note that, even if you initialize the pTitleData field of the FIELDINFO 
  2505. structure to point to the column heading, the titles are not displayed unless 
  2506. you specify CA_DETAILSVIEWTITLES in the flWindowAttr field. 
  2507.  
  2508. Select this to go to the next section 
  2509.  
  2510.  
  2511. ΓòÉΓòÉΓòÉ 4.4.3. Direct Editing ΓòÉΓòÉΓòÉ
  2512.  
  2513. Direct editing is accomplished by pressing the proper combination of keys 
  2514. and/or mouse buttons as defined in the "Mappings"  page of the "Mouse" 
  2515. settings (in the "OS/2 System"/"System Setup" folder) while the mouse is over a 
  2516. directly-editable region.  When this is done, a multi-line edit control appears 
  2517. and is initialized with the current text, in which you can make your changes; 
  2518. the enter key acts as a newline, while the pad enter key completes the editing 
  2519. operation and (normally) applies the changes. 
  2520.  
  2521. From a programming perspective, three notifications are sent to the application 
  2522. whenever direct-editing is requested by the user when over a non-read-only 
  2523. field ("field" is used here to mean any text string and not as it was defined 
  2524. in the discussion of the detail view) - CN_BEGINEDIT, CN_REALLOCPSZ, and 
  2525. CN_ENDEDIT (in that order).  For all three, mpParm2 points to a CNREDITDATA 
  2526. structure which describes the state of the record being edited.  The purpose of 
  2527. CN_BEGINEDIT and CN_ENDEDIT is to notify the user that editing is about to 
  2528. begin/end.  However, only the CN_REALLOCPSZ is important, since the former two 
  2529. can be ignored while the latter cannot. 
  2530.  
  2531. typedef struct _CNREDITDATA {
  2532.    ULONG cb;
  2533.    HWND hwndCnr;
  2534.    PRECORDCORE pRecord;
  2535.    PFIELDINFO pFieldInfo;
  2536.    PSZ *ppszText;
  2537.    ULONG cbText;
  2538.    ULONG id;
  2539. } CNREDITDATA;
  2540.  
  2541. Figure 4.  The CNREDITDATA structure. 
  2542.  
  2543. cb                  specifies the size of the structure in bytes. 
  2544.  
  2545. hwndCnr             specifies the handle of the container. 
  2546.  
  2547. pRecord             points to the record being edited. 
  2548.  
  2549. pFieldInfo          points to the FIELDINFO structure describing the field 
  2550.                     being edited. 
  2551.  
  2552. ppszText            points to the pointer to the text being edited. 
  2553.  
  2554. cbText              specifies the size of the text. 
  2555.  
  2556. id                  specifies which part of the container contains the text to 
  2557.                     be edited and can be one of the following: 
  2558.                     CID_CNRTITLEWND, CID_LEFTDVWND, CID_RIGHTDVWND, 
  2559.                     CID_LEFTCOLTITLEWND, or CID_RIGHTCOLTITLEWND. 
  2560.  
  2561. The CN_REALLOCPSZ indicates that editing is about to end and that the 
  2562. application should allocate a new block of memory to contain the text. 
  2563. ppszText double-points to the old text and cbText specifies the length of the 
  2564. new text.  If a new memory block is allocated, the pointer to the new memory 
  2565. block must be stored in ppszText. Returning TRUE from this notification 
  2566. indicates that ppszText  points to a memory block sufficiently large enough to 
  2567. hold cbText  bytes and that the container should copy the new text to this 
  2568. buffer.  (I am not sure if cbText  includes the null terminator - `\0') 
  2569. Returning FALSE  indicates that the changes should not be copied and should be 
  2570. discarded. 
  2571.  
  2572. Select this to go to the next section 
  2573.  
  2574.  
  2575. ΓòÉΓòÉΓòÉ 4.4.4. Altered States ΓòÉΓòÉΓòÉ
  2576.  
  2577. As defined by CUA '91 (I think), an object in general can be in one or more of 
  2578. five states (or none at all) - source, target, in-use, cursored, and selected. 
  2579. A container record stores information on its current state in the flRecordAttr 
  2580. (in both the RECORDCORE and MINIRECORDCORE structures) in the form of CRA_* 
  2581. constants.  Setting the state, however, is not a simple matter of setting this 
  2582. field, since the container will have no way of knowing that you've changed the 
  2583. field.  Instead, you send the container a CM_SETRECORDEMPHASIS message which 
  2584. updates this field in the record and updates the display of that record on the 
  2585. screen. 
  2586.  
  2587. Those who are "on the ball" will notice that there is no CRA_SOURCE constant 
  2588. defined in the 2.0 Toolkit.  This was inadvertently left out and should be 
  2589. defined to be 0x00004000L in pmstddlg.h. 
  2590.  
  2591. So what do all of these states mean? 
  2592.  
  2593. CRA_CURSORED        the record has the input focus. 
  2594.  
  2595. CRA_INUSE           the record (and thus the object) is in use by the 
  2596.                     application. 
  2597.  
  2598. CRA_SELECTED        the record is selected for later manipulation. 
  2599.  
  2600. CRA_SOURCE          the record is a source for a direct-manipulation operation. 
  2601.  
  2602. CRA_TARGET          the record is a target for a direct-manipulation operation. 
  2603.  
  2604. When you want to query all records with a particular emphasis type, you use the 
  2605. CM_QUERYRECORDEMPHASIS message.  This returns the next record that has the 
  2606. specifies emphasis (or NULL if none exists). 
  2607.  
  2608. Popup Menus 
  2609.  
  2610. If you take a close look at the Workplace Shell, you will see all of these 
  2611. states used in one way or another.  A more interesting use is in conjunction 
  2612. with popup menus; if the record underneath the mouse is not selected, it alone 
  2613. is given source emphasis.  If it is selected, all records that are selected are 
  2614. given source emphasis.  If no record is underneath the mouse, the container 
  2615. itself is given source emphasis.  After the appropriate record states have been 
  2616. changed, WinPopupMenu() is called.  Finally, the WM_MENUEND message is 
  2617. intercepted to "un-source" the records that were changed.  Broken down into 
  2618. pseudo-code, this becomes: 
  2619.  
  2620.  1. Determine if the mouse is over a container record 
  2621.  
  2622.    o If so, check the selection state 
  2623.  
  2624.       - If the record is selected, add source emphasis to all selected records 
  2625.       - If the record is not selected, give it source emphasis only 
  2626.  
  2627.    o If not, select the enter container 
  2628.  
  2629.  2. Call WinPopupMenu() 
  2630.  3. Undo source emphasis changes 
  2631.  
  2632. While determining if the mouse is over a record is easy when processing the 
  2633. WM_CONTROL message, it is a bit more difficult when in the WM_CONTEXTMENU menu. 
  2634. The solution, it would appear from looking at our arsenal of messages that we 
  2635. can send to the container, would be to send the container a 
  2636. CM_QUERYRECORDFROMRECT message, specifying the mouse position as the rectangle 
  2637. to query.  Looking a bit closer at the documentation reveals that the rectangle 
  2638. has to be specified in virtual  coordinates.  What??? 
  2639.  
  2640. Virtual Coordinates 
  2641.  
  2642. Okay, okay, everyone has probably heard of and is vaguely familiar with virtual 
  2643. coordinates, or else you would not be in PM programming to begin with. The 
  2644. container's notion of the origin in its coordinate system is somewhat awry, 
  2645. unfortunately, and this confuses things; the origin is defined to be the screen 
  2646. coordinate of the lower left corner of the container at the time the last 
  2647. CM_ARRANGE message was sent. 
  2648.  
  2649. So, you either have to keep track of when you send the container a CM_ARRANGE 
  2650. message and perform all sorts of hocus pocus to remember where the origin is 
  2651. supposed to be, or you can finish reading this sentence and discover that the 
  2652. documentation for CM_QUERYRECORDFROMRECT is flat-out wrong.  The rectangle 
  2653. specified in this message is in window coordinates.  Whew!  That greatly 
  2654. simplifies things, except that when in detail view the record returned is the 
  2655. one above the one the mouse is over.  Oh boy.  Fortunately, we can calculate 
  2656. the height of a record using the CM_QUERYRECORDRECT message, which we use to 
  2657. adjust the mouse position before calling CM_QUERYRECORDFROMRECT. 
  2658.  
  2659. Now that we have the record underneath the mouse, we can check its selection 
  2660. state by examining the flRecordAttr field.  If the record is selected, it is 
  2661. probably more efficient to use the CM_QUERYRECORDEMPHASIS message to get all 
  2662. selected records, but we already have this exquisite recursive search function, 
  2663. so I used that instead. Another example of poor documentation is in 
  2664. CM_SETRECORDEMPHASIS where it does not tell you that you can set the 
  2665. container's source emphasis by specifying NULL for the record. 
  2666.  
  2667. Finally, we call WinPopupMenu() and undo the source emphasis and - voila! - 
  2668. we're done. 
  2669.  
  2670. Select this to go to the next section 
  2671.  
  2672.  
  2673. ΓòÉΓòÉΓòÉ 4.4.5. CNR3 - A Sample Application Revisited ΓòÉΓòÉΓòÉ
  2674.  
  2675. CNR3 builds upon CNR2 by adding detail view support, direct editing support, 
  2676. and "proper" popup menu support.  As with part II, landmarks have been added to 
  2677. CNR3.C which are to point out things of interest.  These landmarks are 
  2678. described below. 
  2679.  
  2680. Landmark 1 
  2681.  
  2682. This is to point out the additions of the last four fields to the MYCNREDIT 
  2683. structure and the addition of the pmcrMenu field to the CLIENTDATA structure. 
  2684.  
  2685. Landmark 2 
  2686.  
  2687. This points out the allocation, initialization, and insertion of the FIELDINFO 
  2688. structures. 
  2689.  
  2690. Landmark 3 
  2691.  
  2692. This points out the new procedure for handling the context menu. 
  2693.  
  2694. Landmark 4 
  2695.  
  2696. This points out the correction for the bug in the CM_QUERYRECORDFROMRECT 
  2697. message when in details view as described above. 
  2698.  
  2699. Landmark 5 
  2700.  
  2701. This points out the processing of the CN_REALLOCPSZ notification. 
  2702.  
  2703. Landmark 6 
  2704.  
  2705. This points out the addition of the detail view menu item. 
  2706.  
  2707. Select this to go to the next section 
  2708.  
  2709.  
  2710. ΓòÉΓòÉΓòÉ 4.4.6. Summary ΓòÉΓòÉΓòÉ
  2711.  
  2712. This month we learned a lot of things, namely how to setup the details view, 
  2713. how direct editing is performed and what the container expects from the 
  2714. application with regards to this, and how selection states are set, queried, 
  2715. and used.  We also saw how inadequate the documentation is when it contains so 
  2716. many examples of incorrect or incomplete information. 
  2717.  
  2718. Now you have enough information to use the container well.  However, we're not 
  2719. done yet; next month, I will try to figure out some of the more advanced 
  2720. capabilities of the container such as record sharing and deltas. Stay tuned, 
  2721. same Bat-time, same Bat-channel! 
  2722.  
  2723. Select this to go to the next section 
  2724.  
  2725.  
  2726. ΓòÉΓòÉΓòÉ 4.5. A Review of C++ Compilers ΓòÉΓòÉΓòÉ
  2727.  
  2728.                          Written by Gordon W. Zeglinski
  2729.  
  2730. Select this to go to the next section 
  2731.  
  2732.  
  2733. ΓòÉΓòÉΓòÉ 4.5.1. Introduction ΓòÉΓòÉΓòÉ
  2734.  
  2735. This article, examines various real-world aspects of the primary C++ compilers 
  2736. available for OS/2.  The compilers included in this review are: 
  2737.  
  2738. Borland C++ for OS/2 version 1.0 
  2739. Watcom C/C++ version 9.5 
  2740. IBM Cset++ version 2.0 
  2741. EMX/gcc version 0.8g 
  2742.  
  2743. I have omitted Zoretch C++ from this list because I do not have access to this 
  2744. compiler.  The last time I looked at this compiler, it did not include an OS/2 
  2745. debugger. 
  2746.  
  2747. These compilers will be compared on the bases of: 
  2748.  
  2749. o Time to compile the test code 
  2750. o Execution time of the test code 
  2751. o Size of the resultant .EXE file 
  2752. o Quality of bundled tools 
  2753. o Bugs found 
  2754.  
  2755. About the Tests 
  2756.  
  2757. The test code consists of a series of matrix objects developed by the author. 
  2758. These objects rely on both floating point operations and list manipulations 
  2759. (integer math, pointer dereferencing, etc.).  The object hierarchy makes 
  2760. extensive use of virtual, pure virtual, and inline "functions".  "Functions" in 
  2761. this case refer to both operators and functions. 
  2762.  
  2763. Select this to go to the next section 
  2764.  
  2765.  
  2766. ΓòÉΓòÉΓòÉ 4.5.2. Compiler Overview ΓòÉΓòÉΓòÉ
  2767.  
  2768. In this section, I will examine the non-quantitative aspects of the various 
  2769. compilers, i.e.  how easy they are to install, ease of use, and quality of the 
  2770. support tools.  Given this, one should keep in mind that the following 
  2771. discussion is subjective and, as such, is the opinion of the author. 
  2772.  
  2773. Borland C++ for OS/2 version 1.0 
  2774.  
  2775. This compiler is very similar to its windows counter part.  Its IDE uses the 
  2776. same basic design and the windows version.  The package comes with both a 
  2777. command line and PM-based compiler, a debugger, and documents on OS/2 
  2778. programming in .INF format.  Also, various on-line documents are provided to 
  2779. help use the the tools. 
  2780.  
  2781. I have found several bugs in the compiler.  The following list is by no means 
  2782. extensive. 
  2783.  
  2784.  1. The editor in the IDE has a tendency to drop line feed characters every so 
  2785.     often this leads to the occasional hard to find syntax error. 
  2786.  
  2787.  2. None of the PM functions are accessible using the <CTRL><F1> help hotkeys 
  2788.     from within the IDE. 
  2789.  
  2790.  3. The compiler has problems filling in virtual function tables under certain 
  2791.     instances.  It leaves them as NULL.  The results of calling a function in 
  2792.     this state is a protection violation error. 
  2793.  
  2794.  4. The debugger is next to unusable in my opinion.  When debugging C++ 
  2795.     programs (especially PM programs), one can expect to reboot their systems 
  2796.     very often.  This is due to OS/2's single threaded message queue and the 
  2797.     inability to kill the debugger via repeated <CTRL><ESC>'s. 
  2798.  
  2799.  5. TLINK is unable to properly handle segments with IOPL permission, resulting 
  2800.     is a protection violation.  There was a work around for this problem, but I 
  2801.     have not tried it because bug #3 prevents me from using this compiler in 
  2802.     the application that needs IOPL priviledges. 
  2803.  
  2804. The Resource Workshop that ships with this version is similar to its Windows 
  2805. counterpart but lack much of its nice features.  For instance, when editing 
  2806. menus one is simply typing a resource script into a large entry field control. 
  2807. The only resources that are edited visually are the dialog boxes, bitmaps and 
  2808. icons; however, the icons no longer work under OS/2 2.1 and the bitmap editor 
  2809. has some bugs in it that cause stray pixels to appear.  The dialog editor is 
  2810. great, though, and is far better than the one IBM supplies with CSet++. 
  2811.  
  2812. This version lacks OWL and the profiler which ships with its DOS/Windows 
  2813. counterpart.  On the positive side, this is a fast compiler.  It compiles 
  2814. source files faster than any other compiler tested.  Also, it seems that there 
  2815. has been some bugs fixed in its optimizer because code that would bomb under 
  2816. the DOS compiler when optimized now works under the OS/2 compiler. 
  2817.  
  2818. Tech support from Borland is available through Compuserve.  I have heard that 
  2819. they no longer provide tech support to Internet mail addresses but cannot say 
  2820. if this is true.  Past experience with them was a little disappointing. If you 
  2821. report a bug that has been fixed, they will tell you about a patch if it 
  2822. exists.  Bug fixes integrated into the product, though, are usually done in a 
  2823. future version, which you have to purchase to get these fixes. 
  2824.  
  2825. Watcom C/C++ version 9.5 
  2826.  
  2827. The Watcom compiler ships with a modified version of the OS/2 Toolkit version 
  2828. 2.0.  It generates code for 32 bit DOS, Windows (with a DOS extender), NT and 
  2829. OS/2.  If multi-platform code generation is a must for you, then this is the 
  2830. compiler you want.  It includes a text mode debugger and profiler. Another plus 
  2831. for this package is that it is capable of optimizing for the Pentinum 
  2832. processor.  Also included in the package is quite the hefty stack of 
  2833. documentation.  However, in order to program in any of the above environments, 
  2834. one still has to buy the appropriate programming guides for the target 
  2835. operating systems.  Shipped documentation includes: 
  2836.  
  2837. o WATCOM C/C++32. Optimizing User's Guide 
  2838. o WATCOM C/C++ Tools User's Guide 
  2839. o WATCOM VIDEO User's Guide 
  2840. o WATCOM VIDEO User's Guide Addendum 
  2841. o WATCOM Linker User's Guide 
  2842. o Supplement to WATCOM Linker User's Guide 
  2843. o WATCOM C Library Reference 
  2844. o WATCOM C++ Class Library Reference 
  2845. o WATCOM C++ Container Class Library Reference 
  2846. o WATCOM C Graphics Library Reference 
  2847. o The C++ Programming Language 
  2848. o WATCOM C Language Reference 
  2849. o WATCOM C/C++32 Commonly Asked Questions & Answers 
  2850.  
  2851. Although being a VIO mode app, the debugger is quite powerful.  In addition to 
  2852. the typical features associated with a source-level debugger, it also allows 
  2853. debugger instructions to be executed at break points.  However, there does not 
  2854. seem to be any C++ specific functionality, e.g. class browsers. 
  2855.  
  2856. The profiler included is also a VIO mode application and is divided into two 
  2857. separate parts:  the sampler and sample displayer.  The sampler uses the system 
  2858. clock to periodically interrupt the executing program and see where it is.  It 
  2859. also allows the programmer to set "profile points"  or "marks"  within the 
  2860. source code, allowing it to be used as either an intrusive or non-intrusive 
  2861. profiler.  Because the profiler does not use any device drivers, it is likely 
  2862. that under OS/2 the sample rate is only approximately 32 Hz, due to the fact 
  2863. that the profiler can only use the standard API calls to gain access to the 
  2864. timer interrupts. 
  2865.  
  2866. At any rate, the non-intrusiveness of the profiler is a negative point when it 
  2867. comes to profiling existing C++ code since in any OOP language, it is common to 
  2868. have many small functions that are frequently called.  The only way to 
  2869. determine the impact of these functions is to place marks around them.  For 
  2870. large amounts of code, this is undesirable because it has to be done manually. 
  2871. The sample displayer is pretty basic.  It only gathers and displays time and 
  2872. frequency related data. 
  2873.  
  2874. One of the things which bothers me the most about the product is that the 
  2875. Watcom linker does not use standard .DEF files. 
  2876.  
  2877. In the few days that I have tested this package, the following bugs were found: 
  2878.  
  2879.  1. The compiler has problems dealing with the construct virtual operator=.  I 
  2880.     was able to work around this bug so that I could perform the benchmarks. 
  2881.  
  2882.  2. I could not get it to work properly with the Workframe version 1.1.  This 
  2883.     is probably due to the fact that I'm using the beta version of the 
  2884.     Workframe from the last PDK until my copy of CSet++ arrives. 
  2885.  
  2886. Having found what I consider to be a serious bug (#1 above), I decided to give 
  2887. their tech support a try, provided through email.  My first bug report was 
  2888. answered within 2 hours and subsequent email were all answered the same day. 
  2889. One day after sending them the code, I got a reply.  Unfortunately for me, 
  2890. there is a grey area in the C++ "standards" that revolve around the use of 
  2891. virtual operator=().  Watcom follows the approach taken in MSC 7.0 which is 
  2892. different than just about every other C++ compiler. Watcom will be bringing 
  2893. this area to the attention of the ANSI C++ standards committee. 
  2894.  
  2895. IBM CSet++ version 2.0 
  2896.  
  2897. Now that my copy of the GA version of CSet++ has arrived, I can compare it to 
  2898. the release version of the others and to the beta version some of you may have. 
  2899. The package includes the OS/2 toolkit, IBM's Workframe, and the CSet++ 
  2900. compiler.  I'll concentrate on the compiler and it's support tools. 
  2901.  
  2902. The comparison of the GA to the BETA version of this compiler can be summarized 
  2903. in one sentence:  the GA version compiles code about 2-3 times faster and it's 
  2904. tools are far more stable. 
  2905.  
  2906. One of the most important things (for some of my applications) about this 
  2907. compiler and the accompanying linker is that it is capable of interfacing with 
  2908. IOPL code segments.  I have not tested Watcom's ability in this area.  I also 
  2909. believe that the EMX package has input/output functions.  Like Watcom, this 
  2910. compiler is compatible with version 3.0 of the C++ specifications, meaning that 
  2911. they support exceptions among other things.  The Borland compiler does not and 
  2912. I'm not sure about the EMX package. 
  2913.  
  2914. The debugger is PM-based and has object browsing abilities built into it. It 
  2915. also has features which are specific to debugging PM-based programs (ie. 
  2916. monitoring message queues and such).  My biggest problem with any PM-based 
  2917. debugger is that, if it is buggy, it can hang both the system queue and itself 
  2918. such that a reset is required.  It does not appear to have the ability to 
  2919. program actions at breakpoints like the Watcom compiler does. 
  2920.  
  2921. After much use, the debugger performed almost flawlessly.  I have found that it 
  2922. sometimes kills itself when the program monitor (a variable browser) is packed 
  2923. with variables.  The best feature it has is its ability to save all of the 
  2924. settings and restore them when you resume debugging.  These settings include 
  2925. breakpoints, user defined messages, etc.  I have found a minor bug in its user 
  2926. defined messages - it did not properly display the message parameters after 
  2927. restarting the debugger although it did remember the messages I defined. 
  2928.  
  2929. The profiler is excellent, feature wise, and is PM-based.  It is an intrusive 
  2930. analyzer that requires one to compile the code with both debugging info and 
  2931. profiling hooks turned on.  The programmer can also insert profiling points 
  2932. within the code.  The profiler is a full featured execution analyzer capable of 
  2933. measuring time, the number of times a profiler hook was called, and displaying 
  2934. a call tree.  The time and frequency data can be displayed in a number of 
  2935. formats.  The call tree displays which functions called who and the number of 
  2936. times these calls were made.  It has problems, however; I have found that one 
  2937. of its display options will not function with a trace file I generated.  Even 
  2938. worse is that some of its display modules do not support long filenames, which 
  2939. is unacceptable. 
  2940.  
  2941. The object browser is also quite useful; it allows a graphical and textual 
  2942. exploration of the classes used in the program.  It displays the relationship 
  2943. between these objects by showing inheritance, who calls who, and class members. 
  2944.  
  2945. I have not used the PM object library that comes with this compiler because I 
  2946. am creating my own library.  Others have complained that there is a lot of 
  2947. overhead in using this library, though, and that it takes along time to compile 
  2948. code that uses it. 
  2949.  
  2950. My biggest complaint about this product is its so-called documentation.  I 
  2951. bought the 3.5" format package hoping to find tons of hard copy manuals. To my 
  2952. surprise, the hard copy documentation is very similar in size to the 
  2953. documentation that came with OS/2 2.0 GA.  In several places, the hard copy 
  2954. documentation refers the reader to the on-line help.  The only hard copy 
  2955. manuals with some thickness to them are: 
  2956.  
  2957. o Class Libraries Reference Summary 
  2958. o User Interface Class Library User's Guide (an IBM Red Book) 
  2959. o Programming Guide 
  2960.  
  2961. The rest of the manuals seem to have trivial content; if you were really stuck, 
  2962. you would typically be referred to the on-line help for the product or some 
  2963. other on-line file.  There are also a few typo's in the manuals. 
  2964.  
  2965. Latest Bug Fixes 
  2966.  
  2967. My complaints about the lack of long filename support in EXTRA (the profiler) 
  2968. have been solved by applying CSD level 0001 to the package and then running the 
  2969. following little REXX program, which sets a flag in the EXTRA executables that 
  2970. allow them to see files with long names. 
  2971.  
  2972. Note:  This REXX file assumes that the program EXEHDR.EXE is on the path (it is 
  2973. included with the toolkit). 
  2974.  
  2975. /* This exec addes the "newfiles" flag to the header of each of the
  2976. Extra executables.  This allows the user to use long names for trace
  2977. files */
  2978.  
  2979. "EXEHDR /NEWFILES IXTRA.EXE"
  2980. "EXEHDR /NEWFILES ITIME.EXE"
  2981. "EXEHDR /NEWFILES IEXCDENS.EXE"
  2982. "EXEHDR /NEWFILES ICALNEST.EXE"
  2983. "EXEHDR /NEWFILES ISTATS.EXE"
  2984. "EXEHDR /NEWFILES IDCGRAPH.EXE"
  2985.  
  2986. EMX/gcc version 0.8g 
  2987.  
  2988. The EMX/GNU compiler package is a very impressive freeware compiler.  The 
  2989. package includes the GNU gcc version 2.4.5 compiler and a debugger.  A bunch of 
  2990. other Unix-like tools are also included.  The debugger is a VIO program which 
  2991. is command line driven.  I haven't used it for PM programming or interfacing 
  2992. with OS/2's API.  The docs for the package are available via ftp from the 
  2993. primary OS/2 FTP sites.  The reader can get these documents for themselves if 
  2994. they so desire. 
  2995.  
  2996. Select this to go to the next section 
  2997.  
  2998.  
  2999. ΓòÉΓòÉΓòÉ 4.5.3. Summary of Features ΓòÉΓòÉΓòÉ
  3000.  
  3001. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3002. Γöé                    ΓöéBorland C++ forΓöéWatcom C/C++   ΓöéIBM CSet++     ΓöéEMX/gcc        Γöé
  3003. Γöé                    ΓöéOS/2           Γöé               Γöé               Γöé               Γöé
  3004. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3005. ΓöéMulti-Platform      ΓöéNo             Γöé32 bit OS/2,   ΓöéNo             ΓöéOS/2, DOS      Γöé
  3006. Γöé                    Γöé               ΓöéDOS, Windows,  Γöé               Γöé               Γöé
  3007. Γöé                    Γöé               ΓöéNT             Γöé               Γöé               Γöé
  3008. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3009. ΓöéDebugger            ΓöéPM             ΓöéVIO            ΓöéPM             ΓöéVIO            Γöé
  3010. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3011. ΓöéProfiler            ΓöéNo             ΓöéVIO            ΓöéPM             ΓöéNo             Γöé
  3012. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3013. ΓöéC++ Level           Γöé2.1            Γöé3.0            Γöé3.0            Γöé2.1(?)         Γöé
  3014. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3015. ΓöéPrecompiled Headers ΓöéYes            ΓöéNo             ΓöéYes            ΓöéNo             Γöé
  3016. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3017. ΓöéTech Support        Γöécompuserve     ΓöéInternet email ΓöéInternet email ΓöéNo official    Γöé
  3018. Γöé                    Γöé               Γöé               Γöé               Γöésupport        Γöé
  3019. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3020.  
  3021. Select this to go to the next section 
  3022.  
  3023.  
  3024. ΓòÉΓòÉΓòÉ 4.5.4. On with the Benchmarks ΓòÉΓòÉΓòÉ
  3025.  
  3026. The benchmarking was performed on a 486 DX/33-based machine with 16M of RAM. 
  3027. The test consist of two programs both are related to my work on object oriented 
  3028. matrix classes.  One test (the full matrix) is mostly floating point while the 
  3029. other (the sparse matrix) is a combination of list manipulation and floating 
  3030. point.  Listed are the times it took to compile the two first test both with 
  3031. and without optimizations enabled is measured, the times it took to execute the 
  3032. each test program, and the size of the resulting executables. 
  3033.  
  3034. Note:  in the following charts, (opt) means that optimization was turned on 
  3035.  
  3036. Compile Times 
  3037.  
  3038. These times are measured with a stopwatch and represent the time it took NMAKE 
  3039. or MAKE (in the case of EMX) to create the executable.  The source code 
  3040. consists of approximately 11 files for each test. 
  3041.  
  3042. Note:  For each table below, all times are in seconds and all sizes are in 
  3043. bytes. 
  3044.  
  3045. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3046. Γöé                    ΓöéBorland ΓöéWatcom  ΓöéIBM     ΓöéEMX/gcc ΓöéBorland(opt)ΓöéWatcom(opt)ΓöéIBM(opt)   ΓöéEMX/gcc(opt)Γöé
  3047. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3048. ΓöéFull Matrix         Γöé106     Γöé240     Γöé161     Γöé270     Γöé122         Γöé259        Γöé204        Γöé288         Γöé
  3049. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3050.  
  3051. Executable size 
  3052.  
  3053. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3054. Γöé                    ΓöéBorland ΓöéWatcom  ΓöéIBM     ΓöéEMX/gcc ΓöéBorland(opt)ΓöéWatcom(opt)ΓöéIBM(opt)   ΓöéEMX/gcc(opt)Γöé
  3055. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3056. ΓöéFull Matrix         Γöé86549   Γöé137532  Γöé147328  Γöé176132  Γöé83477       Γöé145622     Γöé125552     Γöé118788      Γöé
  3057. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3058. ΓöéSparse Matrix       Γöé113173  Γöé156712  Γöé171344  Γöé229380  Γöé107541      Γöé164775     Γöé147104     Γöé139628      Γöé
  3059. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3060.  
  3061. Execution Time 
  3062.  
  3063. The full test measures the time to LU decompose a 200 x 200 matrix.  The sparse 
  3064. test measures the time to LU decompose and solve a 800 x 800 sparse matrix. 
  3065.  
  3066. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3067. Γöé                    ΓöéBorland ΓöéWatcom  ΓöéIBM     ΓöéEMX/gcc ΓöéBorland(opt)ΓöéWatcom(opt)ΓöéIBM(opt)   ΓöéEMX/gcc(opt)Γöé
  3068. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3069. ΓöéFull Matrix         Γöé8       Γöé8.33    Γöé11      Γöé11.67   Γöé6.33        Γöé6.00       Γöé7.67       Γöé5.33        Γöé
  3070. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3071. ΓöéSparse Matrix       Γöé75.5    Γöé51.5    Γöé102.5   Γöé109     Γöé67.5        Γöé48.5       Γöé50.5       Γöé50.0        Γöé
  3072. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3073.  
  3074. I've noticed that while running the sparse test, the Watcom compiler required 
  3075. about 8M of RAM.  All the other compilers produced executables that only 
  3076. required about 2M of RAM when executed, which requires further investigation. 
  3077. All of the compilers except Borland performed equally well in the sparse test. 
  3078.  
  3079. Select this to go to the next section 
  3080.  
  3081.  
  3082. ΓòÉΓòÉΓòÉ 4.5.5. Closing Remarks ΓòÉΓòÉΓòÉ
  3083.  
  3084. When I began this series of tests, I was hoping that there would be a clear 
  3085. "winner."  However, I do not think that one exists; each of the products have 
  3086. their own unique qualities which will appeal to different users. I strongly 
  3087. feel that for people looking simply for an OS/2 C++ compiler with excellent 
  3088. tools, CSet++ is the right choice.  For others, I hope the guidelines below 
  3089. will help. 
  3090.  
  3091. As a side note, I am very impressed with the EMX/GCC package.  It is as good as 
  3092. any of the others and costs nothing.  If I didn't need a profiler and want 
  3093. precompiled header files, I'd definetly save some cash and use it. 
  3094.  
  3095. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3096. ΓöéDesired Usage       ΓöéCompiler(s)                                  Γöé
  3097. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3098. ΓöéInterfacing with    ΓöéCSet++, Watcom C/C++ or EMX/GCC(?)           Γöé
  3099. ΓöéIOPL code           Γöé                                             Γöé
  3100. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3101. ΓöéFloating Point      ΓöéEMX/GCC, Watcom C/C++, or CSet++             Γöé
  3102. Γöéintensive code      Γöé                                             Γöé
  3103. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3104. ΓöéPM programming      ΓöéCSet++ or Borland (because of precompiled    Γöé
  3105. Γöé                    Γöéheader files). Any of the 4 are quite able inΓöé
  3106. Γöé                    Γöéthis area.                                   Γöé
  3107. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3108. ΓöéC++ code with       Γöé EMX/GCC or CSet++ (Watcom follows the MSC   Γöé
  3109. Γöéworking virtual     Γöéway of handling the operator=() )            Γöé
  3110. Γöéfunctions           Γöé                                             Γöé
  3111. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3112. ΓöéProfiler            ΓöéCSet++ or Watcom C/C++                       Γöé
  3113. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3114. ΓöéEnvironment like BC ΓöéBorland C++ for OS/2                         Γöé
  3115. Γöé3.1                 Γöé                                             Γöé
  3116. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3117. Γöé Really fast        Γöé Borland C++ or CSet++ (CSet++ is slower but Γöé
  3118. Γöécompilation         Γöéit's debugger is better)                     Γöé
  3119. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3120.  
  3121. Select this to go to the next section 
  3122.  
  3123.  
  3124. ΓòÉΓòÉΓòÉ 4.5.6. Editor's Notes ΓòÉΓòÉΓòÉ
  3125.  
  3126. After mentioning in comp.os.os2.programmer.misc that this issue would contain a 
  3127. comparison of C++ compilers, I received a request from Tim Francis in the 
  3128. C-Set++ compiler group to review the article pre-press.  I gladly sent him a 
  3129. copy with the stipulation that the article would not be modified based on any 
  3130. comments he made, to which he agreed.  However, I feel it necessary to put 
  3131. these comments here, as a side-note, with the intent of demonstrating the 
  3132. apparent customer-driven attitude of this group.  As a disclaimer, while I do 
  3133. know some people on the compiler development team, I have never had any 
  3134. business dealings with them and am not doing this as a favor to them or because 
  3135. of any bias I have. 
  3136.  
  3137. Tim Francis writes: 
  3138.  
  3139. I didn't find anything really wrong in the compiler review.  I thought C-Set++ 
  3140. came out looking quite good, actually.  I would be interested in seeing the 
  3141. actual code used in the execution benchmarks - we were last in the opt/full 
  3142. matrix test, and 2nd last in the opt/sparse matrix test.  I'm certainly not 
  3143. trying to dispute these numbers, but our benchmarks tend to place us a little 
  3144. higher in the competition than that.  Our performance evaluation guy would 
  3145. really like a look at what's happening, to see if we can improve anything. 
  3146.  
  3147. The only other comment I have is in the summary of features, Tech support 
  3148. column.  As documented in the C-Set++ package, we offer the following support: 
  3149.  
  3150. o Non-defect support, and informal (best effort) defect support 
  3151.  
  3152.    - Compuserve 
  3153.    - Internet 
  3154.    - Talklink 
  3155.  
  3156. o Formal defect support 
  3157.  
  3158.    - 1-800 number, available 24hrs/day, 7 days/week. 
  3159.  
  3160. Obviously we feel that the support we offer is a key component of the product, 
  3161. so if you mention the above somewhere in EDMI I'd appreciate it. 
  3162.  
  3163. For the purposes of completeness, I am also including the following from Ian 
  3164. Ameline: 
  3165.  
  3166. If possible, could you have those floating point tests run with /Gf+ turned on 
  3167. - it will result in *much* faster FP code by relaxing our strict interpretation 
  3168. of the IEEE standard.  The other compilers all use the more relaxed 
  3169. interpretation - and this places us at a bit of a performance disadvantage 
  3170. compared to them, but we do produce results that are the same as any other IEEE 
  3171. 64 bit FP processor (Of course the Intel one is uses 80 bits of precision 
  3172. naturally, and if we try to conform to the 64 bit standards, we have to 
  3173. truncate the numbers each time they're stored to a variable.  This truncation 
  3174. is expensive) 
  3175.  
  3176. Also, I'll make sure the long filename bug in Extra is fixed for CSD 2. 
  3177.  
  3178. Ian's comment about the compiler's strict interpretation of IEEE standards 
  3179. prompted me to request that the author use the /Gf+ option for the optimized 
  3180. part of the benchmarks (he was using /Gf); he did so and reported that /Gf and 
  3181. /Gf+ resulted in no difference in time (it appears that /Gf invokes the default 
  3182. which is /Gf+), while /Gf- resulted in an time increase of 1.5 seconds. 
  3183.  
  3184. Select this to go to the next section 
  3185.  
  3186. Select this to go to the next section 
  3187.  
  3188.  
  3189. ΓòÉΓòÉΓòÉ 5. Columns ΓòÉΓòÉΓòÉ
  3190.  
  3191. The following columns can be found in this issue: 
  3192.  
  3193. o Scratch Patch 
  3194.  
  3195.  
  3196. ΓòÉΓòÉΓòÉ 5.1. Scratch Patch ΓòÉΓòÉΓòÉ
  3197.  
  3198. Welcome to this month's "Scratch Patch"!  Each month, I collect various items 
  3199. that fit into this column sent to me via email. The ones that I feel contribute 
  3200. the most to developers, whether in terms of information or as a nifty trick to 
  3201. tuck into your cap, get published in this column. 
  3202.  
  3203. To submit an item, send it via email to my address - os2man@panix.com - and be 
  3204. sure to grant permission to publish it (those that forget will not be 
  3205. considered for publication).  This month, we have the following: 
  3206.  
  3207. o Questions and Answers 
  3208. o Snippet(s) of the Month 
  3209. o Documentation Chop Shop 
  3210. o Want Ads 
  3211.  
  3212.  
  3213. ΓòÉΓòÉΓòÉ 5.1.1. Questions and Answers ΓòÉΓòÉΓòÉ
  3214.  
  3215. Brian Stark (stark@saturn.sdsu.edu) writes: 
  3216.  
  3217. While building entry fields I noticed the style option ES_AUTOTAB, which moves 
  3218. the cursor to the next "control window" automatically when the maximum number 
  3219. of characters are entered (Ref.  OS/2 2.0 Technical Library, Programming Guide 
  3220. Volume II).  My assumption is that this is done by sending a WM_CONTROL message 
  3221. to the current control windows owner.  However I was unable to verify this in 
  3222. the document, or any other document.  Currently I am only able to establish 
  3223. control of an entry field using the mouse, I would like to be able to use the 
  3224. arrow keys and the tab to move from field to field.  Is the application 
  3225. responsible for this?  If so, is there a document available that gives a clear 
  3226. description of this process, or am I just doing something wrong when I create 
  3227. the fields. 
  3228.  
  3229. After checking the toolkit header files (mainly pmwin.h) and not finding any 
  3230. notifications that would indicate what you are hoping (EN_* constants), a quick 
  3231. test application yielded that no WM_CONTROL messages are indeed sent that 
  3232. indicate the auto-tab feature has been invoked.  However, the EN_KILLFOCUS and 
  3233. EN_SETFOCUS notifications are sent to the entryfield losing the focus and to 
  3234. the one receiving the focus, respectively. 
  3235.  
  3236. While these are not sent only when the auto-tab takes place (a mouse click in 
  3237. another entryfield will generate the same two notifications), a little thought 
  3238. and hocus-pocus will help you figure out how to do what you want to do. 
  3239.  
  3240. Regarding arrow keys and tabs, the system treats the keys in the following 
  3241. ways: 
  3242.  
  3243. Tab/Down arrow      Moves the focus to the next control ("next" is defined 
  3244.                     using Z-order) with the WS_TABSTOP style. 
  3245. Backtab/Up arrow    Moves the focus to the previous control ("previous" is 
  3246.                     defined using Z-order) with the WS_TABSTOP style. 
  3247.  
  3248. In entryfields, the left/right arrows maneuver the cursor within the control. 
  3249.  
  3250. Dominique Beauchamp (beaucham@phy.ulaval.ca) writes: 
  3251.  
  3252. What is the difference between a "string" and a "message" in a resource file? 
  3253. Each can be loaded with WinLoadString and WinLoadMessage but afterwards it 
  3254. seems we can use them the same way.  If I want to program an error message box, 
  3255. should I use "string" or "message" to do it? (No, it's not obvious!) 
  3256.  
  3257. To be honest, often times I have asked the same question.  Within PM, there 
  3258. seem to be a few items whose usefulness are questionable (this being one of 
  3259. them).  To my knowledge, there is no difference between the two; one of the two 
  3260. might exist for historical reasons (SAA comes to mind), or there might be other 
  3261. logic at work here.  In any case, I personally prefer WinLoadString since its 
  3262. name implies that it is used for more than just messages; whatever you choose, 
  3263. be consistent in your coding. 
  3264.  
  3265.  
  3266. ΓòÉΓòÉΓòÉ 5.1.2. Snippet(s) of the Month ΓòÉΓòÉΓòÉ
  3267.  
  3268. Since I announced this new section this month, I would be expecting a lot if I 
  3269. wanted to put user-submissions here.  Thus, here are some of my favorite 
  3270. subroutines: 
  3271.  
  3272. SHORT winDisplayMessage(HWND hwndParent,
  3273.                         HWND hwndOwner,
  3274.                         ULONG ulStyle,
  3275.                         HMODULE hmDll,
  3276.                         USHORT usId,
  3277.                         USHORT usHelpId,...)
  3278. //-------------------------------------------------------------------------
  3279. // This function puts a message to the screen in PM mode (using WinMessageBox).
  3280. // The title of the message box is assumed to have the message id usId|0x8000.
  3281. //
  3282. // Input:  hwndParent - handle of the parent window
  3283. //         hwndOwner - handle of the owning window
  3284. //         ulStyle - specifies the WinMessageBox styles
  3285. //         hmDll - handle of the DLL containing the message
  3286. //         usId - specifies the id of the message to load
  3287. //         usHelpId - specifies the id of the corresponding help panel
  3288. // Returns:  TRUE if successful, FALSE otherwise
  3289. //-------------------------------------------------------------------------
  3290. {
  3291.    CHAR achMsg[1024];
  3292.    CHAR achTitle[256];
  3293.    va_list vlArgs;
  3294.    CHAR achBuf[2048];
  3295.    ULONG ulRc;
  3296.  
  3297.    if (ulStyle==0L) {
  3298.       ulStyle=MB_INFORMATION | MB_OK;
  3299.    } /* endif */
  3300.  
  3301.    if ((ulStyle & MB_SYSTEMMODAL)==0) {
  3302.       ulStyle|=MB_APPLMODAL;
  3303.    } /* endif */
  3304.  
  3305.    if (usHelpId!=0) {
  3306.       ulStyle|=MB_HELP;
  3307.    } /* endif */
  3308.  
  3309.    ulStyle|=MB_MOVEABLE;
  3310.  
  3311.    //----------------------------------------------------------------------
  3312.    // Load the message box text and title
  3313.    //----------------------------------------------------------------------
  3314.    if (WinLoadString(NULLHANDLE,
  3315.                      hmDll,
  3316.                      usId,
  3317.                      sizeof(achMsg),
  3318.                      achMsg)==0) {
  3319.       return MBID_ERROR;
  3320.    } /* endif */
  3321.  
  3322.    if (WinLoadString(NULLHANDLE,
  3323.                      hmDll,
  3324.                      usId | 0x8000,
  3325.                      sizeof(achTitle),
  3326.                      achTitle)==0) {
  3327.       return MBID_ERROR;
  3328.    } /* endif */
  3329.  
  3330.    //----------------------------------------------------------------------
  3331.    // Format the message and display it
  3332.    //----------------------------------------------------------------------
  3333.    va_start(vlArgs,usHelpId);
  3334.    vsprintf(achBuf,achMsg,vlArgs);
  3335.    va_end(vlArgs);
  3336.  
  3337.    ulRc=WinMessageBox(hwndParent,
  3338.                       hwndOwner,
  3339.                       achBuf,
  3340.                       achTitle,
  3341.                       usHelpId,
  3342.                       ulStyle);
  3343.    return ulRc;
  3344. }
  3345.  
  3346. VOID winCenterWindow(HWND hwndCenter)
  3347. //-------------------------------------------------------------------------
  3348. // This function centers the window within its parent
  3349. //
  3350. // Input:  hwndCenter - handle of the window to center
  3351. //-------------------------------------------------------------------------
  3352. {
  3353.    SWP swpCenter;
  3354.    RECTL rclParent;
  3355.  
  3356.    WinQueryWindowPos(hwndCenter,&swpCenter);
  3357.    WinQueryWindowRect(WinQueryWindow(hwndCenter,QW_PARENT),&rclParent);
  3358.  
  3359.    swpCenter.x=(rclParent.xRight-swpCenter.cx)/2;
  3360.    swpCenter.y=(rclParent.yTop-swpCenter.cy)/2;
  3361.  
  3362.    WinSetWindowPos(hwndCenter,NULLHANDLE,swpCenter.x,swpCenter.y,0,0,SWP_MOVE);
  3363. }
  3364.  
  3365.  
  3366. ΓòÉΓòÉΓòÉ 5.1.3. Documentation Chop Shop ΓòÉΓòÉΓòÉ
  3367.  
  3368. Problem with BN_PAINT 
  3369.  
  3370. I have a confession to make:  I have yet to upgrade my machine at work to OS/2 
  3371. 2.1, so the following problem might have been fixed in 2.1.  I will try to 
  3372. remember to check at home, but if anyone else knows the answer already I would 
  3373. appreciate email.  The problem is with buttons created with the style 
  3374. BS_USERBUTTON; the documentation states that, when the button needs to be 
  3375. repainted, you will receive a BN_PAINT notification and mpParm2 will point to a 
  3376. USERBUTTON structure which contains four fields: 
  3377.  
  3378. hwnd                handle of the button window 
  3379. hps                 presentation space in which drawing should be performed 
  3380. fsState             the current state of the button 
  3381. fsStateOld          the previous state of the button 
  3382.  
  3383. According to the documentation, the fields fsState and fsStateOld can be one of 
  3384. three values - BDS_DEFAULT, BDS_HILITED, or BDS_DISABLED.  When creating a 
  3385. 32-bit application utilizing "ownerdraw" buttons, this did not seem to work, so 
  3386. I added a few calls to fprintf() and below is what I got (the labelling of the 
  3387. events were added later): 
  3388.  
  3389. Upon window creation
  3390. --------------------
  3391. Button state       = 0x00000000
  3392. Button state (old) = 0x00040010
  3393.  
  3394. First down
  3395. ----------
  3396. Button state       = 0x00000100
  3397. Button state (old) = 0xD0DF032B
  3398.  
  3399. First up
  3400. --------
  3401. Button state       = 0x01000000
  3402. Button state (old) = 0x01000100
  3403.  
  3404. Second down
  3405. -----------
  3406. Button state       = 0x00000100
  3407. Button state (old) = 0xD0DF032B
  3408.  
  3409. Second up
  3410. ---------
  3411. Button state       = 0x01000000
  3412. Button state (old) = 0x01000100
  3413.  
  3414. If you will accept the notion that my code is correct, you can see that the 
  3415. documentation appears to be completely wrong.  I tried to reinterpret the 
  3416. values but still I ran into problems.  Several calls to printf() later, a 
  3417. pattern emerged.  I quickly followed my hunch and all of my problems went away. 
  3418.  
  3419. IBM defined the USERBUTTON structure incorrectly!  The fsState and fsStateOld 
  3420. fields which are defined as ULONG's should be USHORT's instead.  That 
  3421. simplified the problem to having to undefine BDS_DEFAULT (0x0400) and 
  3422. redefining it as 0x0000. 
  3423.  
  3424. Workaround 
  3425.  
  3426. The workaround should be obvious - either change your toolkit header files or 
  3427. define your own structure and redefine the BDS_DEFAULT constant. The former is 
  3428. preferred since you will not have to "kludge" every program that utilizes 
  3429. user-buttons to get this to work. 
  3430.  
  3431.  
  3432. ΓòÉΓòÉΓòÉ 5.1.4. Want Ads ΓòÉΓòÉΓòÉ
  3433.  
  3434. My apologies for all of you who have sent requests for other topics that I did 
  3435. not place below.  My memory is getting fragile in my old age.  (*grin*) These 
  3436. seem to be good topics to write on; I have tried to assign some weighting on 
  3437. the "hotness" ("heat" just doesn't convey the idea properly, so I made up a new 
  3438. word) of the topic, so feel free to write on the really hot ones. 
  3439.  
  3440. Anything on Rexx/2 (hot) - many people have requested more articles on Rexx/2. 
  3441. I, for one, would like to see how to write external functions encased in DLL's, 
  3442. but other topics include interfacing Rexx/2 with C (as in a macro language), 
  3443. writing "Enhanced Editor"  macros in Rexx/2, and interfacing with the Workplace 
  3444. Shell from Rexx/2. 
  3445.  
  3446. Using Input Hooks (hot) - this is a complicated topic which is brought up 
  3447. frequently in the comp.os.os2.programmer.misc newsgroup. 
  3448.  
  3449. Hit testing (warm) - one reader noted that the Jigsaw sample in both the IBM 
  3450. and Borland toolkits (are they not the same?) perform there own correlation and 
  3451. wondered why?  Charles Petzold, in his OS/2 book "Programming the OS/2 
  3452. Presentation Manager" briefly describes correlation and hit-testing, but does 
  3453. not go into any detail nor does it describe the Gpi functions used for this 
  3454. purpose. 
  3455.  
  3456. Animation (warm) - a few readers expressed an interest in the various animation 
  3457. techniques that can be applied to PM applications.  The ultimate article, in my 
  3458. opinion, would be one that develops a sprite library a la the Commodore 64's 
  3459. (and Amiga's?) built-in routines, since this is probably the hardest component 
  3460. of any good animation sequence. 
  3461.  
  3462. Client/Server (warm) - using either named pipes (with or without a network) or 
  3463. sockets, client/server programming is all-the-rage these days.  Some time ago, 
  3464. I started development on a post-office and a named-pipe implementation of FTP; 
  3465. maybe I will get time to finish them and will write articles on them. 
  3466.  
  3467. Multiple Threads in a PM application (warm) - this is another complicated topic 
  3468. which is brought up from time to time in the comp.os.os2.programmer.misc 
  3469. newsgroup.  While various solutions to the dilemma of communication without 
  3470. global variables have been discussed, it would be nice to see (one or more of) 
  3471. them in a more permanent place than a news server. 
  3472.  
  3473. Select this to go to the next section 
  3474.  
  3475.  
  3476. ΓòÉΓòÉΓòÉ 6. Future Attractions ΓòÉΓòÉΓòÉ
  3477.  
  3478. As always, we are always looking for (new) authors.  If you have a topic about 
  3479. which you would like to write, send a brief description of the topic 
  3480. electronically to any of the editors, whose addresses are listed below, by the 
  3481. 15th of the month in which your article will appear.  This alerts us that you 
  3482. will be sending an article so that we can plan the issue layout accordingly. 
  3483. After you have done this, get the latest copy of the Article Submission 
  3484. Guidelines from ftp.cdrom.com in the /pub/os2/2_x/program/newsltr directory. 
  3485. (the file is artsub.zip)  The completed text of your article should be sent to 
  3486. us no later than the last day of the month; any articles received after that 
  3487. time may be pushed to the next issue. 
  3488.  
  3489. The editor's can be reached at the following email addresses: 
  3490.  
  3491. o Steve Luzynski - sal8@po.cwru.edu (Internet), 72677,2140 (Compuserve). 
  3492. o Larry Salomon - os2man@panix.com (Internet). 
  3493.  
  3494. Since Steve is incapacitated at the moment, Larry is the preferred contact at 
  3495. this time. 
  3496.  
  3497. Select this to go to the next section 
  3498.  
  3499.  
  3500. ΓòÉΓòÉΓòÉ 7. Contributors to this Issue ΓòÉΓòÉΓòÉ
  3501.  
  3502. The following people contributed to this issue in one form or another (in 
  3503. alphabetical order): 
  3504.  
  3505. o Andre Asselin 
  3506. o Larry Salomon, Jr. 
  3507. o Gordon Zeglinski 
  3508. o Network distributors 
  3509.  
  3510.  
  3511. ΓòÉΓòÉΓòÉ 7.1. Andre Asselin ΓòÉΓòÉΓòÉ
  3512.  
  3513. Andre Asselin recently graduated Cum Laude from Rensselaer Polytechnic 
  3514. Institute with a Bachelor of Science degree in Computer Science.  He has worked 
  3515. with OS/2 since version 1.3, and also has extensive experience with MS-DOS and 
  3516. Microsoft Windows.  He currently works in IBM's OS/2 TCP/IP Development group 
  3517. in Raleigh NC, where his responsibilities include the NFS client, a remote file 
  3518. system implemented as an IFS. 
  3519.  
  3520. Andre is also a member of Alpha Sigma Phi Fraternity, and enjoys hockey, 
  3521. soccer, and a good science fiction novel.  He can be reached via email at 
  3522. asselin@vnet.ibm.com or on CompuServe at 71075,133. 
  3523.  
  3524.  
  3525. ΓòÉΓòÉΓòÉ 7.2. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
  3526.  
  3527. Larry Salomon wrote his first Presentation Manager application for OS/2 version 
  3528. 1.1 in 1989.  Since that time, he has written numerous VIO and PM applications, 
  3529. including the Scramble applet included with OS/2 and the I-Brow/Magnify/Screen 
  3530. Capture trio included with the IBM Professional Developers Kit CD-ROM currently 
  3531. being distributed by IBM.  Currently, he works for International Masters 
  3532. Publishers in Stamford, Connecticut and resides in Bellerose, New York with his 
  3533. wife Lisa. 
  3534.  
  3535. Larry can be reached electronically via the Internet at os2man@panix.com. 
  3536.  
  3537.  
  3538. ΓòÉΓòÉΓòÉ 7.3. Gordon Zeglinski ΓòÉΓòÉΓòÉ
  3539.  
  3540. Gordon Zeglinski is a freelance programmer/consultant who received his Master's 
  3541. degree in Mechanical Engineering with a thesis on C++ sparse matrix objects. 
  3542. He has been programming in C++ for 6 years and also has a strong background in 
  3543. FORTRAN.  He started developing OS/2 applications with version 2.0 . 
  3544.  
  3545. His current projects include a client/server communications program that 
  3546. utilitizes OS/2's features and is soon to enter beta testing. Additionally, he 
  3547. is involved in the development of a "real-time" automated vehicle based on OS/2 
  3548. and using C++ in which he does device driver development and designs the 
  3549. applications that comprise the control logic and user interface. 
  3550.  
  3551. He can be reached via the Internet at zeglins@cc.umanitoba.ca. 
  3552.  
  3553.  
  3554. ΓòÉΓòÉΓòÉ 7.4. Network distributors ΓòÉΓòÉΓòÉ
  3555.  
  3556. These people are part of our distribution system to provide EDM/2 on networks 
  3557. other than the Internet.  Their desire to help provide others access to this 
  3558. magazine is voluntary and we appreciate them a lot! 
  3559.  
  3560. o Paul Hethman (hethman@cs.utk.edu) - Compuserve 
  3561. o David Singer (singer@almaden.ibm.com) - IBM Internal 
  3562.  
  3563.  
  3564. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3565.  
  3566. Precompiled headers are very useful when including OS2.H. Precompiled header 
  3567. files can greatly decrease the amount of time necessary to compile files that 
  3568. include many and/or large header files. However, not all compilers are equal in 
  3569. this respect. Borland compiles all headers into one large file. This probably 
  3570. make it a bit faster to access than multiple files.  But, when one header 
  3571. changes, all headers must be recompiled and stored in the large file.  IBM's 
  3572. CSet++ on the other hand uses one precompiled file for each header. Thus, when 
  3573. you change one of your header files, only that file has to be recompiled. Also, 
  3574. the method employed by CSet++ allows the same precompiled headers to be used by 
  3575. multiple projects, unlike the method used by Borland. 
  3576.  
  3577.  
  3578. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3579.  
  3580. The following command line options were used with Borland's compiler: 
  3581.  
  3582.     -I.. -If:\bcos2\include -ff -G -4 -O2it -vi -c -D_USE_POST_FIX_
  3583.  
  3584.  
  3585. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3586.  
  3587. The following command line options were used with IBM's compiler: 
  3588.  
  3589.     /I.. /Tdp /J- /Si- /O+ /Oi+ /Os+ /W1 /Gf /Gi /G4 /Gx+ /C /d_USE_POST_FIX_
  3590.  
  3591.  
  3592. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3593.  
  3594. The following command line options were used with Watcom's compiler: 
  3595.  
  3596.     /i=.. /i=. /i=f:\watcom\H /i=f:\TOOLKIT\C\OS2H /mf /4r /bt=os2 /sg /d_USE_POST_FIX_ /oneatx /zp4
  3597.  
  3598.  
  3599. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3600.  
  3601. The following command line options were used with GNU's EMX compiler: 
  3602.  
  3603.     -c -O2 -m486 -I..
  3604.  
  3605.  
  3606. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3607.  
  3608. The following command line options were used with Borland's compiler: 
  3609.  
  3610.     -I.. -If:\bcos2\include -ff -G -4 -vi -c -D_USE_POST_FIX_
  3611.  
  3612.  
  3613. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3614.  
  3615. The following command line options were used with IBM's compiler: 
  3616.  
  3617.     /I.. /Tdp /J- /Si- /W1 /Gf /Gi /G4 /Gx+ /C /d_USE_POST_FIX_
  3618.  
  3619.  
  3620. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3621.  
  3622. The following command line options were used with Watcom's compiler: 
  3623.  
  3624.     /i=.. /i=. /i=f:\watcom\H /i=f:\TOOLKIT\C\OS2H /mf /4r /bt=os2 /sg /d_USE_POST_FIX_ /zp4
  3625.  
  3626.  
  3627. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3628.  
  3629. The following command line options were used with GNU's EMX compiler: 
  3630.  
  3631.     -c -m486 -I..
  3632.