home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 32 Periodic / 32-Periodic.zip / edmi3-5.zip / EDMI3-5.INF (.txt) < prev    next >
OS/2 Help File  |  1995-05-08  |  244KB  |  3,506 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. May 1995 Title Page ΓòÉΓòÉΓòÉ
  3.  
  4.                   The Electronic Developer's Magazine for OS/2
  5.                       Portions copyright (c) by IQPac Inc.
  6.                                 Volume 3, issue 5
  7.  
  8. Administrivia 
  9.  
  10. The last month has zoomed by and it's time for another issue of the magazine. 
  11. This issue seems to be a bit on the slim side but that is because of finals, no 
  12. doubt about it.  You will finally see the end of the VIOWIN series, as well as 
  13. another fantastic installment about RMX-OS/2. 
  14.  
  15. On the Net 
  16.  
  17. One of the advantages of working in the "network systems development" group of 
  18. a large company is that one undoubtedly gets a connection to the Internet. I 
  19. still have no answer for why that is; maybe it's because the two names have the 
  20. word "net" in them.  <grin> 
  21.  
  22. Anyway, I now have a T1 link to the Internet, via an ethernet connection, from 
  23. my machine at work.  I will try, from time-to-time, to place some interesting 
  24. demos of things- to-come in EDM/2  there, retrievable via anonymous FTP.  The 
  25. machine name is os2man.sysdev.telerate.com and there is currently a demo of a 
  26. Stock Graphing program.  The demo utilizes a set of graphing classes that I 
  27. wrote in C++ using Watcom's compiler.  The set of classes has some work to be 
  28. done, as you will see if you get the demo, but they are already quite usable. 
  29. I plan to finish the classes and will rewrite them on my home machine ("clean 
  30. room") so that I can present a series in EDM/2  on their design and 
  31. implementation. 
  32.  
  33. Regarding the Future of the Magazine 
  34.  
  35. It needs to be stated again that the magazine will not be charging for 
  36. subscriptions.  Enough said. 
  37.  
  38. We are behind schedule in our preparation for this change, however; originally, 
  39. it was intended that the first issue should be in July (volume 3, issue 7). 
  40. This deadline can still be made, but we are far from completion of the steps 
  41. necessary to enact the change.  Just thought you'd like to know. 
  42.  
  43. Letters and Announcements 
  44.  
  45. We have been getting scarce feedback, although better than nothing, about the 
  46. new Letters and Announcements sections.  We are glad that you enjoy them.  I 
  47. will reiterate the need for new columnists, however. Please send mail to me - 
  48. os2man@panix.com - if you're interested. Also, authors are always welcome; 
  49. please get the latest Article Submission Guidelines if you plan to write an 
  50. article for the magazine. 
  51.  
  52.  
  53. ΓòÉΓòÉΓòÉ 2. Copyright Notice ΓòÉΓòÉΓòÉ
  54.  
  55. Copyright Notice 
  56.  
  57. EDM/2 is published by IQPac Inc.  IQPac Inc. can be reached via U.S. Mail at 
  58. the following address: 
  59.  
  60. IQPac Inc.
  61. 7 East Broadway, Box 804
  62. New York, NY 10038
  63. U.S.A.
  64.  
  65.  Editor-in-chief     Larry Salomon Jr. 
  66.  Associate editor    Carsten Whimster 
  67.  Contributing editor Gordon Zeglinski 
  68.  
  69.  CEO/President       Larry Salomon Jr. 
  70.  
  71.  All material is copyrighted by its original author.  No part of this magazine 
  72.  may be reproduced without permission from the original author. 
  73.  
  74.  This publication may be freely distributed in electronic form provided that 
  75.  all parts are present in their original unmodified form.  A reasonable fee may 
  76.  be charged for the physical act of distribution; no fee may be charged for the 
  77.  publication itself. 
  78.  
  79.  Neither IQPac Inc. nor this publication are affiliated with International 
  80.  Business Machines Corporation. 
  81.  
  82.  OS/2 is a registered trademark of International Business Machines Corporation. 
  83.  Other trademarks are property of their respective owners.  Any mention of a 
  84.  product in this publication does not constitute an endorsement or affiliation 
  85.  unless specifically stated in the text. 
  86.  
  87.  The OS/2 Accredited Logo is a trademark of International Business Machines 
  88.  Corporation and is used by IQPac Inc. under license.  This On-line Publication 
  89.  is independently produced by IQPac Inc. and IBM is not responsible in any way 
  90.  for its contents. 
  91.  
  92.  IQPac Inc. is an accredited member of the IBM Independent Vendor League. 
  93.  
  94.  Copyright Notice - EDM/2 - May 1995 - Volume 3, Issue 5 
  95.  
  96.  
  97. ΓòÉΓòÉΓòÉ 3. Letters ΓòÉΓòÉΓòÉ
  98.  
  99. Letters 
  100.  
  101. To write to EDM/2, send your email to os2man@panix.com and use the Subject: 
  102. line "Letters". 
  103.  
  104. HTML Revisited 
  105.  
  106. Ernest T Christley (ernestc@mercury.interpath.net) writes: 
  107.  
  108. "I took interest in the fact that with issue 4 many of your readers are 
  109. requesting EDM/2 in HTML format.  You should seriously consider adopting Howard 
  110. Gilbert's 'Sphydir'.  It will generate HTML and IPF code simultaneously, and 
  111. makes HTML production a no-brainer, drag-and-drop, WPS enabled walk in the 
  112. park." 
  113.  
  114. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  115.  
  116. Scratch Patch Resurrected 
  117.  
  118. scratch01@aol.com writes: 
  119.  
  120. "If  you still answer these in EDM/2, I have a question  that shouldn't be too 
  121. difficult...(why do I feel like I've missed something really obvious?) 
  122.  
  123. I've noticed in several of the IBM apps (ex.  VIEW.EXE) which use an MDI, the 
  124. main window's system menu is the standard system menu.  However the system menu 
  125. on any child windows is different in that it uses CTRL key combinations instead 
  126. of ALT key combinations.  I've noticed this behavior in several MDI type 
  127. Windows applications.  Is there a simple way to do this for child windows, or 
  128. would I have to 'manually' change each system menu entry at window creation 
  129. time?" 
  130.  
  131. Larry Salomon Jr. responds: 
  132.  
  133. What needs to be done is to create your own accelerator table in your resource 
  134. file, load it using WinLoadAccelTable, and then set it as the child frame using 
  135. WinSetAccelTable.  On the WinSetAccelTable call, make sure that the last 
  136. parameter is not NULLHANDLE, or you'll replace the accelerator table for the 
  137. entire application. 
  138.  
  139. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  140.  
  141. Sprites and the Magical Color Black 
  142.  
  143. Jonathan Abbey (jonabbey@eden.com) writes: 
  144.  
  145. "Hi Larry.  I'm trying to make use of some of the ideas that you put together 
  146. in the sprite library you presented in EDM/2.  I'm trying to do this on a cross 
  147. platform basis (we are developing class libraries for a game we're doing and we 
  148. want the class interface to be portable across OS/2 PM, X, and Windows, if not 
  149. Mac as well), and I'm wondering whether the techniques you presented would be 
  150. able to work if the transparent color was not black. 
  151.  
  152. That is, is there something magical about black?  Is it guaranteed to map into 
  153. all 0 bits on the display or something? 
  154.  
  155. I guess if I can't figure out some way to be able to use an arbitrary 
  156. transparency index, I could remap things, so that all black turns into 0,0,1 or 
  157. some such, and the transparency index is converted to black. 
  158.  
  159. I guess the only other ways of doing it would be by using GpiSetPel and/or by 
  160. cutting chunks out of large sprites, convert them to icons, and blit them bit 
  161. by bit to an off screen buffer, then swap it onto screen. 
  162.  
  163. Yuck.  I can't believe the GPI doesn't provide for 3 blit operands. 
  164.  
  165. Anyway, thanks for any clarification you might be able to provide." 
  166.  
  167. Larry Salomon Jr. responds: 
  168.  
  169. The color black was chosen in conjunction with the ROP operation specified in 
  170. creating the monochrome bitmask.  Think of how the process works conceptually 
  171. and then consider how you would create the mask.  You might be able to try the 
  172. mapping method that you hinted at, but I do not know if it would work. 
  173. Converting the sprites to icons will not work because the algorithm presented 
  174. in the series is identical in concept to that which the system uses, except 
  175. that the application is responsible for creating the masks and not the system. 
  176.  
  177. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  178.  
  179. Custom Controls Needs a Custom Fix 
  180.  
  181. Mark Mathews (mark.mathews@channel1.com) writes: 
  182.  
  183. "The article 'Building Custom Controls' was great!  We are porting DEU (for 
  184. DOOM) to OS/2 and we have been stuck on how to make a status bar for about 1 
  185. month.  Thank you!!!!! 
  186.  
  187. In the EDITOR1 example one should use the height from MINMAX instead of the 
  188. MENU.  The reason is when changing the window size the height of the menu may 
  189. change, where MINMAX will not change. 
  190.  
  191. Did anyone try to compile the source code with C Set++ 2.1?  I tried to compile 
  192. EDITOR1.RC and I keep getting errors on MIS_BITMAP.  I'm not sure yet. I'll 
  193. investigate. 
  194.  
  195. I'm sending you EDITOR2.ZIP.  I modified EDITOR to only have a status bar and 
  196. vertical and horizontal scrollbars ONLY.  It works fine.  My question is, what 
  197. is the the square windows on the lower right side of the window where the 
  198. horizontal and vertical scrollbars meet?  For some reason that section has 
  199. become transparent.  Can you help me? 
  200.  
  201. I also want to say excellent work on the article 'Making Executable Smaller.' 
  202. Could the author expand on the subject of optimizing C code.  Over the years 
  203. there are little tricks you can use to make the code faster and smaller.  For 
  204. example,    junk =3;    if (temp==45)     junk = 5; is faster and smaller than: 
  205. junk = temp==45 ? 5 : 3 
  206.  
  207. BTW, if EDM/2 goes public please don't write articles like the other 
  208. programmers' magazines.  Continue just what your doing.  If you do that I will 
  209. be first in line to buy an EDM/2 subscription." 
  210.  
  211. Eric Slaats responds: 
  212.  
  213. Your suggestion to use the min/max control to set the statusbar height is 
  214. really elegant.  If the menu height changes, the statusbar height will also 
  215. change.  This solution prevents it, excellent.  I'm afraid I can't help you 
  216. with your C-Set 2.1 problem.  I don't own C-Set, and I don't know anyone who 
  217. does (or anyone who builds programs under OS/2 for that matter).  Maybe someone 
  218. else can address this matter.  The problem you've got with the scrollbars 
  219. really baffles me.  When I executed your .EXE file, it clearly showed the 
  220. transparent area.  After recompilation however, it was gone!  I wasn't able to 
  221. invoke the error again.  However I've noticed that a PM program can be 
  222. extremely sensitive to compiler settings.  When using the MLE control I 
  223. couldn't get the find message to work properly.  I've tried recompiling 
  224. examples that worked properly, but it would not work.  After toying with the 
  225. compiler settings after reading about smaller .EXE files, I noticed that these 
  226. messages worked!  Maybe there's a solution here (keep me posted).  I've added a 
  227. the new EDITOR.CPP code (in CUSTOM.ZIP).  This new code uses your min/max trick 
  228. and it is modified so that the ALT key combinations will work. 
  229.  
  230. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  231.  
  232. scratch01@aol.com writes: 
  233.  
  234. "Your  article  in the April '95 edition of EDM/2  ['Building Custom Controls'] 
  235. has been very helpful.  I have one question about the toolbar.  In the article 
  236. you said something to the effect of '...the last menu loaded is the one 
  237. attached to the frame...'  (the same thing is mentioned in a similar example 
  238. from IBM on Hobbes called FRMSUB.ZIP).  However I have run into a difficulty 
  239. with this.  When I press the ALT key (or the combination of ALT-anything) the 
  240. only menus that respond are the system menu and the toolbar (respond, as in 
  241. becoming selected or 'indented').  There is no response from the main (text) 
  242. menu.  In fact, the only way to get a response is to use the mouse.  If you are 
  243. aware of this, do you have a solution? 
  244.  
  245. BTW, I tried reversing the loading order of the WinLoadMenu statements, and the 
  246. program trapped." 
  247.  
  248. Eric Slaats responds: 
  249.  
  250. The ALT thing you've noticed is a bug.  I personally never use this feature but 
  251. (as your messages states) others do.  It was rather sloppy to overlook this 
  252. problem.  So I've come up with a solution.  (The code is included in 
  253. CUSTOM1.ZIP).  Simply reversing the loading order of the WinLoadMenu statements 
  254. isn't a solution.  The program will trap because the last loaded menu (toolbar) 
  255. in this case will be handled twice and the menu won't be handled.  So how does 
  256. this new code work? 
  257.  
  258. The first thing we do is (indeed) swapping the WinLoadMenu statements so the 
  259. Toolbar will be loaded last.  This way the toolbar will be loaded last and it 
  260. will be treated like a regular menu.  Next we change the subclass window 
  261. procedure for the frame window.  It must size and place the normal menu window. 
  262. So where at first the toolbar was handled we will now handle the menu.  It is 
  263. still desirable that the toolbar is placed under the menubar. The toolbar is 
  264. now placed on top of the client window.  So we have to put the menubar on top 
  265. and replace the toolbar directly underneath it.  This is done by the following 
  266. lines: 
  267.  
  268.      pSWP[usMenu].x = pSWP[usToolbar].x;
  269.      pSWP[usMenu].y = pSWP[usToolbar].y +
  270.                          pSWP[usToolbar].cy -
  271.                          pSWP[usMenu].cy;
  272.      pSWP[usToolbar].y = pSWP[usMenu].y - pSWP[usToolbar].cy;
  273.  
  274. The menubar is placed on top by using the position and cy of the toolbar. 
  275. (Remember the toolbar has a larger height than the menubar).  The last line 
  276. replaces the toolbar just under the menubar.  So now every control has its 
  277. desired place and the ALT keys will work properly because the PM will attach 
  278. them to the menubar (highest menu loaded) 
  279.  
  280. The code changes are marked with CODE CHANGE !!!!!!!!! 
  281.  
  282. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  283.  
  284. Kudos and Stuff 
  285.  
  286. Graham TerMarsch (cs27524@vcc8.langara.bc.ca) writes: 
  287.  
  288. Well, just finished reading EDM/2 volume 3, issue 3, and decided that I've just 
  289. got to write and tell you a few things... 
  290.  
  291. Firstly, thank you so much for releasing EDM/2.  I've searched for, hoarded, 
  292. handed out, and read every single issue since its beginning and have loved 
  293. every issue; they were all helpful for something I've been working on. 
  294.  
  295. If you're still accepting snippets, I'm sure I've got a few lying around that 
  296. I'd send along.  I know it might be too little too late and have no excuse for 
  297. it, but if you'd like some I'd be happy to send them along. 
  298.  
  299. As for what I'd like to see in an upcoming issue, I'll put my vote in with the 
  300. gentleman who suggested some info on making toolbars and button bars for an 
  301. application.  I've spoken to several developers who all do it different, from 
  302. creating it as another menu option on the frame to creating a completely new 
  303. frame control from scratch.  In a more broad sense, subclassing of windows 
  304. would be a really good topic; most everything I'm hung up on right now reflects 
  305. not knowing how to take proper advantage of window subclasing (especially the 
  306. frame window).  Ok, maybe I'm a bit selfish on this but I'm allowed, it's my 
  307. suggestion.  <grin> 
  308.  
  309. I won't babble forever, but will instead thank you and all of the contributors 
  310. to EDM/2 once again for the service that you've done to all OS/2 developers.  I 
  311. can say that if it wasn't for EDM/2, I probably would've given up on trying to 
  312. further my PM programming skills and would've just bought a quick and dirty 
  313. package instead. 
  314.  
  315. Letters - EDM/2 - May 1995 - Volume 3, Issue 5 
  316.  
  317.  
  318. ΓòÉΓòÉΓòÉ 4. Announcements ΓòÉΓòÉΓòÉ
  319.  
  320. Announcements 
  321.  
  322. New Book Explains OS/2 Graphics Interface 
  323.  
  324. A new book from John Wiley & Sons addresses the Graphics Programming Interface 
  325. (GPI) for OS/2 Warp, providing step-by- step instructions and accompanying 
  326. coding examples.  The book, written by Stephen Knight and Jeffrey Ryan, covers 
  327. the full range of OS/2 GPI functions, including the latest additions to OS/2 
  328. Warp Version 3. 
  329.  
  330. Programming the OS/2 Warp Version 3 GPI includes: 
  331.  
  332.      Drawing primitives 
  333.      Working in coordinate spaces 
  334.      Character fonts, metrics, sizing and positioning 
  335.      Metafiles 
  336.      Transformations 
  337.      Over 60 screen shots, drawings and tables 
  338.  
  339.  Accompanying disk includes: 
  340.  
  341.      Graphics editor application 
  342.      Text browser file 
  343.      Query printer information 
  344.      Other utilities 
  345.  
  346.  The book (416 pages, $39.95 U.S.)  can be ordered as ISBN 0- 471-10718-2 or 
  347.  through IBM as SR28-5681.  Publisher's order line:  (800) CALL-WILEY 
  348.  (800-225-5945).  Fax:  (908) 203- 3200.  For more information, e-mail: 
  349.  CompBks@JWiley.Com. 
  350.  
  351.  John Wiley & Sons, a leading supplier of books about OS/2 and related 
  352.  products, is a member of IBM's Independent Vendor League (IVL).  The IVL 
  353.  supports individuals and companies who develop and market books, newsletters, 
  354.  magazines, training videos, courseware and consulting services for OS/2 and 
  355.  other IBM personal software products. 
  356.  
  357.  This news release is from the IBM IVL News Service and may be freely copied 
  358.  and distributed.  For information about the IVL, call (203) 452-7704, fax 
  359.  (203) 268-1075 or e-mail gailo@vnet.ibm.com.  Send news and distribution 
  360.  changes to ivlinfo@vnet.ibm.com.  (OS/2 is a registered trademark of IBM 
  361.  Corporation.) 
  362.  
  363.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  364.  
  365.  OS/2 Utilities CD-ROM Is Now Shipping 
  366.  
  367.  EMS Professional Shareware is now shipping the 15th (Apr'95) edition of its 
  368.  OS/2 Utilities CD-ROM, with 774 carefully selected PD/Shareware ZIP files and 
  369.  a database and search program so you can quickly find/view/copy/etc.  $25 
  370.  special "Net" price includes 3 CD-ROMs with a free copy of the 211,000 record 
  371.  PC products database. 
  372.  
  373.   EMS Professional Shareware
  374.   4505 Buckhurst Ct.
  375.   Olney MD 20832-1830
  376.  
  377.   Voice:  301-924-3594
  378.   Fax:  301-963-2708 ems@wdn.com
  379.   http://www.xmission.com/~wwwads/ems
  380.  
  381.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  382.  
  383.  Perl 4 With Sockets 
  384.  
  385.  Located at hobbes.nmsu.edu /os2/unix/sockperl.zip 
  386.  
  387.  Perl for OS/2 with sockets.  (This build also has use of crypt(), fork() and 
  388.  -D debug options.)  Built using EMX 09a with fix03 applied.  This build passes 
  389.  all the regression tests as the distribution version of perl.exe.  Of course 
  390.  this version won't run under dos at all, presumably the sock_ini call is 
  391.  protect-mode only. 
  392.  
  393.  While perl5 with sockets is available also, some sites / systems may not be 
  394.  able to support this larger .EXE, .DLL. 
  395.  
  396.  No changes were made to Kai's sources for Perl / OS/2. 
  397.  
  398.  I've run the entire test battery (using a csh script, as I don't have MAKE). 
  399.  Aside from pure Unix-isms and problems in comparing strings with '<cr><lf>' on 
  400.  OS/2, the only unexplained error I found was in op/magic.t, where SIG action 
  401.  "DEFAULT" is supported?  The only other anomaly is that this perl stops 
  402.  creating new sockets after the 257th.  Perhaps this is an OS/2 or OS/2 TCP/IP 
  403.  limitation. 
  404.  
  405.  I have taken reasonable care in testing the resultant binary, but of course 
  406.  there is NO WARRANTY.  I have tested only a small subset of the Perl or EMX 
  407.  support for Berkeley sockets. 
  408.  
  409.  Thanks as always to Larry for Perl, Kai for the OS/2 version, and Eberhard 
  410.  Mattes for the excellent EMX environment. 
  411.  
  412.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  413.  
  414.  Adams-Blake Publishing Announces Book on How To Be A Consultant 
  415.  
  416.  People who are proficient in OS2 programming have a unique opportunity to work 
  417.  independently as a contract consultant.  While not for everyone, for most, 
  418.  doing contract work will result in a significant increase in income. Others, 
  419.  especially those with children or other responsibilities, prefer the more 
  420.  flexible work schedule.  There are also those who seek to work out of their 
  421.  home.  However, it is not get-rich-quick by any stretch of the imagination. 
  422.  
  423.  Starting an independent consulting business is not the easiest thing in the 
  424.  world but it's absolutely doable by most technically skilled people.  Finding 
  425.  clients and knowing how to conduct oneself in face-to-face sales situations 
  426.  are the two most difficult tasks for most people.  Those who want to work 
  427.  through brokers or agents can do so, but they have to know how to negotiate so 
  428.  the agent doesn't end up with all the money. 
  429.  
  430.  Technical people have the most difficulty with sales and marketing. Marketing 
  431.  is not sales.  Marketing is finding someone to sell to.  Sales is the 
  432.  face-to-face meeting.  With respect to face-to-face sales, it is not like a 
  433.  job interview.  You must be in control and direct each "scene" of the play. 
  434.  You're equal, not subservient to the client.  There is no one strategy but 
  435.  there are many different ways the technical sale can be (or should be) closed. 
  436.  
  437.  There are a multitude of agents who act as third party matchmakers.  This can 
  438.  be a good way to start out, however you will give up a good part of your 
  439.  billing income.  With agents, there are many contract pitfalls, such as the 
  440.  "you're not paid until we're paid" clause you must be aware of and be able to 
  441.  negotiate around. 
  442.  
  443.  And of course, you have to be qualified.  Yet, it's not technical knowledge 
  444.  that is the most necessary ingredient to success.  You must have a take-a-risk 
  445.  personality.  You have to want an "adventure."  You have to be motivated by 
  446.  money because no one is going to stroke your ego while on the job. 
  447.  
  448.  Our publishing company has a 320 page title on the subject of technical 
  449.  consulting. 
  450.  
  451.  With respect to the non-commercial nature of this group, we do not mention 
  452.  title, price or availability.  This announcement is neither an offer to sell, 
  453.  nor a solicitation of an offer to buy.  The offer is made only by the 
  454.  prospectus. 
  455.  
  456.  If you have an interest and would like information, contact us by e-mail. 
  457.  
  458.   Jennifer Church
  459.   Adams-Blake Publishing
  460.   abpub@aol.com
  461.  
  462.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  463.  
  464.  Designing Object-Oriented User Interfaces 
  465.  
  466.  IS International's four-day course on designing user interfaces has been 
  467.  updated to include designing interfaces for OS/2 Warp.  The course 
  468.  incorporates presentations, demonstrations, workshops, and a sample 
  469.  application scenario to teach the complete object-oriented interface design 
  470.  process. 
  471.  
  472.  Topics include: 
  473.  
  474.      GUI / OOUI history, concepts and philosophy 
  475.      User interface design principles and benefits 
  476.      Design process 
  477.      Task analysis 
  478.      Components and interaction 
  479.      Designing, building and testing low fidelity prototypes 
  480.      Developing prototypes with IBM's VisualAge 
  481.  
  482.  The course is offered in both public and on-site venues.  It is also available 
  483.  through IBM's Object Technology University and IBM Education and Training as 
  484.  the Designing Object- Oriented Interfaces Workshop, course N5010. Sessions are 
  485.  taught by Ian Stopps and Harris Kravatz, both experienced in the design, 
  486.  teaching and documentation of user interfaces, including IBM's Common User 
  487.  Access (CUA) standard. 
  488.  
  489.  For more information, contact IS International at (800) 276- 1075, fax (407) 
  490.  994-4373, e-mail info@isii.com, or http://www.isii.com. 
  491.  
  492.  IS International, an advanced education and consulting company specializing in 
  493.  object-oriented design and development, is a member of IBM's Independent 
  494.  Vendor League (IVL).  The IVL supports individuals and companies who develop 
  495.  and market books, newsletters, magazines, training videos, courseware and 
  496.  consulting services for OS/2 and other IBM personal software products. 
  497.  
  498.  This news release is from the IBM IVL News Service and may be freely copied 
  499.  and distributed.  For information about the IVL, call (203) 452-7704, fax 
  500.  (203) 268-1075 or e-mail gailo@vnet.ibm.com.  Send news and distribution 
  501.  changes to ivlinfo@vnet.ibm.com.  (OS/2 is a registered trademark of IBM 
  502.  Corporation.) 
  503.  
  504.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  505.  
  506.  GNU Fortran (G77) Has Been Ported To EMX. 
  507.  
  508.  It's available for anonymous ftp on ftp.uni-stuttgart.de.  Look for g77bin.zip 
  509.  (binaries) and g77src.zip (source) in directory 
  510.  /pub/systems/os2/emx0.9a/contrib. 
  511.  
  512.  It's also available for anonymous ftp on ftp.leo.org.  Look for g77bin.zip 
  513.  (binaries) and g77src.zip (source) in directory 
  514.  /pub/comp/os/os2/gnu/emx+gcc/contrib. 
  515.  
  516.  Please note that this is a quite early release of g77 and has several bugs. 
  517.  Please send bug reports for g77 to the address given in 
  518.  /emx/gnu/gcc-2.6/f/INSTALL, except for bugs introduced by the port, which 
  519.  should be reported to me. 
  520.  
  521.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  522.  
  523.  FREE DEMO - ZGRAF C++ Graph Toolkit 
  524.  
  525.  The ZGRAF C++ Graph Toolkit is a library of routines for making tech/business 
  526.  graphs in several environments, including OS/2 Presentation Manager and 
  527.  Windows/Windows NT. 
  528.  
  529.  Graph styles include X/Y, Bar, Pie, Area, Ribbon, Scatter, Polar, Log, 2-D 
  530.  Function, 3-D Surface Graphs, Smith Chart, and more!  The toolkit sells for 
  531.  $30 (Personal Version) or $45 ( Commercial Developer Version) and includes 
  532.  full C++ library source code.  There are no royalties. 
  533.  
  534.  You can download a free demo from our BBS (see phone number below).  For a 
  535.  demo disk, just send e-mail with your name/address/company information 
  536.  (Serious inquiries only, please.  Allow 2-4 weeks for delivery). 
  537.  
  538.  Thanks for your interest in our products. 
  539.  
  540.   ZGRAF Software Products
  541.   1831 Old Hickory Ct.
  542.   New Albany, IN 47150
  543.  
  544.   Phone:     (812) 949-9524
  545.   BBS:    (812) 949-0416, 14.4K/9600 BPS, 8/1/None
  546.   Compuserve:   70742,1356
  547.  
  548.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  549.  
  550.  REXX Cookbook by Merrill Callaway 
  551.  
  552.  The REXX Cookbook by Merrill Callaway is now available from WHITESTONE. The 
  553.  319-page book is a tutorial written for both beginners and more experienced 
  554.  programmers.  Extensive use of REXX programming examples helps illustrate 
  555.  topics in a real-life context.  In addition to basic concepts, The REXX 
  556.  Cookbook shows how to write programs that work with everyday OS/2 applications 
  557.  and files, including PostScript, Structured Query Language (SQL), DB2/2, 
  558.  AmiPro, and others. 
  559.  
  560.  The REXX Cookbook, ISBN # 0-9632773-4-0, sells in the U.S.  for $27.95.  A 
  561.  companion disk, THE REXX FILES, ISBN # 0- 9632773-5-9, is priced at $14.95 
  562.  U.S. 
  563.  
  564.  For more information, contact WHITESTONE at e-mail 5979987@MCIMAIL.COM or 
  565.  Voice (505) 268-0678. 
  566.  
  567.  WHITESTONE, a publisher of books about OS/2 and related products, is a member 
  568.  of IBM's Independent Vendor League (IVL).  The IVL supports individuals and 
  569.  companies who develop and market books, newsletters, magazines, training 
  570.  videos, courseware and consulting services for OS/2 and other IBM personal 
  571.  software products. 
  572.  
  573.  This news release is from the IBM IVL News Service and may be freely copied 
  574.  and distributed.  For information about the IVL, call (203) 452-7704, fax 
  575.  (203) 268-1075 or e-mail gailo@vnet.ibm.com.  Send news and distribution 
  576.  changes to ivlinfo@vnet.ibm.com. 
  577.  
  578.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  579.  
  580.  JYACC Announces JAM For OS/2 At DB-Expo 
  581.  
  582.  DB-EXPO, San Francisco, CA - May 2, 1995 - Today, JYACC, Inc., announced the 
  583.  OS/2 version of JAM (JYACC Application Manager), the leading cross-platform 
  584.  tool for building client/server and distributed applications. JYACC will show 
  585.  the new release for the first time at DB-Expo Booth 1162 in San Francisco's 
  586.  Moscone Center. 
  587.  
  588.  JAM for OS/2 allows developers to build 32 bit GUI applications that fully 
  589.  exploit the stability and preemptive multi-tasking features of the OS/2 
  590.  platform, said Darryl Zack, JYACC Vice President of Sales and Marketing.  The 
  591.  ability to build OS/2 applications with JAM and re-deploy them on over 100 
  592.  platforms and operating environments is an essential component in our 
  593.  customers enterprise computing strategy. 
  594.  
  595.  With the release of JAM for OS/2 Warp, customers will be able to build and 
  596.  deploy business-critical applications that are portable enough to span the 
  597.  enterprise, said Jim Grant, Vice President, IBM Solution Developer Operations. 
  598.  This new product from JYACC continues their tradition of support for IBM 
  599.  client/server solutions, including AIX on the RS/6000, and DB2/2 and 
  600.  represents another important vendor who has committed support for OS/2, the 
  601.  industry's leading 32-bit operating system. 
  602.  
  603.  Applications developed with JAM for OS/2 can be deployed on OS/2 versions 2.x 
  604.  and Warp, as well as 100 other platforms and operating environments, including 
  605.  MS-Windows, DOS, Motif, VAX/VMS, Macintosh, and virtually every implementation 
  606.  of UNIX.  JAM also integrates seamlessly with more than twenty of the most 
  607.  popular RDBMS products, and provides transparent access to legacy systems via 
  608.  DRDA and Microsofts ODBC. 
  609.  
  610.  The $2,000 JAM for OS/2 package includes: 
  611.  
  612.      The complete JAM development environment. 
  613.      A database driver for JYACCs built-in prototyping database (JDB). 
  614.      A second, customer-selected database driver.  (Users can purchase 
  615.       additional database drivers if they wish.  Drivers are currently 
  616.       available for Oracle, Sybase, Informix, and DB2.  Drivers for other RDMS 
  617.       products will be offered later this year.) 
  618.      Complete documentation. 
  619.  
  620.  JAM for OS/2 continues the JYACC tradition of never charging runtime fees. 
  621.  
  622.  Contact:  Eric Block (212) 267-7722 or royalties for JAM-built applications. 
  623.  
  624.  About JAM and JYACC 
  625.  
  626.  JAM combines four significant advanced technologies -- visual programming, 
  627.  repository-driven development, object- orientation, and high performance 
  628.  transaction management.  In addition to offering a fully graphical development 
  629.  environment, JAM is the industry's most advanced application development tool 
  630.  in delivering codeless programming and productivity.  JAM is the centerpiece 
  631.  of a fully integrated family of application development products that includes 
  632.  a report writing tool, and interfaces to more than 20 database engines, the 
  633.  leading transaction monitors (including Novell's TUXEDO and Transarc's 
  634.  Encina), and CASE tools (including Cadre's Teamwork and Innovator SERM from 
  635.  MID, GmbH of Germany). 
  636.  
  637.  JYACC offers products and services that enable developers to build high 
  638.  performance client/server applications quickly and cost-effectively, integrate 
  639.  them into their business environment, and maximize each application's value. 
  640.  Founded in 1978 as a software consulting firm, JYACC first shipped JAM in 
  641.  1985.  With ten years as an industry leader and tens of thousands of JAM 
  642.  development licenses sold worldwide, JYACC has impeccable credentials in the 
  643.  open systems marketplace.  Thanks to its power and field-proven performance, 
  644.  JAM has been selected by IS organizations throughout the Fortune 1000 to build 
  645.  the most demanding, mission critical applications.  JYACC is based in New York 
  646.  City with offices in Boston, Massachusetts; Parsippany, New Jersey; San 
  647.  Francisco, California; Chicago, Illinois; Atlanta, Georgia; and Orlando, 
  648.  Florida.  JYACC also has offices in London (UK) and Paris, France.  JYACC 
  649.  Headquarters is located at 116 John Street, New York, New York 10038. 
  650.  
  651.  JAM and Jterm are registered trademarks of JYACC, Inc.  JAM/TPi, JAM/CASE 
  652.  interface, and JAM/ReportWriter are trademarks of JYACC.  OS/2 and Warp are 
  653.  registered trademarks of IBM, Corporation.  Other brands and product names 
  654.  appearing in this document may be trademarks or registered trademarks of their 
  655.  respective companies. 
  656.  
  657.  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  658.  
  659.  Prominare Launches Prominare Designer 
  660.  
  661.  Prominare Designer, an OS/2 PM programmer's Rapid Application Development tool 
  662.  for creating fully featured GUIs for OS/2, has been launched by Prominare 
  663.  Inc., of Canada. 
  664.  
  665.  Prominare Designer allows the developer to create visual interfaces for an 
  666.  application in a matter of minutes without having to write any source code. 
  667.  This productivity gain remains high throughout the development of the 
  668.  application, even as new visual interface elements are added. 
  669.  
  670.  Prominare Designer generates code for multiple class libraries and multiple 
  671.  compilers, and offers the capability to generate code across platforms, e.g. 
  672.  OS/2, Windows 3.1, and Windows NT, all from one tool.  This feature makes the 
  673.  process of developing for multiple platforms easy. 
  674.  
  675.  Acting as an extended resource editor, Prominare supports all versions of 
  676.  OS/2, including Warp.  Its inherent flexibility enables the power of C and C++ 
  677.  to be fully exploited, with the added benefits of intelligent code generation. 
  678.  Programmers can construct compact, efficient code without unnecessary 
  679.  overheads or proprietary modules. 
  680.  
  681.  Programmers can use one interface to create both the resources and source code 
  682.  for PM applications.  The resource editing capabilities of Prominare are 
  683.  backwardly compatible with all versions of OS/2.  This offers unique 
  684.  facilities in the areas of custom controls and PM Control Extensions (PMCX), 
  685.  facilities which are lacking in other tools. 
  686.  
  687.  Prominare supports all OS/2 PM controls including multimedia (MMPM/2) and Pen 
  688.  for OS/2. 
  689.  
  690.  Another impressive ability is that of Prominare-created applications to easily 
  691.  conform to individual companies' programming standards, coding conventions and 
  692.  selected level of CUA compliance.  This ability to allow programmers to modify 
  693.  Prominare's source code generation rules ensures that the source code 
  694.  generated conforms with company naming conventions and coding standards. 
  695.  
  696.  This capability is essential for speeding up programming in major companies 
  697.  which are developing large applications, as the code is in a form that their 
  698.  programmers already understand. 
  699.  
  700.  Matt Smith, Prominare Designer architect, said, "Prominare speeds the process 
  701.  by removing unnecessary generation phases.  When the visual design for the 
  702.  application is modified, Prominare adds source code for only the parts that 
  703.  have been modified since the last generation operation was carried out. 
  704.  
  705.  "Prominare's inherent intelligence enables the application developer to change 
  706.  the look and feel of the interface without having to reprogram the actions of 
  707.  individual controls.  The application developer can add his or her own source 
  708.  code to that generated and Prominare ensures that the application developer's 
  709.  source code remains untouched the next time a change is made to the visual 
  710.  design, even when new source code based on the changes is added. 
  711.  
  712.  Prominare Designer has a suggested retail price of $699 (US) and can be 
  713.  ordered through Indelible Blue, Programmer's Paradise, Egghead Software, OS/2 
  714.  Express, ImageSoft in the US.  In the UK, it can be order through 
  715.  Microtransfer and OneStop OS/2.  A complete list of qualified resellers can 
  716.  found through Prominare's WWW server at http://www.prominare.com/prominare. 
  717.  
  718.  Further detail on Prominare Designer can be found through Prominare's WWW 
  719.  server or by sending email to designer@prominare.com. 
  720.  
  721.  Prominare is the Latin word which means "to drive forward," and Prominare 
  722.  Designer allows developers to do just that. 
  723.  
  724.  Announcements - EDM/2 - May 1995 - Volume 3, Issue 5 
  725.  
  726.  
  727. ΓòÉΓòÉΓòÉ 5. The Design and Implementation of VIOWIN (Part 8) ΓòÉΓòÉΓòÉ
  728.  
  729.  
  730. ΓòÉΓòÉΓòÉ 5.1. Introduction ΓòÉΓòÉΓòÉ
  731.  
  732. The Design and Implementation of VIOWIN (Part 8) 
  733.  
  734. Written by Larry Salomon, Jr. 
  735.  
  736. Introduction 
  737.  
  738. For my job, I once had to write an application that ran only when OS/2 booted 
  739. from the floppy diskettes.  Because I had no access to the functionality PM 
  740. provides, I resorted to a line-oriented interface, where messages were 
  741. displayed on the screen and scrolled up when necessary.  It was a good 
  742. interface, I thought; it was fully NLS enabled and had intelligent defaults so 
  743. the user basically only had to type in the name of the application. 
  744. Unfortunately, the Quality Assurance team didn't concur with my opinion.  "We 
  745. want a nice interface!"  one exclaimed.  "Yeah, one with different windows and 
  746. such!"  another shouted. 
  747.  
  748. I was backed into a corner that I could only get out of one way. 
  749.  
  750. This series describes the design and implementation of VIOWIN, a library that 
  751. implements a subset of the Win APIs provided by PM for fullscreen sessions. 
  752. The reasoning behind writing this series is that it provided me and will 
  753. hopefully provide you with some unique insights into how a windowing system is 
  754. developed; and since it is based on PM, your familiarity with the already 
  755. defined interface will increase your capability to fully understand what is 
  756. being described. 
  757.  
  758. Obviously, this series assumes you have PM application development experience, 
  759. but it isn't required. 
  760.  
  761. This Month 
  762.  
  763. This month, we will (finally) wrap up the series with the VWWC_BUTTON class. 
  764.  
  765. The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3, 
  766. Issue 5 
  767.  
  768.  
  769. ΓòÉΓòÉΓòÉ 5.2. Button Controls ΓòÉΓòÉΓòÉ
  770.  
  771. Button Controls 
  772.  
  773. VIOWIN implements three types of button controls: pushbuttons, checkboxes, and 
  774. radiobuttons. Checkboxes and radiobuttons are assumed to be the "auto" type, 
  775. meaning that they process the painting themselves. Ownerdrawn buttons are not 
  776. supported.  I need not describe the functionality of each, but it should be 
  777. noted that even though all three types belong to the same window class, they 
  778. are different enough that they can "logically" be considered of distinct 
  779. classes. 
  780.  
  781. There are four helper functions used by the static control (the term "subclass" 
  782. is used below to refer to the different types of button classes): 
  783.  
  784. pushButtonProc() - processes the messages for the push button "subclass." 
  785.  
  786. checkBoxProc() - processes the messages for the check box "subclass." 
  787.  
  788. radioButtonProc() - processes the messages for the radio button "subclass." 
  789.  
  790. findGroupButton() - finds a specified radio button within a group (first, last, 
  791. previous, or next). 
  792.  
  793. The first three simply process the WM_PAINT, WM_CHAR, and BM_ messages. 
  794.  
  795. The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3, 
  796. Issue 5 
  797.  
  798.  
  799. ΓòÉΓòÉΓòÉ 5.3. The Instance Data and Other Things ΓòÉΓòÉΓòÉ
  800.  
  801. The Instance Data and Other Things 
  802.  
  803. The instance data is shown in the code below.  The definitions of the fields 
  804. are listed afterwards. 
  805.  
  806. #define RB_SELECTED              'o'
  807. #define CB_SELECTED              'x'
  808.  
  809. typedef struct _INSTDATA {
  810.    ULONG ulSzStruct;
  811.    ULONG ulStyle;
  812.    BOOL bChecked;
  813. } INSTDATA, *PINSTDATA;
  814.  
  815.  Field               Definition 
  816.  ulSzStruct          Size of the structure in bytes 
  817.  ulStyle             Style of the window 
  818.  bChecked            TRUE if this is a checkbox and it is checked.  FALSE 
  819.                      otherwise. 
  820.  
  821.  The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 
  822.  3, Issue 5 
  823.  
  824.  
  825. ΓòÉΓòÉΓòÉ 5.4. The pushButtonProc() Function ΓòÉΓòÉΓòÉ
  826.  
  827. The pushButtonProc() Function 
  828.  
  829. The appearance of the button is simply a rectangle with the text centered 
  830. within.  If the button has the focus, the text colors (foreground and 
  831. background) are inverted.  While it would have been nice to draw a border 
  832. around the button, it was determined that the 200% increase in height (since 
  833. extra two rows are necessary but the button only has one row of text) wasn't 
  834. worth it. 
  835.  
  836. MRESULT EXPENTRY pushButtonProc(HVWWND hwndWnd,
  837.                                 ULONG ulMsg,
  838.                                 MPARAM mpParm1,
  839.                                 MPARAM mpParm2)
  840. //-------------------------------------------------------------------------
  841. // This "sub-window procedure" handles the push button-specific messages
  842. //-------------------------------------------------------------------------
  843. {
  844.    PINSTDATA pidData;
  845.  
  846.    pidData=vwQueryWindowPtr(hwndWnd,1);
  847.  
  848.    switch (ulMsg) {
  849.    case WM_PAINT:
  850.       {
  851.          RECTL rclWnd;
  852.          CHAR achText[256];
  853.          ULONG ulFore;
  854.          ULONG ulBack;
  855.  
  856.          vwQueryWindowRect(hwndWnd,&rclWnd);
  857.          rclWnd.xRight--;
  858.          rclWnd.yTop--;
  859.  
  860.          vwQueryWindowText(hwndWnd,sizeof(achText),achText);
  861.  
  862.          ulFore=vwQueryForeColor(hwndWnd);
  863.          ulBack=vwQueryBackColor(hwndWnd);
  864.  
  865.          //----------------------------------------------------------------
  866.          // Fill ourselves with the background color.
  867.          //----------------------------------------------------------------
  868.          vwFillRect(hwndWnd,&rclWnd,ulBack);
  869.  
  870.          //----------------------------------------------------------------
  871.          // If we have the focus, invert the colors to indicate this
  872.          //----------------------------------------------------------------
  873.          if (vwQueryFocus()==hwndWnd) {
  874.             ulFore^=0x000000FF;
  875.             ulBack^=0x000000FF;
  876.          } /* endif */
  877.  
  878.          //----------------------------------------------------------------
  879.          // Draw the button text
  880.          //----------------------------------------------------------------
  881.          vwDrawText(hwndWnd,
  882.                     -1,
  883.                     achText,
  884.                     &rclWnd,
  885.                     ulFore,
  886.                     ulBack,
  887.                     DT_CENTER|DT_VCENTER);
  888.       }
  889.       break;
  890.    case WM_CHAR:
  891.       {
  892.          USHORT usFlags;
  893.          USHORT usMods;
  894.  
  895.          //----------------------------------------------------------------
  896.          // Code like this is what makes me appreciate the similarities
  897.          // of the library to the corresponding PM code.  Here, we
  898.          // check to see if we've been selected using the <SPACE> or
  899.          // <ENTER> keys (either one).
  900.          //----------------------------------------------------------------
  901.          usFlags=KC_VIRTUALKEY | KC_KEYUP;
  902.          usMods=KC_ALT | KC_CTRL | KC_SHIFT;
  903.  
  904.          if ((CHARMSG(&ulMsg)->fs & usFlags)!=usFlags) {
  905.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  906.          } /* endif */
  907.  
  908.          if ((CHARMSG(&ulMsg)->fs & usMods)!=0) {
  909.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  910.          } /* endif */
  911.  
  912.          switch (CHARMSG(&ulMsg)->vkey) {
  913.          case VK_SPACE:
  914.          case VK_ENTER:
  915.          case VK_NEWLINE:
  916.             vwPostMsg(hwndWnd,BM_CLICK,0,0);
  917.             break;
  918.          default:
  919.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  920.          } /* endswitch */
  921.       }
  922.       break;
  923.    case WM_QUERYDLGCODE:
  924.       return MRFROMLONG(DLGC_BUTTON);
  925.    case BM_CLICK:
  926.       vwPostMsg(VWHWND_DESKTOP,
  927.                 WM_COMMAND,
  928.                 MPFROMSHORT(vwQueryWindowUShort(hwndWnd,QWS_ID)),
  929.                 0);
  930.       break;
  931.    case BM_QUERYCHECKINDEX:
  932.       return MRFROMSHORT(-1);
  933.    case BM_QUERYHILITE:
  934.       break;
  935.    case BM_SETHILITE:
  936.       break;
  937.    case BM_QUERYCHECK:
  938.       return MRFROMSHORT(FALSE);
  939.    case BM_SETCHECK:
  940.       return MRFROMSHORT(FALSE);
  941.    case BM_SETDEFAULT:
  942.       break;
  943.    default:
  944.       return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  945.    } /* endswitch */
  946.  
  947.    return MRFROMLONG(FALSE);
  948. }
  949.  
  950. The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3, 
  951. Issue 5 
  952.  
  953.  
  954. ΓòÉΓòÉΓòÉ 5.5. The checkBoxProc() Function ΓòÉΓòÉΓòÉ
  955.  
  956. The checkBoxProc() Function 
  957.  
  958. Note the choice (in the "Instance Data and Other Things" section) of character 
  959. for the checked state of the button ("x").  While "ΓêÜ" is probably a better 
  960. choice, this character might not exist in other codepages, so we'll stick to 
  961. one that is more likely to exist. 
  962.  
  963. MRESULT EXPENTRY checkBoxProc(HVWWND hwndWnd,
  964.                               ULONG ulMsg,
  965.                               MPARAM mpParm1,
  966.                               MPARAM mpParm2)
  967. //-------------------------------------------------------------------------
  968. // This "sub-window procedure" handles the check box-specific messages
  969. //-------------------------------------------------------------------------
  970. {
  971.    PINSTDATA pidData;
  972.  
  973.    pidData=vwQueryWindowPtr(hwndWnd,1);
  974.  
  975.    switch (ulMsg) {
  976.    case WM_PAINT:
  977.       {
  978.          CHAR achFmt[256];
  979.          CHAR chCheck;
  980.          CHAR achText[256];
  981.          ULONG ulFore;
  982.          ULONG ulBack;
  983.  
  984.          vwQueryWindowText(hwndWnd,sizeof(achFmt),achFmt);
  985.  
  986.          //----------------------------------------------------------------
  987.          // See if we're checked and, if so, display the appropriate
  988.          // character in the brackets.
  989.          //----------------------------------------------------------------
  990.          chCheck=pidData->bChecked?CB_SELECTED:' ';
  991.  
  992.          sprintf(achText,"[%c] %s",chCheck,achFmt);
  993.  
  994.          ulFore=vwQueryForeColor(hwndWnd);
  995.          ulBack=vwQueryBackColor(hwndWnd);
  996.  
  997.          //----------------------------------------------------------------
  998.          // If we have the focus, invert the colors to indicate this
  999.          //----------------------------------------------------------------
  1000.          if (vwQueryFocus()==hwndWnd) {
  1001.             ulFore^=0x000000FF;
  1002.             ulBack^=0x000000FF;
  1003.          } /* endif */
  1004.  
  1005.          //----------------------------------------------------------------
  1006.          // Draw the button text as we have built it above
  1007.          //----------------------------------------------------------------
  1008.          vwDrawText(hwndWnd,
  1009.                     -1,
  1010.                     achText,
  1011.                     NULL,
  1012.                     ulFore,
  1013.                     ulBack,
  1014.                     DT_LEFT|DT_VCENTER|DT_ERASERECT);
  1015.       }
  1016.       break;
  1017.    case WM_CHAR:
  1018.       {
  1019.          USHORT usFlags;
  1020.          USHORT usMods;
  1021.  
  1022.          usFlags=KC_VIRTUALKEY | KC_KEYUP;
  1023.          usMods=KC_ALT | KC_CTRL | KC_SHIFT;
  1024.  
  1025.          if ((CHARMSG(&ulMsg)->fs & usFlags)!=usFlags) {
  1026.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1027.          } /* endif */
  1028.  
  1029.          if ((CHARMSG(&ulMsg)->fs & usMods)!=0) {
  1030.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1031.          } /* endif */
  1032.  
  1033.          //----------------------------------------------------------------
  1034.          // If the user pressed the spacebar, toggle the checked state
  1035.          // by sending ourselves a BM_CLICK message
  1036.          //----------------------------------------------------------------
  1037.          switch (CHARMSG(&ulMsg)->vkey) {
  1038.          case VK_SPACE:
  1039.             vwPostMsg(hwndWnd,BM_CLICK,0,0);
  1040.             break;
  1041.          default:
  1042.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1043.          } /* endswitch */
  1044.       }
  1045.       break;
  1046.    case WM_QUERYDLGCODE:
  1047.       return MRFROMLONG(DLGC_BUTTON);
  1048.    case BM_CLICK:
  1049.       //-------------------------------------------------------------------
  1050.       // Toggle the check state, repaint ourselves, and send the
  1051.       // notification to our owner, which is always the desktop.
  1052.       //-------------------------------------------------------------------
  1053.       pidData->bChecked=!pidData->bChecked;
  1054.       vwSendMsg(hwndWnd,WM_PAINT,0,0);
  1055.  
  1056.       vwSendMsg(VWHWND_DESKTOP,
  1057.                 WM_CONTROL,
  1058.                 MPFROM2SHORT(vwQueryWindowUShort(hwndWnd,QWS_ID),
  1059.                              BN_CLICKED),
  1060.                 MPFROMHWND(hwndWnd));
  1061.       break;
  1062.    case BM_QUERYCHECKINDEX:
  1063.       return MRFROMSHORT(-1);
  1064.    case BM_QUERYHILITE:
  1065.       break;
  1066.    case BM_SETHILITE:
  1067.       break;
  1068.    case BM_QUERYCHECK:
  1069.       return MRFROMSHORT(pidData->bChecked);
  1070.    case BM_SETCHECK:
  1071.       pidData->bChecked=SHORT1FROMMP(mpParm1);
  1072.       vwSendMsg(hwndWnd,WM_PAINT,0,0);
  1073.       break;
  1074.    case BM_SETDEFAULT:
  1075.       break;
  1076.    default:
  1077.       return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1078.    } /* endswitch */
  1079.  
  1080.    return MRFROMLONG(FALSE);
  1081. }
  1082.  
  1083. The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3, 
  1084. Issue 5 
  1085.  
  1086.  
  1087. ΓòÉΓòÉΓòÉ 5.6. The radioButtonProc() Function ΓòÉΓòÉΓòÉ
  1088.  
  1089. The radioButtonProc() Function 
  1090.  
  1091. This one was the most tricky to handle because of the processing of the arrow 
  1092. keys.  In PM, pressing the up or left arrow moves the focus to the previous 
  1093. button in the group and the down and right arrow moves the focus to the next 
  1094. button in the group.  After spending a couple of days on this and still not 
  1095. successfully accomplishing the desired behavior, I removed the code to the 
  1096. findGroupButton() function which greatly simplified this window procedure. 
  1097.  
  1098. MRESULT EXPENTRY radioButtonProc(HVWWND hwndWnd,
  1099.                                  ULONG ulMsg,
  1100.                                  MPARAM mpParm1,
  1101.                                  MPARAM mpParm2)
  1102. //-------------------------------------------------------------------------
  1103. // This "sub-window procedure" handles the radio button-specific messages
  1104. //-------------------------------------------------------------------------
  1105. {
  1106.    PINSTDATA pidData;
  1107.  
  1108.    pidData=vwQueryWindowPtr(hwndWnd,1);
  1109.  
  1110.    switch (ulMsg) {
  1111.    case WM_PAINT:
  1112.       {
  1113.          CHAR achFmt[256];
  1114.          CHAR chCheck;
  1115.          CHAR achText[256];
  1116.          ULONG ulFore;
  1117.          ULONG ulBack;
  1118.  
  1119.          vwQueryWindowText(hwndWnd,sizeof(achFmt),achFmt);
  1120.  
  1121.          //----------------------------------------------------------------
  1122.          // See if we're checked and, if so, display the appropriate
  1123.          // character in the brackets.
  1124.          //----------------------------------------------------------------
  1125.          chCheck=pidData->bChecked?RB_SELECTED:' ';
  1126.  
  1127.          sprintf(achText,"(%c) %s",chCheck,achFmt);
  1128.  
  1129.          ulFore=vwQueryForeColor(hwndWnd);
  1130.          ulBack=vwQueryBackColor(hwndWnd);
  1131.  
  1132.          //----------------------------------------------------------------
  1133.          // If we have the focus, invert the colors to indicate this
  1134.          //----------------------------------------------------------------
  1135.          if (vwQueryFocus()==hwndWnd) {
  1136.             ulFore^=0x000000FF;
  1137.             ulBack^=0x000000FF;
  1138.          } /* endif */
  1139.  
  1140.          //----------------------------------------------------------------
  1141.          // Draw the button text as we have built it above
  1142.          //----------------------------------------------------------------
  1143.          vwDrawText(hwndWnd,
  1144.                     -1,
  1145.                     achText,
  1146.                     NULL,
  1147.                     ulFore,
  1148.                     ulBack,
  1149.                     DT_LEFT|DT_VCENTER|DT_ERASERECT);
  1150.       }
  1151.       break;
  1152.    case WM_CHAR:
  1153.       {
  1154.          USHORT usFlags;
  1155.          USHORT usMods;
  1156.  
  1157.          usFlags=KC_VIRTUALKEY | KC_KEYUP;
  1158.          usMods=KC_ALT | KC_CTRL | KC_SHIFT;
  1159.  
  1160.          if ((CHARMSG(&ulMsg)->fs & usFlags)!=usFlags) {
  1161.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1162.          } /* endif */
  1163.  
  1164.          if ((CHARMSG(&ulMsg)->fs & usMods)!=0) {
  1165.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1166.          } /* endif */
  1167.  
  1168.          //----------------------------------------------------------------
  1169.          // If the user pressed <SPACE> or either <ENTER> key, select
  1170.          // ourselves.  If they pressed the <UP> or <LEFT> keys, click the
  1171.          // previous button in the group.  If they pressed the <DOWN> or
  1172.          // <RIGHT> keys, click the next button in the group.
  1173.          //----------------------------------------------------------------
  1174.          switch (CHARMSG(&ulMsg)->vkey) {
  1175.          case VK_SPACE:
  1176.          case VK_ENTER:
  1177.          case VK_NEWLINE:
  1178.             vwPostMsg(hwndWnd,BM_CLICK,0,0);
  1179.             break;
  1180.          case VK_UP:
  1181.          case VK_LEFT:
  1182.             {
  1183.                HVWWND hwndPrev;
  1184.  
  1185.                hwndPrev=findGroupButton(hwndWnd,QW_PREV);
  1186.                if (hwndPrev==NULLHANDLE) {
  1187.                   hwndPrev=findGroupButton(hwndWnd,QW_BOTTOM);
  1188.                } /* endif */
  1189.  
  1190.                vwSendMsg(hwndPrev,BM_CLICK,MPFROMSHORT(TRUE),0);
  1191.             }
  1192.             break;
  1193.          case VK_DOWN:
  1194.          case VK_RIGHT:
  1195.             {
  1196.                HVWWND hwndNext;
  1197.  
  1198.                hwndNext=findGroupButton(hwndWnd,QW_NEXT);
  1199.                if (hwndNext==NULLHANDLE) {
  1200.                   hwndNext=findGroupButton(hwndWnd,QW_TOP);
  1201.                } /* endif */
  1202.  
  1203.                vwSendMsg(hwndNext,BM_CLICK,MPFROMSHORT(TRUE),0);
  1204.             }
  1205.             break;
  1206.          default:
  1207.             return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1208.          } /* endswitch */
  1209.       }
  1210.       break;
  1211.    case WM_QUERYDLGCODE:
  1212.       return MRFROMLONG(DLGC_BUTTON);
  1213.    case BM_CLICK:
  1214.       {
  1215.          SHORT sIndex;
  1216.          HVWWND hwndCheck;
  1217.  
  1218.          //----------------------------------------------------------------
  1219.          // If we've been clicked, we need to find the button _within our
  1220.          // group_ that is currently selected, unselect it, and then
  1221.          // select ourselves.  This is not as trivial as it sounds, but
  1222.          // the code below doesn't indicate this.  See findGroupButton().
  1223.          // - - - - - - - - - - - - - -
  1224.          // Send ourselves a BM_QUERYCHECKINDEX to see who currently is
  1225.          // selected in the group.
  1226.          //----------------------------------------------------------------
  1227.          sIndex=SHORT1FROMMR(vwSendMsg(hwndWnd,BM_QUERYCHECKINDEX,0,0));
  1228.  
  1229.          //----------------------------------------------------------------
  1230.          // If sIndex is not -1, find the button and uncheck it.
  1231.          //----------------------------------------------------------------
  1232.          if (sIndex!=-1) {
  1233.             hwndCheck=findGroupButton(hwndWnd,QW_TOP);
  1234.             while (sIndex>0) {
  1235.                hwndCheck=findGroupButton(hwndCheck,QW_NEXT);
  1236.                sIndex--;
  1237.             } /* endwhile */
  1238.          } else {
  1239.             hwndCheck=NULLHANDLE;
  1240.          } /* endif */
  1241.  
  1242.          if (hwndCheck!=NULLHANDLE) {
  1243.             vwSendMsg(hwndCheck,BM_SETCHECK,MPFROMSHORT(FALSE),0);
  1244.          } /* endif */
  1245.  
  1246.          //----------------------------------------------------------------
  1247.          // Check ourselves, set the focus to us, and send the notification
  1248.          // to our owner (the desktop).
  1249.          //----------------------------------------------------------------
  1250.          vwSendMsg(hwndWnd,BM_SETCHECK,MPFROMSHORT(TRUE),0);
  1251.          vwSetFocus(hwndWnd);
  1252.  
  1253.          vwSendMsg(VWHWND_DESKTOP,
  1254.                    WM_CONTROL,
  1255.                    MPFROM2SHORT(vwQueryWindowUShort(hwndWnd,QWS_ID),
  1256.                                 BN_CLICKED),
  1257.                    MPFROMHWND(hwndWnd));
  1258.       }
  1259.       break;
  1260.    case BM_QUERYCHECKINDEX:
  1261.       {
  1262.          HWND hwndGroup;
  1263.          SHORT sIndex;
  1264.  
  1265.          //----------------------------------------------------------------
  1266.          // Moving the findGroupButton() code to a separate function
  1267.          // made this a lot easier.  Amen to code-readability!
  1268.          // - - - - - - - - - - - - - -
  1269.          // Start from the top and enumerate all of the buttons in the
  1270.          // group until we find one that is checked.
  1271.          //----------------------------------------------------------------
  1272.          hwndGroup=findGroupButton(hwndWnd,QW_TOP);
  1273.          if (hwndGroup==NULLHANDLE) {
  1274.             return MRFROMSHORT(-1);
  1275.          } /* endif */
  1276.  
  1277.          sIndex=0;
  1278.  
  1279.          if (SHORT1FROMMR(vwSendMsg(hwndGroup,BM_QUERYCHECK,0,0))==TRUE) {
  1280.             return MRFROMSHORT(sIndex);
  1281.          } /* endif */
  1282.  
  1283.          hwndGroup=findGroupButton(hwndGroup,QW_NEXT);
  1284.  
  1285.          while (hwndGroup!=NULLHANDLE) {
  1286.             sIndex++;
  1287.  
  1288.             if (SHORT1FROMMR(vwSendMsg(hwndGroup,BM_QUERYCHECK,0,0))==TRUE) {
  1289.                return MRFROMSHORT(sIndex);
  1290.             } /* endif */
  1291.  
  1292.             hwndGroup=findGroupButton(hwndGroup,QW_NEXT);
  1293.          } /* endwhile */
  1294.  
  1295.          return MRFROMSHORT(-1);
  1296.       }
  1297.    case BM_QUERYHILITE:
  1298.       break;
  1299.    case BM_SETHILITE:
  1300.       break;
  1301.    case BM_QUERYCHECK:
  1302.       return MRFROMSHORT(pidData->bChecked);
  1303.    case BM_SETCHECK:
  1304.       pidData->bChecked=SHORT1FROMMP(mpParm1);
  1305.       vwSendMsg(hwndWnd,WM_PAINT,0,0);
  1306.       break;
  1307.    case BM_SETDEFAULT:
  1308.       break;
  1309.    default:
  1310.       return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1311.    } /* endswitch */
  1312.  
  1313.    return MRFROMLONG(FALSE);
  1314. }
  1315.  
  1316. The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3, 
  1317. Issue 5 
  1318.  
  1319.  
  1320. ΓòÉΓòÉΓòÉ 5.7. The findGroupButton() Function ΓòÉΓòÉΓòÉ
  1321.  
  1322. The findGroupButton() Function 
  1323.  
  1324. This does the hard work for the radio buttons.  Note the following behavioral 
  1325. characteristics: 
  1326.  
  1327.      The previous button of the top button in the group does not exist. 
  1328.      The next button of the bottom button in the group does not exist. 
  1329.      The previous or next button in the group must be a radio button, but 
  1330.       having a checkbox in the middle of the group does not delineate the 
  1331.       group. 
  1332.  
  1333.   HVWWND findGroupButton(HVWWND hwndWnd,LONG lCmd)
  1334.   //-------------------------------------------------------------------------
  1335.   // This function finds the group button in the appropriate position given
  1336.   // a button handle in the same group.
  1337.   //
  1338.   // Input:  hwndWnd - button handle in the group to check
  1339.   //         lCmd - a QW_ constant (from the vwQueryWindow() function)
  1340.   // Returns:  specified button handle if successful, NULLHANDLE otherwise
  1341.   //-------------------------------------------------------------------------
  1342.   {
  1343.      HVWWND hwndTop;
  1344.      HVWWND hwndBottom;
  1345.      HVWWND hwndReturn;
  1346.      ULONG ulStyle;
  1347.      CHAR achClass[256];
  1348.      BOOL bIsRadioButton;
  1349.      HVWWND hwndLast;
  1350.  
  1351.      //----------------------------------------------------------------------
  1352.      // Of the four QW_ constants, QW_PREV and QW_NEXT make recursive calls
  1353.      // specifying QW_TOP and QW_BOTTOM respectively.  Thus, the latter two
  1354.      // must be entirely self-contained in order to avoid an endless
  1355.      // recursive loop.  Additionally, QW_PREV cannot call QW_NEXT, nor can
  1356.      // QW_NEXT call QW_PREV.
  1357.      //----------------------------------------------------------------------
  1358.  
  1359.      switch (lCmd) {
  1360.      case QW_PREV:
  1361.         //-------------------------------------------------------------------
  1362.         // Query the top of the group and check for equality with the
  1363.         // specified window.  If they match, return NULLHANDLE.
  1364.         //-------------------------------------------------------------------
  1365.         hwndTop=findGroupButton(hwndWnd,QW_TOP);
  1366.  
  1367.         if (hwndWnd==hwndTop) {
  1368.            return NULLHANDLE;
  1369.         } /* endif */
  1370.  
  1371.         hwndReturn=hwndWnd;
  1372.  
  1373.         //-------------------------------------------------------------------
  1374.         // Work our way backwards in the window chain until we find the
  1375.         // first radio button.
  1376.         //-------------------------------------------------------------------
  1377.         do {
  1378.            hwndReturn=vwQueryWindow(hwndReturn,QW_PREV);
  1379.            if (hwndReturn==NULLHANDLE) {
  1380.               return NULLHANDLE;
  1381.            } /* endif */
  1382.  
  1383.            ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
  1384.            vwQueryClassName(hwndReturn,sizeof(achClass),achClass);
  1385.  
  1386.            bIsRadioButton=((strcmp(achClass,VWWC_BUTTON)==0) &&
  1387.                            (((ulStyle & BS_AUTORADIOBUTTON)!=0) ||
  1388.                             ((ulStyle & BS_RADIOBUTTON)!=0)));
  1389.         } while (!bIsRadioButton); /* enddo */
  1390.  
  1391.         return hwndReturn;
  1392.      case QW_NEXT:
  1393.         //-------------------------------------------------------------------
  1394.         // Query the bottom of the group and check for equality with the
  1395.         // specified window.  If they match, return NULLHANDLE.
  1396.         //-------------------------------------------------------------------
  1397.         hwndBottom=findGroupButton(hwndWnd,QW_BOTTOM);
  1398.  
  1399.         if (hwndWnd==hwndBottom) {
  1400.            return NULLHANDLE;
  1401.         } /* endif */
  1402.  
  1403.         hwndReturn=hwndWnd;
  1404.  
  1405.         //-------------------------------------------------------------------
  1406.         // Work our way forewards in the window chain until we find the
  1407.         // first radio button.
  1408.         //-------------------------------------------------------------------
  1409.         do {
  1410.            hwndReturn=vwQueryWindow(hwndReturn,QW_NEXT);
  1411.            if (hwndReturn==NULLHANDLE) {
  1412.               return NULLHANDLE;
  1413.            } /* endif */
  1414.  
  1415.            ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
  1416.            vwQueryClassName(hwndReturn,sizeof(achClass),achClass);
  1417.  
  1418.            bIsRadioButton=((strcmp(achClass,VWWC_BUTTON)==0) &&
  1419.                            (((ulStyle & BS_AUTORADIOBUTTON)!=0) ||
  1420.                             ((ulStyle & BS_RADIOBUTTON)!=0)));
  1421.         } while (!bIsRadioButton); /* enddo */
  1422.  
  1423.         return hwndReturn;
  1424.      case QW_TOP:
  1425.         //-------------------------------------------------------------------
  1426.         // Start with the window specified and work our way backwards until
  1427.         // we either reach the beginning
  1428.         //-------------------------------------------------------------------
  1429.         hwndReturn=hwndWnd;
  1430.         hwndLast=hwndReturn;
  1431.  
  1432.         ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
  1433.  
  1434.         while ((ulStyle & WS_GROUP)==0) {
  1435.            hwndReturn=vwQueryWindow(hwndReturn,QW_PREV);
  1436.  
  1437.            //----------------------------------------------------------------
  1438.            // If we've reached the beginning of the window chain return the
  1439.            // last valid one that we saw
  1440.            //----------------------------------------------------------------
  1441.            if (hwndReturn==NULLHANDLE) {
  1442.               return hwndLast;
  1443.            } /* endif */
  1444.  
  1445.            ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
  1446.            vwQueryClassName(hwndReturn,sizeof(achClass),achClass);
  1447.  
  1448.            bIsRadioButton=((strcmp(achClass,VWWC_BUTTON)==0) &&
  1449.                            (((ulStyle & BS_AUTORADIOBUTTON)!=0) ||
  1450.                             ((ulStyle & BS_RADIOBUTTON)!=0)));
  1451.  
  1452.            //----------------------------------------------------------------
  1453.            // If the current window (hwndReturn) is of the class VWWC_BUTTON
  1454.            // and the style indicates it's a radio button, remember this
  1455.            // window handle
  1456.            //----------------------------------------------------------------
  1457.            if (bIsRadioButton) {
  1458.               hwndLast=hwndReturn;
  1459.            } /* endif */
  1460.         } /* endwhile */
  1461.  
  1462.         return hwndReturn;
  1463.      case QW_BOTTOM:
  1464.         hwndReturn=hwndWnd;
  1465.         hwndLast=hwndReturn;
  1466.  
  1467.         //-------------------------------------------------------------------
  1468.         // Start here and search forward until we find either the end of
  1469.         // the window chain or the beginning of the next group.  Note that
  1470.         // we can't set ulStyle to the window style because, if this is
  1471.         // the first button in the group, we will return it instead of the
  1472.         // proper value.
  1473.         //-------------------------------------------------------------------
  1474.         ulStyle=0;
  1475.  
  1476.         while ((ulStyle & WS_GROUP)==0) {
  1477.            hwndReturn=vwQueryWindow(hwndReturn,QW_NEXT);
  1478.  
  1479.            //----------------------------------------------------------------
  1480.            // If we've reached the end of the window chain return the
  1481.            // last valid one that we saw
  1482.            //----------------------------------------------------------------
  1483.            if (hwndReturn==NULLHANDLE) {
  1484.               return hwndLast;
  1485.            } /* endif */
  1486.  
  1487.            ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
  1488.            vwQueryClassName(hwndReturn,sizeof(achClass),achClass);
  1489.  
  1490.            bIsRadioButton=((strcmp(achClass,VWWC_BUTTON)==0) &&
  1491.                            (((ulStyle & BS_AUTORADIOBUTTON)!=0) ||
  1492.                             ((ulStyle & BS_RADIOBUTTON)!=0)));
  1493.  
  1494.            //----------------------------------------------------------------
  1495.            // If the current window (hwndReturn) is of the class VWWC_BUTTON
  1496.            // and the style indicates it's a radio button, remember this
  1497.            // window handle
  1498.            //----------------------------------------------------------------
  1499.            if ((bIsRadioButton) && ((ulStyle & WS_GROUP)==0)) {
  1500.               hwndLast=hwndReturn;
  1501.            } /* endif */
  1502.         } /* endwhile */
  1503.  
  1504.         return hwndLast;
  1505.      default:
  1506.         return NULLHANDLE;
  1507.      } /* endswitch */
  1508.   }
  1509.  
  1510.  The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 
  1511.  3, Issue 5 
  1512.  
  1513.  
  1514. ΓòÉΓòÉΓòÉ 5.8. The Window Procedure ΓòÉΓòÉΓòÉ
  1515.  
  1516. The Window Procedure 
  1517.  
  1518. The actual window procedure simply handles the WM_CREATE and WM_DESTROY 
  1519. messages, to allocate and destroy the instance data. Other messages are passed 
  1520. to the appropriate "sub window procedure" based on the window style. 
  1521.  
  1522. MRESULT EXPENTRY VwButtonClassProc(HVWWND hwndWnd,
  1523.                                    ULONG ulMsg,
  1524.                                    MPARAM mpParm1,
  1525.                                    MPARAM mpParm2)
  1526. //-------------------------------------------------------------------------
  1527. // This window procedure simply processes the WM_CREATE and WM_DESTROY
  1528. // messages and otherwise calls the appropriate "sub window procedure"
  1529. // to handle the other messages.  This must be done this way since all
  1530. // button types are of the same class.
  1531. //-------------------------------------------------------------------------
  1532. {
  1533.    PINSTDATA pidData;
  1534.  
  1535.    pidData=vwQueryWindowPtr(hwndWnd,1);
  1536.  
  1537.    switch (ulMsg) {
  1538.    case WM_CREATE:
  1539.       pidData=calloc(1,sizeof(INSTDATA));
  1540.       if (pidData==NULL) {
  1541.          return MRFROMSHORT(TRUE);
  1542.       } /* endif */
  1543.  
  1544.       vwSetWindowPtr(hwndWnd,1,pidData);
  1545.  
  1546.       pidData->ulSzStruct=sizeof(INSTDATA);
  1547.       pidData->ulStyle=vwQueryWindowULong(hwndWnd,QWL_STYLE);
  1548.       pidData->bChecked=FALSE;
  1549.       return MRFROMSHORT(FALSE);
  1550.    case WM_DESTROY:
  1551.       vwSetWindowPtr(hwndWnd,1,NULL);
  1552.       free(pidData);
  1553.       return MRFROMSHORT(FALSE);
  1554.    default:
  1555.       if ((pidData->ulStyle & BS_AUTOCHECKBOX)!=0) {
  1556.          return checkBoxProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1557.       } else
  1558.       if ((pidData->ulStyle & BS_CHECKBOX)!=0) {
  1559.          return checkBoxProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1560.       } else
  1561.       if ((pidData->ulStyle & BS_AUTORADIOBUTTON)!=0) {
  1562.          return radioButtonProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1563.       } else
  1564.       if ((pidData->ulStyle & BS_RADIOBUTTON)!=0) {
  1565.          return radioButtonProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1566.       } else {
  1567.          //----------------------------------------------------------------
  1568.          // Assume it is a pushbutton.
  1569.          //----------------------------------------------------------------
  1570.          return pushButtonProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1571.       } /* endif */
  1572.    } /* endswitch */
  1573. }
  1574.  
  1575. The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3, 
  1576. Issue 5 
  1577.  
  1578.  
  1579. ΓòÉΓòÉΓòÉ 5.9. Conclusion ΓòÉΓòÉΓòÉ
  1580.  
  1581. Conclusion 
  1582.  
  1583. This concludes the VIOWIN implementation.  It has been demonstrated that a 
  1584. subset of PM can be defined for character mode applications, if the proper 
  1585. subset is defined by the designer.  By implementing a subset of PM instead of 
  1586. developing a new user interface, we allow the programmer to leverage their PM 
  1587. experience when developing character-mode interfaces.  This results in a much 
  1588. higher productivity, since they can "just do it" instead of having to concern 
  1589. themselves with learning how to program a new user interface (which includes 
  1590. the pitfalls and idiosyncrasies also). 
  1591.  
  1592. Where can we go from here?  To be honest, I have thought of reimplementing 
  1593. VIOWIN many times to include overlapping windows, a hierarchical parent-child 
  1594. and owner-ownee set of relationships, more window classes (especially listboxes 
  1595. and menus), and then more resource types (especially dialog boxes). After this 
  1596. is done, it could be investigated whether or not a subset of the ICLUI ("IBM 
  1597. Class Libraries for User Interface," I believe) could be implemented on top of 
  1598. the new VIOWIN to allow C++ programmers to also gain the advantages of a 
  1599. familiar programming paradigm. 
  1600.  
  1601. The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3, 
  1602. Issue 5 
  1603.  
  1604.  
  1605. ΓòÉΓòÉΓòÉ 6. RMX-OS2:  An In-Depth View (Part 4) ΓòÉΓòÉΓòÉ
  1606.  
  1607.  
  1608. ΓòÉΓòÉΓòÉ 6.1. Introduction ΓòÉΓòÉΓòÉ
  1609.  
  1610. RMX-OS2:  An In-Depth View (Part 4) 
  1611.  
  1612. Written by Johan Wikman 
  1613.  
  1614. Introduction 
  1615.  
  1616. This is the fourth article in a series where I am describing RMX.  RMX is a 
  1617. system that allows OS/2 PM applications to run remotely, that is, to run on one 
  1618. computer and be used on another.  Now, supposing you have an application that 
  1619. you want to run remotely, how do you start it on the remote computer?  In this 
  1620. article I will describe how that can be done. 
  1621.  
  1622. I assume you have read the previous articles, especially the one dealing with 
  1623. the mechanism RMX uses for the communication between different processes. 
  1624.  
  1625. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  1626.  
  1627.  
  1628. ΓòÉΓòÉΓòÉ 6.2. The Problem ΓòÉΓòÉΓòÉ
  1629.  
  1630. The Problem 
  1631.  
  1632. In the normal case, when applications are run locally, starting an application 
  1633. is not a problem.  If the application has an program-object it is enough to 
  1634. double-click on that, or you can simply start it from the command line. 
  1635. Starting an application from within another application is almost as trivial. 
  1636. Using one of the spawn() functions from the C-library or DosExecPgm() directly 
  1637. it is easy to start other applications. 
  1638.  
  1639. The documentation of DosExecPgm() states that it cannot be used for starting an 
  1640. application that is of different type (fullscreen, windowed, PM application) 
  1641. than the starting application, but DosStartSession()  must be used instead.  I 
  1642. don't know what the situation actually is, because I have at least not 
  1643. experienced any problems when starting PM applications (using DosExecPgm()) 
  1644. from non-PM applications. 
  1645.  
  1646. Anyway, when running remote applications the situation is quite different. 
  1647. Obviously DosExecPgm() is not capable of starting an application on another 
  1648. computer.  The conclusion is that we need some mechanism on the other computer 
  1649. that starts the application that is to appear on the local computer. So, what 
  1650. is this mechanism?  Well, the mechanism is another remote application that is 
  1651. prepared to accept commands from the local computer and start other remote 
  1652. applications. 
  1653.  
  1654. This is almost a CATCH-22 situation<grin>.  To run remote applications we need 
  1655. another remote application (actually mechanism as it need not be a single 
  1656. application) that starts them for us. 
  1657.  
  1658. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  1659.  
  1660.  
  1661. ΓòÉΓòÉΓòÉ 6.3. Standard Solutions ΓòÉΓòÉΓòÉ
  1662.  
  1663. Standard Solutions 
  1664.  
  1665. Depending on what network is being used, there are certain standard solutions 
  1666. for running applications remotely. 
  1667.  
  1668. TCP/IP 
  1669.  
  1670. Apart from being a protocol, the TCP/IP concept includes a lot of different 
  1671. applications.  Provided the right daemons are running (I won't go into that 
  1672. now) it is possible to use TELNET for logging into a computer and running 
  1673. programs remotely.  Currently I have two computers at home, the hostname of one 
  1674. of them is odin, and the hostname of the other is loke. While sitting at odin, 
  1675. I can log into loke the following way: 
  1676.  
  1677.      [C:\]telnet loke
  1678.  
  1679. After having entered my password, I get an almost ordinary command-line prompt. 
  1680.  
  1681.      [<loke>-C:\]
  1682.  
  1683. Although I sit at odin, whatever I do is executed in the context of loke. 
  1684. Typing dir shows me the context of the C-drive of loke.  If I run command-line 
  1685. programs they also run on loke, but I can interract with them on odin I am 
  1686. sitting at.  However, If I start a PM application then it will appear on loke, 
  1687. and not on odin.  That is, TELNET as such does not allow PM application to be 
  1688. used remotely.  If you remember from previous articels, all that is required in 
  1689. order to run an RMX application is that the environment variable RMXDISPLAY has 
  1690. been set.  So, if I want to run a PM application on loke, yet be able to use it 
  1691. on odin I would: 
  1692.  
  1693.      [<loke>-C:\]set RMXDISPLAY=odin[<loke>-C:\]start
  1694.      pulse.exe
  1695.  
  1696. This works, provided PULSE.EXE has been patched the way I described in a 
  1697. previous article. 
  1698.  
  1699. Named Pipes 
  1700.  
  1701. LAN Server (perhaps some other products as well) provides the possibility of 
  1702. running programs on another computer using the command NETRUN. I have never 
  1703. tried it out, but supposedly it would be possible to set the RMXDISPLAY 
  1704. variable and start an application (patched for RMX) using it. 
  1705.  
  1706. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  1707.  
  1708.  
  1709. ΓòÉΓòÉΓòÉ 6.4. Custom Solutions ΓòÉΓòÉΓòÉ
  1710.  
  1711. Custom Solutions 
  1712.  
  1713. Even if the TELNET option works and even if TELNET as such is very useful, the 
  1714. option is rather limited.  In practice it would be, I can imagine, quite 
  1715. difficult to create a program object that automatically would start a remote 
  1716. application.  Also, the TELNET option is present only on TCP/IP networks.  For 
  1717. these reasons, but also because it was a nice problem<grin>, I developed a 
  1718. custom solution that is independent from any applications provided by the 
  1719. network software.  The solution consists of three programs: RMXSTRTR.EXE, 
  1720. RMXSTART.EXE and RMXSTOP.EXE. 
  1721.  
  1722. RMXSTRTR.EXE and RMXSTART.EXE runs on different computers.  RMXSTRTR.EXE is a 
  1723. daemon application that usually is started when the computer is booted.  It 
  1724. sits there idle, waiting for start requests from RMXSTART.EXE that is run on 
  1725. some other computer.  RMXSTOP.EXE provides a graceful way of stopping a 
  1726. (possibly) detached RMXSTRTR.EXE. 
  1727.  
  1728. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  1729.  
  1730.  
  1731. ΓòÉΓòÉΓòÉ 6.5. RMXSTRTR.EXE ΓòÉΓòÉΓòÉ
  1732.  
  1733. RMXSTRTR.EXE 
  1734.  
  1735. The overall structure of RMXSTRTR.EXE is illustrated in the following figure. 
  1736.  
  1737. So, what is going on? 
  1738.  
  1739. When RMXSTRTR.EXE is started, it initializes itself, which among other things 
  1740. involves the creation of two semaphores. 
  1741.  
  1742.    1. If it succeeds in the initializing, it spawns a second thread. 
  1743.    2. The startup thread then blocks on one of the semaphores. 
  1744.    3. The started thread creates a connection, which it subsequently blocks on. 
  1745.    4. When some instance of RMXSTART.EXE somewhere on the network opens the 
  1746.       connection, the thread 
  1747.    5. immediately spawns a new thread and passes the connection handle along. 
  1748.       The current thread (thread 2) then loops back to step 4. 
  1749.    6. The new thread reads the start request from RMXSTART, 
  1750.    7. starts the requested application, and 
  1751.    8. sends a response telling whether the starting succeeded.  Finally it just 
  1752.       dies. 
  1753.  
  1754.  Having a separate thread for each client ensures that the likelihood that 
  1755.  RMXSTRTR would be busy when an instance of RMXSTART attempts to open a 
  1756.  connection is quite small.  Nevertheless, under heavy load the task of 
  1757.  spawning a new thread might take a while, so a better approach would perhaps 
  1758.  be to have a number of threads ready for immediate dispatch. 
  1759.  
  1760.  Main function of RMXSTRTR 
  1761.  
  1762.  Let's look then at the main function of RMXSTRTR in greater detail (the actual 
  1763.  code is available in a zip-file you should have got along with this issue). 
  1764.  
  1765.        set_new_handler(OutOfMem);
  1766.        ios::sync_with_stdio();
  1767.  
  1768.  The first call establishes a function that is called when the C++ operator new 
  1769.  fails to allocate memory.  It is unlikely that an out-of-memory situation ever 
  1770.  occurs, but it doesn't hurt.  The function specified simply writes a message 
  1771.  and terminates the application.  The following call synchronizes the C++ 
  1772.  output mechanism (cout) with the C output mechanism (printf).  This is 
  1773.  necessary because both are being used within RMXSTRTR. 
  1774.  
  1775.        ULONG  ulFunctionOrder = MAKEUSHORT(EXLST_ADD, 0xFF);
  1776.        DosExitList(ulFunctionOrder, CleanUp);
  1777.  
  1778.  Then we register a cleanup-function.  The function registered - CleanUp() - 
  1779.  will be called by the system regardless of how RMXSTRTR is terminated.  The 
  1780.  first argument of DosExitList() specifies what we want to do.  The high-order 
  1781.  word should be 0, and the low-order word contains the actual information as 
  1782.  two one-byte fields.  The lower of the bytes specifies the action:  EXLST_ADD 
  1783.  indicates that we are adding a function to the cleanup-functions, EXLST_REMOVE 
  1784.  indicates that we want to remove an existing function, and EXLST_EXIT 
  1785.  indicates that we have done our processing and the system should call the next 
  1786.  function.  EXLST_EXIT is used only from within the actual cleanup-function. 
  1787.  The higher of the bytes specifies where the registered function should be 
  1788.  placed in the list of cleanup- functions.  Functions with an order code of 0x0 
  1789.  are invoked first, and functions with an order code of 0xFF are invoked last. 
  1790.  
  1791.        hev = CreateEventSemaphore();
  1792.        hmtx = CreateMutexSemaphore();
  1793.  
  1794.  Two semaphores - one of them an event-semaphore and the other a 
  1795.  mutex-semaphore - are created.  The main thread blocks on the event-semaphore 
  1796.  when it has initialized everything and has started the thread that does the 
  1797.  actual job.  As I will show later, the name used for the semaphore is 
  1798.  constructed from the value of the environment variable RMXCOMMS.  Doing this 
  1799.  gives us two benefits: 
  1800.  
  1801.      It effectively means that there can only be one RMXSTRTR running using a 
  1802.       specific RMXCOMMS DLL.  This is what we want, as it does not make sense 
  1803.       to have several instances of RMXSTRTR that uses the same communications 
  1804.       DLL.  On the other hand it allows several instances of RMXSTRTR to run, 
  1805.       provided they use a different DLL. 
  1806.  
  1807.      As the name of the semaphore is constructed from the value of RMXCOMMS it 
  1808.       means that we later can open the semaphore and post it, thus causing the 
  1809.       (possibly detached) RMXSTRTR to exit. 
  1810.  
  1811.  It is here that RMXSTRTR exits after having printed an error message if the 
  1812.  creation of the event semaphore fails, as that indicates that an RMXSTRTR 
  1813.  using the same RMXCOMMS DLL already is running.  The mutex semaphore is used 
  1814.  for synchronizing the output of different threads. 
  1815.  
  1816.        PSZ  pszName = GetStarterName();
  1817.  
  1818.  The next this to do is to obtain the name RMXSTRTR should listen on. 
  1819.  GetStarterName() is implemented on top of the RMXCOMMS function 
  1820.  RmxGetServiceName().  That means that the contents of the buffer that is 
  1821.  returned varies depending on which actual communications DLL is being used. 
  1822.  That doesn't matter, however, as we do not care what it contains. 
  1823.  
  1824.        void (*firstThread)(void*) = (void (*)(void*)) StarterLoop;
  1825.        int  tid = _beginthread(firstThread, SIZE_STACK, pszName);
  1826.  
  1827.  Once the semaphores have been created and the name RMXSTRTR should be 
  1828.  listening on has been obtained, the thread that does the actual work can be 
  1829.  started.  The function _beginthread() is the C RTL function for creating 
  1830.  threads.  The first argument is a pointer to a function that takes a void* as 
  1831.  argument and returns nothing, the second argument is the size of the stack, 
  1832.  and the third argument is an argument that should be provided to the thread 
  1833.  function (the one given as first argument).  This is the Borland format, the 
  1834.  prototype is slightly different in IBM and other compilers.  The function we 
  1835.  want to use as thread function - StarterLoop() - is otherwise ok, except that 
  1836.  it takes a PSZ  as argument and not a void*.  The funny looking variable 
  1837.  declaration above the call to _beginthread() is simply there for making 
  1838.  StarterLoop() acceptable as argument.  This is perfectly safe as PSZ and void* 
  1839.  are fully compatible in this context. 
  1840.  
  1841.              DosWaitEventSem(hev, SEM_INDEFINITE_WAIT);
  1842.  
  1843.  Once the new thread has been started, the main thread simply blocks on the 
  1844.  created semaphore.  There it stays forever if need be. 
  1845.  
  1846.  Starter Loop 
  1847.  
  1848.  Essentially the starter loop - as shown in the figure earlier - is very 
  1849.  simple.  It is a tight loop where a connection is created, a connecting 
  1850.  instance of RMXSTART is waited for, and a handler thread that does the job is 
  1851.  spawned. 
  1852.  
  1853.        while (TRUE)   {
  1854.             create connection
  1855.             wait for RMXSTART
  1856.             spawn handler thread
  1857.        }
  1858.  
  1859.  The connection is created the following way. 
  1860.  
  1861.        HCONNECTION  hConn;
  1862.        ULONG  rc;
  1863.  
  1864.        rc = RmxCreate(pcszName, &hConn);
  1865.  
  1866.  The name of the connection - pcszName - was obtained as an argument to the 
  1867.  function.  It is the same name as was used in the call to _beginthread() in 
  1868.  the main thread.  If the call is successful, hConn contains the connection 
  1869.  handle. 
  1870.  
  1871.        RmxConnect(hConn);
  1872.  
  1873.  This call blocks until somebody opens the connection.  The task of actually 
  1874.  starting an application is a rather heavy operation, so a separate thread is 
  1875.  dedicated for it. 
  1876.  
  1877.        _beginthread(HandlerThread, SIZE_STACK, (VOID*) hConn);
  1878.  
  1879.  The connection handle is provided as thread argument.  Immediately when the 
  1880.  thread has been started a new connection is created and RMXSTRTR is ready for 
  1881.  another client. 
  1882.  
  1883.  Handling the Client 
  1884.  
  1885.  The client wants RMXSTRTR to start an application.  Exactly which one, the 
  1886.  client (RMXSTART) has to tell RMXSTRTR.  The first thing to do then, is to 
  1887.  read the entire request the client sent.  For that purpose a small structure 
  1888.  has been defined. 
  1889.  
  1890.        struct Request{
  1891.            PBYTE pbRequest;
  1892.            ULONG ulSize;
  1893.        };
  1894.  
  1895.  So first the entire request is read. 
  1896.  
  1897.        Request  request;
  1898.  
  1899.        ReadRequest(hConn, &request);
  1900.  
  1901.  The hConn was received by the thread when it was started. ReadRequest() (which 
  1902.  I won't look at in detail) simply reads everything the client has sent and 
  1903.  allocates a sufficiently large buffer on behalf of the caller where it stores 
  1904.  the data.  ulSize is updated to the actual size of the data sent by the 
  1905.  client.  We need to know the exact size of the request as we cannot trust the 
  1906.  client to provide us with data of proper format. 
  1907.  
  1908.  Once the request has been read, we must parse it.  A proper request is of one 
  1909.  of the following formats, 
  1910.  
  1911.        DISPLAY0APPLICATION00
  1912.        DISPLAY0APPLICATION0ATTRIBUTES00
  1913.  
  1914.  where DISPLAY, APPLICATION and ATTRIBUTES denotes strings (without ending 
  1915.  NULL).  That is, two or three catenated ASCIIZ strings followed by an 
  1916.  additional NULL. 
  1917.  
  1918.        PSZ  pszDisplay,  pszApplication,  pszArguments;
  1919.  
  1920.        ParseRequest(&request, &pszDisplay, &pszApplication,
  1921.        &pszArguments);
  1922.  
  1923.  ParseRequest() takes a request and sets the three provided PSZ pointers to 
  1924.  point at the correct place in the request buffer.  Once the request has 
  1925.  successfully been parsed, we can call the function that actually starts the 
  1926.  application. 
  1927.  
  1928.        StartApp(pszDisplay, pszApplication, pszArguments);
  1929.  
  1930.  When the application has been started a return code is sent back to the 
  1931.  client.  What the return code - rc - actually is depends on whether everything 
  1932.  done so far has succeeded. 
  1933.  
  1934.        SendResponse(hConn, rc);
  1935.  
  1936.  Finally when everything is ready, the connection can be disconnected and 
  1937.  closed. 
  1938.  
  1939.        RmxDisConnect(hConn);RmxClose(hConn);
  1940.  
  1941.  Starting the Application 
  1942.  
  1943.  Ok, now we have got so far that the request sent by the client (RMXSTART.EXE) 
  1944.  has been read and parsed.  Now it's time to start the application.  But, we 
  1945.  don't yet know for sure that the application the client specified actually 
  1946.  exists.  The first this to do is to find out if the application path specified 
  1947.  by the client can be used directly. 
  1948.  
  1949.        ULONG  rc = NO_ERROR;CHAR  achPath[CCHMAXPATH];if
  1950.        (access(pcszApplication, 0)){
  1951.  
  1952.  Access() returns zero if the string provided as first argument denotes an 
  1953.  application.  That is, we end up in the if-branch if the application is not 
  1954.  found.  The next thing is to look for the application on the path. 
  1955.  
  1956.            rc = DosSearchPath(SEARCH_IGNORENETERRS |
  1957.                               SEARCH_ENVIRONMENT   |
  1958.                               SEARCH_CUR_DIRECTORY,
  1959.                               "PATH",
  1960.                               pcszApplication,
  1961.                               achPath,
  1962.                               CCHMAXPATH);
  1963.            if (rc == NO_ERROR)
  1964.              pcszApplication = achPath;
  1965.  
  1966.  If DosSearchPath() returns NO_ERROR then the application was found.  In that 
  1967.  case the fully qualified name of the application is copied to achPath.  Also 
  1968.  if the function succeeds we set pcszApplication to point to achPath.  That 
  1969.  way, in the code to follow, we need not worry where the final application name 
  1970.  is to be found, but can simply use pcszApplication.  Now that we know the 
  1971.  applications exists, we can finally launch it. 
  1972.  
  1973.        if (rc == NO_ERROR)
  1974.            LaunchApp(pcszDisplay, pcszApplication,
  1975.        pcszArguments);
  1976.  
  1977.  If you look at the code I've provided, you'll see that I've commented out some 
  1978.  code that would be executed before LaunchApp().  As I wrote RMXSTRTR to be 
  1979.  used for starting remote application it must first be verified that the 
  1980.  application to be started can be run remotely.  After all, the application to 
  1981.  be started is supposed to turn up on another computer somewhere and if that 
  1982.  simply is not possible it doesn't make much sense starting it in the first 
  1983.  place. 
  1984.  
  1985.  Launching the Application 
  1986.  
  1987.  The first thing that is done when the application is to be launched is that 
  1988.  the environment is cloned. 
  1989.  
  1990.        PSZ  pszEnv = CloneEnvironment(pcszDisplay),  pszArg = 0;
  1991.  
  1992.  Why is that done?  Well, if you have read the previous articles about RMX you 
  1993.  know that the value of the environment variable RMXDISPLAY specifies the 
  1994.  computer where the remote application will turn up.  So, the value of that 
  1995.  variable must be set to the value given by the client.  Why not simply set 
  1996.  RMXDISPLAY to the value desired and then start the application as it is easy 
  1997.  to start a child process so that it inherits the environment.  That could be 
  1998.  done, provided RMXSTRTR would be single-threaded.  Now that RMXSTRTR is 
  1999.  multi-threaded that cannot be done, as several threads could simultaneously 
  2000.  modify the variable.  Synchronizing the launching of applications using 
  2001.  semaphores would be a viable alternative, but launching the application is the 
  2002.  most heavily-used operation in RMXSTRTR and it would be a pity not to use 
  2003.  threads there.  So, CloneEnvironment() clones the current environment and 
  2004.  sets/replaces the value of RMXDISPLAY with the value specified by the client. 
  2005.  Finally it returns the copy. 
  2006.  
  2007.  If the application has arguments we must build a proper argument string. 
  2008.  
  2009.        if (pcszArguments){
  2010.          ULONG    ulApplication = strlen(pcszApplication) + 1,
  2011.                   ulArguments   = strlen(pcszArguments) + 1,
  2012.                   ulSize        = ulApplication + ulArguments + 1;
  2013.  
  2014.          pszArg = new CHAR [ulSize];
  2015.          strcpy(pszArg, pcszApplication);
  2016.          strcpy(&pszArg[ulApplication], pcszArguments);
  2017.          pszArg[ulSize - 1] = 0;
  2018.        }
  2019.  
  2020.  According to the documentation of DosExecPgm(), the argument string should 
  2021.  consist of the application name and a NULL, followed by all arguments and a 
  2022.  double NULL. 
  2023.  
  2024.        RESULTCODES  resultCodes;
  2025.        ULONG  rc = DosExecPgm(0, 0, EXEC_BACKGROUND,
  2026.                               pszArg, pszEnv, &resultCodes,
  2027.                               pcszApplication);
  2028.  
  2029.  Then finally the application is started. 
  2030.  
  2031.  Logging 
  2032.  
  2033.  Throughout RMXSTRTR a function named Print() is used for printing information. 
  2034.  It is essentially a thread-safe version of printf().  RMXSTRTR is linked using 
  2035.  the MT RTL, but even so I noticed that the printout of different threads 
  2036.  occasionally got interleaved. 
  2037.  
  2038.        static VOID Print(PCSZ pszFormat, ...)
  2039.        {
  2040.          if (DosRequestMutexSem(hmtx, SEM_INDEFINITE_WAIT))
  2041.            return;
  2042.          printf("[%d, %d]: ", pid, CurrentTid());
  2043.  
  2044.          va_list         arguments;
  2045.  
  2046.          va_start(arguments, pszFormat);
  2047.          vprintf(pszFormat, arguments);
  2048.          va_end(arguments);
  2049.          DosReleaseMutexSem(hmtx);
  2050.        }
  2051.  
  2052.  The mutex semaphore that was created in main() is used for synchronizing 
  2053.  different threads.  First the current pid and tid is printed out.  Then using 
  2054.  the va_start, va_list and va_end macros the string with possible additional 
  2055.  arguments is printed. 
  2056.  
  2057.  Creating the Event Semaphore 
  2058.  
  2059.  The event semaphore name is created from the name of the used communications 
  2060.  DLL.  The name of the DLL has to specified in the variable RMXCOMMS.  So, 
  2061.  first we obtain that name. 
  2062.  
  2063.        PCSZ  pcszRmxComms = getenv("RMXCOMMS");
  2064.  
  2065.  Then the name is catenated to a common prefix. 
  2066.  
  2067.        CHAR      achSemName[CCHMAXPATH];
  2068.        strcpy(achSemName, "\\SEM32\\RMX\\STARTER\\");
  2069.        strcat(achSemName, pcszRmxComms);
  2070.  
  2071.  And then the semaphore is created. 
  2072.  
  2073.        HEV      hev = 0;
  2074.  
  2075.        if (DosCreateEventSem(achSemName,
  2076.                              &hev,
  2077.                              DC_SEM_SHARED,
  2078.                              FALSE) != NO_ERROR)  hev = 0;
  2079.  
  2080.        return hev;
  2081.  
  2082.  If this functions fails it is an indication that another instance of RMXSTRTR 
  2083.  that uses the same communications DLL is running. 
  2084.  
  2085.  RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  2086.  
  2087.  
  2088. ΓòÉΓòÉΓòÉ 6.6. RMXSTART.EXE ΓòÉΓòÉΓòÉ
  2089.  
  2090. RMXSTART.EXE 
  2091.  
  2092. RMXSTART is a great deal simpler than RMXSTRTR.  It basically makes a request 
  2093. out of the arguments, opens a connection to RMXSTRTR, sends the request, waits 
  2094. for a reply and finally closes the connection.  If RMXSTART is started without 
  2095. arguments it prints out: 
  2096.  
  2097.      usage: rmxstart display cpu application [arguments]
  2098.  
  2099. DISPLAY refers to the local computer, that is, the one where the application 
  2100. will appear.  CPU refers to the computer where the application will run, that 
  2101. is, in practice a computer where RMXSTRTR is running.  Nothing prevents the 
  2102. DISPLAY and CPU from being the same.  APPLICATION is, of course, the 
  2103. application to be started, and ARGUMENTS is the arguments that should be 
  2104. provided to the application.  If more than one argument is to be provided to 
  2105. the application then they must all be enclosed in quotes. 
  2106.  
  2107. The main function 
  2108.  
  2109. When RMXSTART is started we set the arguments to a few variables for easier 
  2110. access. 
  2111.  
  2112.      int main(int argc, char* argv[])
  2113.      {
  2114.        PCSZ        pcszDisplay     = argv[1],
  2115.                    pcszHost        = argv[2],
  2116.                    pcszApplication = argv[3],
  2117.                    pcszArguments   = 0;
  2118.  
  2119.        if (argc == 5)
  2120.          pcszArguments = argv[4];
  2121.  
  2122. The name of the starter is, the same way as in RMXSTRTR, obtained from: 
  2123.  
  2124.      PSZ  pszName = GetStarterName();
  2125.  
  2126. Now that we know the host (the computer where the application is to be run) and 
  2127. the name of the starter we open a connection to the starter. 
  2128.  
  2129.      HCONNECTION  hConn = OpenConnection(pcszHost, pszName);
  2130.  
  2131. Once the connection has been opened, the request can be sent.  If it is 
  2132. successfully sent we wait for the reply. 
  2133.  
  2134.      if (SendRequest(hConn, pcszDisplay, pcszApplication, pcszArguments))
  2135.         ReadReply(hConn);
  2136.  
  2137. Finally the connection is closed. 
  2138.  
  2139.      RmxClose(hConn);
  2140.  
  2141. Opening the Connection 
  2142.  
  2143. When the connection is opened we must take precautions for the event that 
  2144. RMXSTRTR is busy. 
  2145.  
  2146.      HCONNECTION  hConn = 0;
  2147.      ULONG        ulAttempts = 1,  rc;
  2148.  
  2149.      do{
  2150.          rc = RmxOpen(pcszHost, pcszPort, &hConn);
  2151.          if (rc == ERROR_PIPE_BUSY)
  2152.            DosSleep(ulAttempts * 200);
  2153.      } while ((rc == ERROR_PIPE_BUSY) &&
  2154.               (ulAttempts++ < MAX_ATTEMPTS));
  2155.  
  2156. Using RmxOpen() we attempt to open the connection.  If it fails because 
  2157. RMXSTRTR is busy, then we sleep for a while and try again.  Each time the 
  2158. function fails, we sleep a little longer.  But not forever; after a specified 
  2159. number of max attempts we just give up. 
  2160.  
  2161. Sending the Request 
  2162.  
  2163. In order to start a remote application we must send the name of our local 
  2164. computer, the name of the application and possible arguments.  It is simply a 
  2165. question of concatenating the two (possibly three) strings and adding an extra 
  2166. NULL.  First we must find out how much memory the entire request needs. 
  2167.  
  2168.      ULONG lenDisplay     = strlen(pcszDisplay) + 1,
  2169.            lenApplication = strlen(pcszApplication) + 1,
  2170.            lenArguments   = pcszArguments ? strlen(pcszArguments) + 1 : 0,
  2171.            lenRequest     = lenDisplay + lenApplication +
  2172.            lenArguments + 1;
  2173.  
  2174. One is added to each sublength as otherwise we wouldn't reserve enough memory 
  2175. for each NULL.  Finally an additional byte is added to the length of the entire 
  2176. request.  When the length is known, the memory can be allocated. 
  2177.  
  2178.      PSZ  pszRequest = new CHAR[lenRequest],
  2179.           p          = pszRequest;
  2180.  
  2181. Then each string is copied to the request buffer. 
  2182.  
  2183.      strcpy(p, pcszDisplay);
  2184.      p += lenDisplay;
  2185.      strcpy(p, pcszApplication);
  2186.      p += lenApplication;
  2187.      if (pcszArguments){
  2188.         strcpy(p, pcszArguments);
  2189.         p += lenArguments;
  2190.      }
  2191.  
  2192. Finally the double NULL is added. 
  2193.  
  2194.      *p = 0;
  2195.  
  2196. Now the request can be sent to RMXSTRTR. 
  2197.  
  2198.      ULONG  rc = RmxWrite(hConn, pszRequest, lenRequest);
  2199.  
  2200. Reading the Reply 
  2201.  
  2202. Even if it is unlikely that RMXSTRTR would ever return anything but a status 
  2203. code, it is better to make sure that any kind of reply can be handled. We need 
  2204. a few variables for that. 
  2205.  
  2206.      ULONG      ulBytesRead,  ulSize = SIZE_BUFFER;
  2207.      BYTE      *pbReply = 0;
  2208.      ULONG      rc;
  2209.  
  2210. Then we can enter the loop for reading the reply. 
  2211.  
  2212.      do{
  2213.          pbReply = new BYTE [ulSize];
  2214.          rc = RmxRead(hConn, pbReply, ulSize, &ulBytesRead);
  2215.          if (rc == RMXERR_ENLARGE_BUFFER)
  2216.          {
  2217.              delete [] pbReply;
  2218.             ulSize = ulBytesRead;
  2219.          }
  2220.      }  while (rc == RMXERR_ENLARGE_BUFFER);
  2221.  
  2222. We spin in the loop until we have a buffer sufficiently large (shouldn't ever 
  2223. need more than two attempts).  The loop is safe as, even if I didn't mention 
  2224. it, a handler for the out-of-memory situation has been set in main(). 
  2225.  
  2226.      if (rc || (ulBytesRead != sizeof(ULONG)))
  2227.      {
  2228.          delete [] pbReply;
  2229.          cerr << "rmxstart: Failed to read reply from starter." << endl;
  2230.          return;
  2231.      }
  2232.  
  2233. If RmxRead() returns an error, or if the size of the returned reply is 
  2234. something other than 4 bytes, we give up.  The rest of the function is simply a 
  2235. switch on the returned status code along with appropriate messages to the user. 
  2236.  
  2237. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  2238.  
  2239.  
  2240. ΓòÉΓòÉΓòÉ 6.7. RMXSTOP.EXE ΓòÉΓòÉΓòÉ
  2241.  
  2242. RMXSTOP.EXE 
  2243.  
  2244. RMXSTOP is the simplest of the three applications.  Its task is to gracefully 
  2245. stop a running RMXSTRTR.  The RMXSTRTR to stop is either specified by 
  2246. explicitly giving the name of the communications DLL the RMXSTRTR is using, or 
  2247. by allowing RMXSTOP to use the current value of RMXCOMMS.  If no arguments has 
  2248. been given RMXSTOP uses the value of RMXCOMMS. 
  2249.  
  2250.      PCSZ  pcszRmxComms = 0;
  2251.  
  2252.      if (argc == 1)
  2253.      {
  2254.          pcszRmxComms = getenv(RMXCOMMS);
  2255.          if (pcszRmxComms == 0)
  2256.                 return EXIT_INIT;
  2257.      }
  2258.  
  2259. If no arguments have been given and the environment variable RMXCOMMS has not 
  2260. been specified, there is nothing we can do.  If arguments have been given we 
  2261. verify that they are of proper format. 
  2262.  
  2263.      else
  2264.      {
  2265.          if (strcmp(argv[1], "-c"))
  2266.            return EXIT_INIT;
  2267.          pcszRmxComms = argv[2];
  2268.      }
  2269.  
  2270. If the flag is "-c" we use argument following it as the DLL name.  From the DLL 
  2271. name we build the semaphore name. 
  2272.  
  2273.      CHAR   achSemName[CCHMAXPATH];
  2274.  
  2275.      strcpy(achSemName, RMXSEMPREFIX);
  2276.      strcat(achSemName, pcszRmxComms);
  2277.  
  2278. RMXSEMPREFIX is a common prefix (actually "\\SEM32\\RMX\\STARTER\\") that is 
  2279. also used by RMXSTRTR when it creates the event semaphore.  Once the complete 
  2280. name is available we can open the semaphore. 
  2281.  
  2282.      HEV      hev = 0;
  2283.  
  2284.      if (DosOpenEventSem(achSemName, &hev) == NO_ERROR)
  2285.      {
  2286.          DosPostEventSem(hev);
  2287.          DosCloseEventSem(hev);
  2288.      }
  2289.  
  2290. If it succeeds we know that the main thread of some RMXSTRTR is blocked on that 
  2291. semaphore.  Hence, if we post the semaphore the RMXSTRTR process will 
  2292. terminate.  If the opening fails, we know no RMXSTRTR is running using the 
  2293. specified communications DLL. 
  2294.  
  2295.      else
  2296.      {
  2297.          cerr << "rmxstop: No rmxstrtr using " << pcszRmxComms
  2298.               << " seems to be running." << endl;
  2299.      }
  2300.  
  2301. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  2302.  
  2303.  
  2304. ΓòÉΓòÉΓòÉ 6.8. Building the Applications ΓòÉΓòÉΓòÉ
  2305.  
  2306. Building the Applications 
  2307.  
  2308. Along with the article you should get a zip-file, RMXSTART.ZIP, that contains 
  2309. all source and ready-made applications and DLLs.  The makefiles are made for 
  2310. NMAKE.EXE (the make provided with IBM's compiler) and the Borland compiler. 
  2311. Pretty heavy editing is probably needed if you use something else.  Before 
  2312. starting the build, you have to set the environment variable RMXROOT to point 
  2313. to the directory where you unzipped the zip-file. E.g. 
  2314.  
  2315.      [C:\]set RMXROOT=C:\RMX
  2316.  
  2317. Then you simply: 
  2318.  
  2319.      [C:\]cd RMX
  2320.      [C:\RMX]nmake
  2321.  
  2322. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  2323.  
  2324.  
  2325. ΓòÉΓòÉΓòÉ 6.9. Running the Applications ΓòÉΓòÉΓòÉ
  2326.  
  2327. Running the Applications 
  2328.  
  2329. The first thing you should do is to either include the directory RMX\DLL in 
  2330. your LIBPATH, or move the DLLs to some directory already in your LIBPATH. 
  2331. Remember that RMXPIPE.DLL requires the file RMXPIPE.DAT to be in the same 
  2332. directory where it is and that RMXTCPIP.DLL requires that the file 
  2333. RMX\RMXCOMMS\RMXTCPIP\services is appended to your TCPIP\ETC\services file. To 
  2334. start RMXSTRTR, e.g.: 
  2335.  
  2336.      [C:\RMX\BIN]set RMXCOMMS=RMXTCPIP
  2337.      [C:\RMX\BIN]rmxstrtr
  2338.  
  2339. Supposing the name of your computer is odin and the name of the computer where 
  2340. RMXSTRTR is running is loke, you could start pulse.exe on that computer with 
  2341. the following commands. 
  2342.  
  2343.      [C:\RMX\BIN]set RMXCOMMS=RMXTCPIP
  2344.      [C:\RMX\BIN]rmxstart odin loke c:\os2\apps\pulse.exe
  2345.  
  2346. If you are using named pipes, the commands would be something like: 
  2347.  
  2348.      [C:\RMX\BIN]set RMXCOMMS=RMXPIPE
  2349.      [C:\RMX\BIN]rmxstart \\odin \\loke c:\os2\apps\pulse.exe
  2350.  
  2351. Remember, these programs only provide a means for starting an application on 
  2352. another computer.  They do not, in themselves, redirect any output anywhere. 
  2353.  
  2354. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  2355.  
  2356.  
  2357. ΓòÉΓòÉΓòÉ 6.10. Conclusion ΓòÉΓòÉΓòÉ
  2358.  
  2359. Conclusion 
  2360.  
  2361. In this article I described the programs that can be used for starting 
  2362. applications on other computers.  The programs are slightly modified, compared 
  2363. with the "official" RMX versions, in that they also start applications that 
  2364. have not been patched for RMX.  That is, it is possible to start remote 
  2365. applications that you subsequently cannot interact with. 
  2366.  
  2367. I have uploaded a complete version of RMX to hobbes and the zip resides in the 
  2368. directory network\other.  If you install that package, then you actually could 
  2369. start a PM application on a remote computer and use it on your local. But 
  2370. please, keep in mind that the version is early beta.  Don't try it out if you 
  2371. expect a finished product<grin>. 
  2372.  
  2373. If you have any problems with RMX, feel free to send me mail. 
  2374.  
  2375. RMX-OS2:  An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5 
  2376.  
  2377.  
  2378. ΓòÉΓòÉΓòÉ 7. /dev/EDM/BookReview ΓòÉΓòÉΓòÉ
  2379.  
  2380.  
  2381. ΓòÉΓòÉΓòÉ 7.1. Introduction ΓòÉΓòÉΓòÉ
  2382.  
  2383. /dev/EDM2/BookReview 
  2384.  
  2385. Written by Carsten Whimster 
  2386.  
  2387. Introduction 
  2388.  
  2389. In /dev/EDM2/BookReview, I focus on development books and materials.  The 
  2390. column is written from the point of view of an intermediate PM C programmer and 
  2391. intermediate REXX programmer.  Pick up whichever book strikes your fancy, and 
  2392. join the growing group of people following our PM programming columns.  I have 
  2393. already reviewed a number of beginner's books, and will try to concentrate a 
  2394. bit more on intermediate techniques and special topics from now on. 
  2395.  
  2396. Please send me your comments and thoughts so that I can make this column as 
  2397. good as possible.  I read and respond to all mail. 
  2398.  
  2399. OS/2 Warp Unleashed, Moskowitz, Kerr, et al is a book I have wanted to review 
  2400. for a while (well, this version is actually brand-new, but you know what I 
  2401. mean).  I have just received a copy of the new edition, hot off the press, and 
  2402. the book, while good for novices too, really comes into its own in the hands of 
  2403. power users.  Many programmers are power users, so many of these tips should be 
  2404. useful in setting up your development machine. 
  2405.  
  2406. /dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5 
  2407.  
  2408.  
  2409. ΓòÉΓòÉΓòÉ 7.2. Errata ΓòÉΓòÉΓòÉ
  2410.  
  2411. Errata 
  2412.  
  2413. My WWW home page grows and grows.  It is getting a little more stable and 
  2414. up-to-date now, but as with everyone I know who has one, it is always being 
  2415. changed.  In the coming few months I may try to create an EDM/2 "homepage" and 
  2416. have a lot of information about EDM/2 and OS/2 programming on it.  We'll see 
  2417. how much time I get for this project. 
  2418.  
  2419. My school (University of Waterloo), like many schools, has a large Microsoft 
  2420. presence, and many decisions are based on not stepping on Microsoft's toes, 
  2421. since they donate large amounts of software to the school. If anyone out there 
  2422. has any experience with changing the attitudes of the powers that be, please 
  2423. e-mail me.  I would like to increase the OS/2 awareness and enthusiasm on 
  2424. campus, but it is hard.  There is at the moment a small hard-core OS/2 
  2425. following, and I would like to increase that to a large hardcore presence 
  2426. <grin>. 
  2427.  
  2428. Van Nostrand Reinhold and John Wiley & Sons (I think I got that right) have 
  2429. apparently announced the sale of all of VNR's OS/2 titles to John Wiley & Sons. 
  2430. Personally, I think that VNR jumped ship at the worst possible time, with 
  2431. Warp's growing sales, but there is obviously a lot I don't know about the 
  2432. situation.  This probably means that getting books from VNR or John Wiley & 
  2433. Sons is going to be difficult for the next little while.  I am therefore 
  2434. looking for ideas for the next couple of review columns.  E-mail me at 
  2435. bcrwhims@undergrad.math.uwaterloo.ca if you have any ideas of good 
  2436. programming/power user books for me to review. 
  2437.  
  2438. /dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5 
  2439.  
  2440.  
  2441. ΓòÉΓòÉΓòÉ 7.3. OS/2 Warp Unleashed - Deluxe Edition ΓòÉΓòÉΓòÉ
  2442.  
  2443. OS/2 Warp Unleashed - Deluxe Edition 
  2444.  
  2445. This book is just full of both common and obscure hints and tricks; it has 
  2446. chapters on the applets, the Internet, and just about anything else you can 
  2447. imagine.  Here is a list of the chapters: 
  2448.  
  2449.    1. Installation 
  2450.    2. System Configuration 
  2451.    3. Reconfiguration 
  2452.    4. Workplace Shell 
  2453.    5. Workplace Shell Objects 
  2454.    6. Configuring the Workplace Shell 
  2455.    7. Command-line Interface 
  2456.    8. REXX Programming 
  2457.    9. Virtual DOS Machines 
  2458.   10. WIN-OS/2 - Windows in OS/2 
  2459.   11. The Video Subsystem 
  2460.   12. Fonts 
  2461.   13. Printing 
  2462.   14. File Systems 
  2463.   15. Multimedia 
  2464.   16. Productivity Applets 
  2465.   17. Networking 
  2466.   18. Troubleshooting 
  2467.   19. OS/2 and the Internet 
  2468.   20. Portable Computing with OS/2 
  2469.  
  2470.   Appendix A.  The OS/2 Unleashed CD-ROM
  2471.   Appendix B.  Resources
  2472.   Appendix C.  OS/2 System Messages
  2473.  
  2474.  This book is huge!  Over 1200 pages, to be exact.  Hence, I don't think that I 
  2475.  can read everything in one month, and also have a semblance of a life. I will 
  2476.  read whatever I am interested in, and base my review on these chapters. In the 
  2477.  process, I will probably (hopefully) cover the items of interest for most of 
  2478.  the column's readers. 
  2479.  
  2480.  I skipped certain chapters, since my machine is already set up, installed, and 
  2481.  pretty well configured the way I want it, but there were still a large number 
  2482.  of chapters of interest to me.  Having skipped chapter 1, I started reading in 
  2483.  chapter 2. Many of the tips in this chapter (and the other chapters) can be 
  2484.  found on the Internet in one of the various newsgroups, or in a file on an ftp 
  2485.  site, but I have never seen anyone explain this stuff in such elaborate 
  2486.  detail, and with such accuracy and confidence as the authors of this book (et 
  2487.  al covers about a dozen other authors), many of which actually develop or 
  2488.  assist in developing OS/2 itself.  The usual foundations are well explained in 
  2489.  this book, although the authors are careful not to explain anything that they 
  2490.  feel IBM already explained well either in the documentation that came with 
  2491.  OS/2, or in the on-line help files.  Unfortunately, there is a large amount of 
  2492.  information which doesn't fall into the latter category, so the authors have 
  2493.  the opportunity to improve on what you have seen before. 
  2494.  
  2495.  Chapter 2 has a number of interesting tidbits of information about the 
  2496.  config.sys, and the file system.  Many of the usual tips are here, but there 
  2497.  are many extra tips as well.  David Moskowitz, who wrote this chapter, shows 
  2498.  you how to set up OS/2 for a minimum system, a "better" system, and a power 
  2499.  user system.  These types of tips abound, but the descriptions given here are 
  2500.  better than usual, complete with rationale.  Explanations are given for most, 
  2501.  if not all, of the unusual and obscure config.sys parameters. 
  2502.  
  2503.  Chapter 3 shows you how to move things around, which parts of OS/2 can be 
  2504.  deleted under what circumstances, and gives more configuration tips.  The 
  2505.  first item is how to remove OS/2 Warp!  If this is all you wanted to do, you 
  2506.  would probably just scan the book at the bookstore, and you certainly wouldn't 
  2507.  be reading this column.  Unless you were running a 100 OS/2 machine site, 
  2508.  perhaps.  There is a really neat section on how to use the Recovery Choices 
  2509.  screen available on booting with the Alt-F1 keystroke to set up custom 
  2510.  config.sys'es.  The end result is similar to what DOS 6.x offers with both 
  2511.  config.sys and autoexec.bat, but more integrated.  It outlines what to do if 
  2512.  you want to use your desktop like you used to use the Windows desktop, before 
  2513.  you switched.  Also explained is how to recover from INI file corruption, and 
  2514.  how to set up multiple desktop configurations.  There is a section with MSHELL 
  2515.  and TSHELL, and how to use these correctly, as well as how to use these 
  2516.  concepts to use any other program as your desktop.  Once you have your desktop 
  2517.  set up, you probably won't want to change it too much, but there is a lot of 
  2518.  interesting information here.  If you develop on a small system, perhaps you 
  2519.  may consider going to an MSHELL desktop to conserve RAM, and regain a little 
  2520.  memory, and hence performance. 
  2521.  
  2522.  Chapters 4, 5, and 6 all discuss the Workplace Shell.  Chapter 4 is a slightly 
  2523.  more in-depth tutorial than IBM gave us with OS/2.  Many obscure features are 
  2524.  noted, such as the fact that the objects listed after a Find has been 
  2525.  performed are the real thing!  Do not delete these objects.  Also, if you have 
  2526.  your desktop set to need a password on bootup, and then forget that password, 
  2527.  there are directions on how to get yourself out of that mess. 
  2528.  
  2529.  Chapter 5 discusses the objects on the desktop in elaborate detail.  The whole 
  2530.  WPS internal class hierarchy is given, and the most important ones are 
  2531.  explained.  A neat tip is given in this chapter:  how to move templates.  This 
  2532.  is not obvious at all, but once you realize that all objects have a default 
  2533.  drag-and-drop action that sometimes can be over-ridden, that the default 
  2534.  action of the templates are a version of copy, and that the move augmentation 
  2535.  key is shift, then it all comes together.  This level of detail is standard 
  2536.  throughout the book, and is immensely helpful for those of us that say "Yeah, 
  2537.  ok, but why?"  all the time.  Another neat feature of the book is that little 
  2538.  REXX scripts are given all the way to accomplish helpful tasks.  These are all 
  2539.  on the included CD-ROM, so that they don't have to be typed in.  The obscure 
  2540.  pages in the object settings notebooks finally seem more purposeful to me, 
  2541.  even if I don't personally use them all.  One of the strong points of the book 
  2542.  is that all the way through it, there are little short-cuts for commonly 
  2543.  performed actions. 
  2544.  
  2545.  Chapter 6 explains how to customize the Workplace Shell.  This includes 
  2546.  explaining the PROTSHELL and RUNWORKPLACE statements in the config.sys.  It 
  2547.  also goes through the AUTOSTART and RESTARTOBJECT parameters.  These 
  2548.  parameters are fairly misunderstood by many people, both novices and 
  2549.  self-proclaimed "experts", with which the Net abounds, but the record is set 
  2550.  straight here.  A neat little tip follows:  try putting the line SET 
  2551.  MENUSTYLE=SHORT in your config.sys.  You can probably guess what it does, but 
  2552.  what a relief from information overload on every pop-up menu the system 
  2553.  presents you with.  Many of the tips presented in earlier chapters are 
  2554.  elaborated on here as well.  There are a number of tips here on how to develop 
  2555.  WPS objects under Warp.  Some of the old tips are no longer relevant, since 
  2556.  Warp now uses DSOM by default, which means that your objects will run 
  2557.  separately from the WPS, and will no longer bring the system down, if they are 
  2558.  buggy. 
  2559.  
  2560.  Chapter 7 discusses command-line windows, but since I have done a lot of work 
  2561.  with these, I will skip this chapter.  The author likes 4OS2, but personally I 
  2562.  prefer YAOS.  It also has aliases, history, and so on, but is much more like 
  2563.  the tcsh that I use at school.  Chapter 8 is about REXX programming, and 
  2564.  again, I will move over this, having already read a number of introductory 
  2565.  REXX books.  Virtual DOS machines in chapter 9, and Win-OS/2 in chapter 10 are 
  2566.  not terribly interesting to me either.  I firmly believe in supporting the 
  2567.  OS/2 developer community, and I am not one of the people who runs NetScape for 
  2568.  Windows, WordPerfect 5.1 for DOS or Word for Windows regularly.  The current 
  2569.  batch of OS/2 programs that do the same thing are close in functionality, and 
  2570.  this is good enough for right now. 
  2571.  
  2572.  Chapter 11 covers the video subsystem, and is written by Bill Bodin, the OS/2 
  2573.  Warp Video Team Lead and Video Architect for the WPS.  His involvement with 
  2574.  OS/2 video really shows in the coverage he gives to this topic.  Like so many 
  2575.  of the chapters, this chapter is in-depth, covers pretty well everything, and 
  2576.  has a unique insight into the inner workings of OS/2.  The pros and cons of 
  2577.  8514/A, SVGA, VGA, and so on are all given.  For example, did you know that 
  2578.  the mode command now supports column widths of 1 to 255 inclusive?  Maybe 1 
  2579.  isn't terribly useful, but it is nice to know that you impose your own 
  2580.  restrictions, as opposed to following theirs.  Some alternative ways of 
  2581.  installing video drivers are given for those of you who are not able to use 
  2582.  the display driver installation utility. 
  2583.  
  2584.  Chapter 12 speaks of fonts.  I have never quite understood why screen fonts 
  2585.  seem so crude in OS/2, but I am sure that this chapter has that information 
  2586.  buried somewhere, although I was unable to find it.  Everything I have ever 
  2587.  printed from OS/2 has come out beautifully, but the fonts used on my screen 
  2588.  are frequently poorly spaced, and choppy.  I have seen a lot of other people 
  2589.  complain about this phenomenon on Usenet newsgroups, but no-one has ever 
  2590.  satisfactorily explained it.  Installation and usage of both Adobe Type 1 and 
  2591.  True Type fonts is explained. 
  2592.  
  2593.  Printing is the topic of the next chapter.  Again, I skimmed this quickly. I 
  2594.  use the HP LaserJet 4 at school, so I just print to file, and am done.  For 
  2595.  this reason, there is nothing in particular I needed to know from this 
  2596.  chapter.  Chapter 14, on the other hand, discusses file systems.  Having 
  2597.  recently written a small file system, this topic was of particular interest to 
  2598.  me.  FAT is built into Warp, whereas HPFS in an installable file system.  That 
  2599.  much I knew.  On the other hand, Warp still has to know something about HPFS 
  2600.  in order to be able to boot from an HPFS drive, with no FAT around.  I hadn't 
  2601.  really thought about that before, but it does make sense.  But, then how do 
  2602.  other people write IFSs for Warp?  It is not possible for someone to port JFS, 
  2603.  for example, and then put a little code into Warp so that it can boot from a 
  2604.  JFS disk.  Yet another chicken and egg argument...  All aspects of both file 
  2605.  systems are explained, such as caches, long/short file names, EAs, and so on. 
  2606.  The relevant parameters from config.sys are pointed out and explained.  The 
  2607.  various disk utilities that come with Warp are also outlined.  A couple of 
  2608.  neat ways of using EAs are given, such as how to store comments with a file, 
  2609.  without changing the file. 
  2610.  
  2611.  Multimedia is covered in chapter 15.  The rationale behind developing it in 
  2612.  the first place is given, and then everything from DIVE to TV is discussed. 
  2613.  Several REXX scripts are given that demonstrate how to program for multimedia 
  2614.  with REXX.  In addition to this, the applets that come with MMOS2 are covered. 
  2615.  The most popular audio cards are talked about, as well as some special 
  2616.  applications, such as Video IN.  There is even some discussion of the 
  2617.  suitability and features of the various sound cards on the market today. 
  2618.  Finally, a brief guide to video recording, multimedia and the Internet, CD-ROM 
  2619.  drives, Pen for OS/2, speech technology, and error messages are discussed. 
  2620.  
  2621.  Chapter 16 is an introduction to the Icon Editor, EPM, and the other applets. 
  2622.  There is a thick chapter 17 on networking, and another on trouble shooting. 
  2623.  The latter chapter includes sections on installation, problem prevention, 
  2624.  failure recovery, and error logging. 
  2625.  
  2626.  Chapter 19 covers the Internet.  Unfortunately, this area has been moving so 
  2627.  fast that some of the information is already out of date, although the book 
  2628.  was only just published.  Such is life.  For example, The Web Explorer covered 
  2629.  is version 0.91, whereas we now have 1.01, and the 950331 beta.  Nonetheless, 
  2630.  there is some good information in here, including a section on the 
  2631.  much-maligned Ultimail Lite.  PPP is also left out, since it was only released 
  2632.  in December/January.  The next update of this book will surely have a nice 
  2633.  section on connecting to other providers, complete with scripts and 
  2634.  information for both SLIP and PPP. 
  2635.  
  2636.  Finally, another chapter for which I don't have much use, but one that is 
  2637.  probably a god-send for many:  Portable computing with OS/2.  There is also an 
  2638.  appendix about the CD-ROM that comes with the book.  Unfortunately, the CD-ROM 
  2639.  itself is a bit messy, but the coverage of the CD in the book is excellent 
  2640.  paradoxically. 
  2641.  
  2642.  /dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5 
  2643.  
  2644.  
  2645. ΓòÉΓòÉΓòÉ 7.4. Summary ΓòÉΓòÉΓòÉ
  2646.  
  2647. Summary 
  2648.  
  2649. There is a plethora of insight and inside knowledge in this book which simply 
  2650. can not be found anywhere else.  This is one of the best books I have ever read 
  2651. about OS/2, and I have no qualms about giving it my mark of excellence, an A+. 
  2652. This is just one of those books that everyone who owns OS/2 should own.  If IBM 
  2653. licensed it, and included it with every copy of OS/2 sold, they would probably 
  2654. save a bundle in support costs.  Unfortunately, that is probably just a 
  2655. pipedream.  The only possible drawback to this book is the relatively high 
  2656. price of 39.99US$/53.99CAN$, but rest assured that once you have paid for it, 
  2657. you will not regret.  A "must buy" book. 
  2658.  
  2659. /dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5 
  2660.  
  2661.  
  2662. ΓòÉΓòÉΓòÉ 7.5. Books Reviewed ΓòÉΓòÉΓòÉ
  2663.  
  2664. Books Reviewed 
  2665.  
  2666. This list is getting rather long, so I will just add list the book reviewed 
  2667. from now on, and instead keep an index of books reviewed, and issues they are 
  2668. reviewed in.  Here is this month's entry: 
  2669.  
  2670.      OS/2 Warp Unleashed, Moskowitz, Kerr, et al. 
  2671.  
  2672.         -  Sams Publishing. ISBN 0-672-30545-3. US$39.99, CAN$53.99 
  2673.         -  OS/2 Users and Power Users 
  2674.         -  A+ 
  2675.  
  2676.       This book has a wealth of hard-to-come-by information regarding just 
  2677.       about every imaginable topic on OS/2.  This book belongs in the OS/2 
  2678.       library of everyone. 
  2679.  
  2680.  NOTES 
  2681.  
  2682.  This list contains all books I have reviewed, so that you can find what you 
  2683.  are looking for at a glance.  I will be careful to rate books fairly.  If I 
  2684.  feel a need to adjust ratings, I will adjust all of them at the same time, and 
  2685.  write a note explaining why I felt this necessary.  Please note that books 
  2686.  aimed at different audiences should only be compared with great care, if at 
  2687.  all.  I intend to concentrate on the strong points of the books I review, but 
  2688.  I will point out any weaknesses in a constructive manner. 
  2689.  
  2690.  LEGEND 
  2691.  
  2692.  BOOK:  The name of the book, and the author(s). 
  2693.  
  2694.  PUBLISHING INFORMATION:  Publishing company, ISBN, and approximate price. 
  2695.  
  2696.  AUDIENCE:  This is a description of the audience I think the book targets 
  2697.  best.  This is not intended as gospel, just a guideline for people not 
  2698.  familiar with the book. 
  2699.  
  2700.  MARK:  My opinion of the success of the book's presentation, and how well it 
  2701.  targets its audience.  Technical content, accuracy, organization, readability, 
  2702.  and quality of index all weigh heavily here, but the single most important 
  2703.  item is how well the book covers what it says it covers.  Many books try to 
  2704.  cover too much, and get a lower mark as a result. 
  2705.  
  2706.  A+        Ground-breaking, all-around outstanding book. 
  2707.  A         Excellent book. This is what I want to see happen a lot. 
  2708.  A-        Excellent book with minor flaws. 
  2709.  B+        Very good book with minor flaws or omissions. 
  2710.  B         Good book with some flaws and omissions. 
  2711.  B-        Good book, but in need of improvement. 
  2712.  C+        Mediocre book with some potential, but in need of some updating. 
  2713.  C         Mediocre book with some good sections, but badly in need of fixing. 
  2714.  C-        Mediocre book, little good material, desperately in need of an 
  2715.            overhaul. 
  2716.  D         Don't buy this book unless you need it, and nothing else exists. 
  2717.  F         Don't buy this book.  Period. 
  2718.  
  2719.  COMMENTS:  This is a very brief summary of the review proper. 
  2720.  
  2721.  /dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5 
  2722.  
  2723.  
  2724. ΓòÉΓòÉΓòÉ 7.6. Index ΓòÉΓòÉΓòÉ
  2725.  
  2726. Index 
  2727.  
  2728. This Content Index is designed to let you find the book that covers the topics 
  2729. you need to learn about.  It will eventually have a lot of categories, with 
  2730. each book being rated along each row.  These tables will be quite large, and 
  2731. will continually grow, so please give me your feedback regarding what 
  2732. categories you would like to see, and which you don't.  It may take me a while 
  2733. to flesh them out, so have a little patience. 
  2734.  
  2735. BOOK LEGEND 
  2736.  
  2737. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2738. ΓöéCode ΓöéIssue  ΓöéTitle                                                              Γöé
  2739. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2740. ΓöéRWP  Γöé2-3    ΓöéReal World Programming for OS/2 2.1                                Γöé
  2741. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2742. ΓöéLPE  Γöé2-4    ΓöéLearning to Program OS/2 2.0 Presentation Manager by Example       Γöé
  2743. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2744. ΓöéODD  Γöé2-5    ΓöéWriting OS/2 2.1 Device Drivers in C                               Γöé
  2745. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2746. ΓöéGPI  Γöé2-6    ΓöéOS/2 Presentation Manager GPI                                      Γöé
  2747. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2748. ΓöéTAO  Γöé2-7    ΓöéThe Art of OS/2 2.1 C Programming                                  Γöé
  2749. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2750. ΓöéMOR  Γöé2-8    ΓöéMastering OS/2 REXX                                                Γöé
  2751. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2752. ΓöéRSH  Γöé2-9    ΓöéREXX Reference Summary Handbook                                    Γöé
  2753. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2754. ΓöéADO  Γöé2-10   ΓöéApplication Development Using OS/2 REXX                            Γöé
  2755. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2756. ΓöéPMP  Γöé2-11   ΓöéOS/2 Presentation Manager Programming                              Γöé
  2757. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2758. ΓöéDOA  Γöé3-1    ΓöéDesigning OS/2 Applications                                        Γöé
  2759. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2760. ΓöéOSP  Γöé3-2    ΓöéOS/2 Programming                                                   Γöé
  2761. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2762. ΓöéTGO  Γöé3-4    ΓöéThe GUI-OOUI War                                                   Γöé
  2763. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2764. ΓöéOU   Γöé3-5    ΓöéOS/2 Warp Unleashed, Deluxe Edition                                Γöé
  2765. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2766.  
  2767. NOTE:  books which cover the same material can look similar in this table, but 
  2768. be different in real life.  The style of a book, for example, can not be seen 
  2769. from a quick table, so make sure that you follow up by reading the reviews of 
  2770. the books you find here.  Finally, be sure that the books you are comparing are 
  2771. aimed at the same audiences. 
  2772.  
  2773. PM C BOOKS 
  2774.  
  2775. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2776. ΓöéBOOK ΓöéMARK ΓöéKernel ΓöéDevice ΓöéVIO andΓöéPM     ΓöéGPI    ΓöéFonts  ΓöéPrint  Γöé
  2777. Γöé     Γöé     ΓöéBasics ΓöéDriver ΓöéAVIO   ΓöéIntro  Γöé       Γöé       Γöé       Γöé
  2778. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2779. ΓöéRWP  ΓöéB+   Γöé2      Γöé0      Γöé0      Γöé4      Γöé4      Γöé4      Γöé3      Γöé
  2780. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2781. ΓöéPME  ΓöéB-   Γöé1      Γöé0      Γöé0      Γöé2      Γöé2      Γöé2      Γöé0      Γöé
  2782. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2783. ΓöéODD  ΓöéA    Γöé0      Γöé5      Γöé0      Γöé0      Γöé1      Γöé0      Γöé1      Γöé
  2784. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2785. ΓöéGPI  ΓöéC+   Γöé0      Γöé0      Γöé0      Γöé0      Γöé5      Γöé2      Γöé3      Γöé
  2786. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2787. ΓöéTAO  ΓöéB+   Γöé3      Γöé2      Γöé1      Γöé4      Γöé1      Γöé2      Γöé0      Γöé
  2788. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2789. ΓöéPMP  ΓöéA-   Γöé1      Γöé0      Γöé1      Γöé5      Γöé3      Γöé4      Γöé2      Γöé
  2790. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2791. ΓöéOSP  ΓöéB+   Γöé2      Γöé0      Γöé0      Γöé3      Γöé2      Γöé1      Γöé0      Γöé
  2792. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2793.  
  2794. REXX BOOKS: 
  2795.  
  2796. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2797. ΓöéBOOK ΓöéMARK ΓöéREXX     ΓöéWPS      ΓöéReferenceΓöé
  2798. Γöé     Γöé     ΓöéIntro    Γöé         Γöé         Γöé
  2799. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2800. ΓöéMOR  ΓöéB    Γöé4        Γöé0        Γöé2        Γöé
  2801. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2802. ΓöéRSH  ΓöéA    Γöé1        Γöé2        Γöé5        Γöé
  2803. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2804. ΓöéADO  ΓöéA-   Γöé3        Γöé2        Γöé4        Γöé
  2805. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2806.  
  2807. SYSTEM AND NON-PROGRAMMING BOOKS: 
  2808.  
  2809. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2810. ΓöéBOOK ΓöéMARK ΓöéKernel ΓöéDevice ΓöéVIO andΓöéPM     ΓöéThread ΓöéGPI    ΓöéFonts  ΓöéPrint  ΓöéWPS    Γöé
  2811. Γöé     Γöé     ΓöéBasics ΓöéDriver ΓöéAVIO   Γöé       Γöé       Γöé       Γöé       Γöé       Γöé       Γöé
  2812. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2813. ΓöéDOA  ΓöéA    Γöé4      Γöé4      Γöé2      Γöé4      Γöé5      Γöé3      Γöé2      Γöé3      Γöé0      Γöé
  2814. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2815. ΓöéTGO  ΓöéB    Γöé0      Γöé0      Γöé0      Γöé2      Γöé1      Γöé0      Γöé2      Γöé1      Γöé5      Γöé
  2816. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2817. ΓöéOU   ΓöéA+   Γöé1      Γöé4      Γöé4      Γöé5      Γöé2      Γöé5      Γöé5      Γöé5      Γöé5      Γöé
  2818. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2819.  
  2820. RATINGS LEGEND: 
  2821.  
  2822. ΓöîΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2823. Γöé0ΓöéNo coverage           Γöé
  2824. Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2825. Γöé1ΓöéVery light coverage   Γöé
  2826. Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2827. Γöé2ΓöéIntroductory coverage Γöé
  2828. Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2829. Γöé3ΓöéGood Coverage         Γöé
  2830. Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2831. Γöé4ΓöéIn-depth coverage     Γöé
  2832. Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2833. Γöé5ΓöéAuthoritative         Γöé
  2834. ΓööΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2835.  
  2836. /dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5 
  2837.  
  2838.  
  2839. ΓòÉΓòÉΓòÉ 7.7. Coming Up ΓòÉΓòÉΓòÉ
  2840.  
  2841. Coming Up 
  2842.  
  2843. I haven't yet picked out a book for next month, but I am going to look for an 
  2844. intermediate PM book.  The following are some other books I intend to review, 
  2845. in no particular order: 
  2846.  
  2847.      OS/2 Presentation Manager GPI, 2nd edition, Winn 
  2848.      The Design of OS/2, 2nd Edition, Kogan and Deitel 
  2849.      Designing High Powered OS/2 Applications, Reich (tentative title) 
  2850.  
  2851.  I am considering reviewing the IBM OS/2 Redbooks, since they are readily and 
  2852.  cheaply available, and look like good reference. 
  2853.  
  2854.  If anyone has a book they want to see reviewed, I will be happy to oblige. 
  2855.  Just mail me and tell me.  Publishers can send me books at the address on my 
  2856.  personal page at the end of the magazine, and I will review all OS/2 
  2857.  development- related and advanced user books I receive. 
  2858.  
  2859.  /dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5 
  2860.  
  2861.  
  2862. ΓòÉΓòÉΓòÉ 8. OOPS Avenue ΓòÉΓòÉΓòÉ
  2863.  
  2864.  
  2865. ΓòÉΓòÉΓòÉ 8.1. Introduction ΓòÉΓòÉΓòÉ
  2866.  
  2867. OOPS Avenue 
  2868.  
  2869. Written by Gordon Zeglinski 
  2870.  
  2871. Using C++ In Dynamic Link Libraries 
  2872.  
  2873. Just when things start moving along, a new set of setbacks arise.  If they 
  2874. weren't happening to me, they'd be quite comical.  At any rate, we'll take a 
  2875. break from SOM/DSOM in this issue, and look at using C++ code from Dynamic Link 
  2876. Libraries (DLLs).  Before looking at C++ specific issues, we start by looking 
  2877. at some DLL basics. 
  2878.  
  2879. OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5 
  2880.  
  2881.  
  2882. ΓòÉΓòÉΓòÉ 8.2. DLL Basics ΓòÉΓòÉΓòÉ
  2883.  
  2884. DLL Basics 
  2885.  
  2886. A DLL is a library of code and or resources that can be loaded and unloaded 
  2887. dynamically and shared between processes.  Dynamic loading means that the 
  2888. library is loaded at run time rather than being statically bound to the 
  2889. application.  When a DLL is loaded or unloaded, the operating system calls the 
  2890. function _DLL_InitTerm().  The following snippet is a skeleton _DLL_InitTerm() 
  2891. function: 
  2892.  
  2893. unsigned long _System _DLL_InitTerm(unsigned long hModule, unsigned long ulFlag){
  2894.  
  2895.    switch (ulFlag) {
  2896.       case 0 :
  2897.          // do load initialization here
  2898.          break;
  2899.       case 1 :
  2900.          // do unload termination here
  2901.          break;
  2902.    }
  2903.  
  2904. return 1UL;       //return 0 if we want to indicate that the initialization code has failed
  2905. }
  2906.  
  2907. The above function (in its current form) is only useful for a resource DLL or a 
  2908. DLL that contains only assembly language functions.  High level languages will 
  2909. require initialization and termination routines to be called.  If we use 
  2910. C-Set++ as an example, the minimal _DLL_InitTerm() function would be as 
  2911. follows: 
  2912.  
  2913. unsigned long _System _DLL_InitTerm(unsigned long hModule, unsigned long ulFlag){
  2914.  
  2915.    switch (ulFlag) {
  2916.       case 0:
  2917.          //initialize the C Run Time library
  2918.          if (_CRT_init() == -1)
  2919.             return 0UL;
  2920.  
  2921.          //for C++ code we call __ctordtorInit to create the global/static intances
  2922.          __ctordtorInit();
  2923.  
  2924.          // do user load initialization here
  2925.          break;
  2926.       case 1:
  2927.          // do user unload termination here
  2928.  
  2929.          //for C++ code we call __ctordtorTerm to destroy static/global instances
  2930.          __ctordtorTerm();
  2931.  
  2932.          //if the C Run Time library is STATICALLY linked, we call _CRT_term to free up the
  2933.          //resources used by the CRTL
  2934.          _CRT_term();
  2935.          break;
  2936.    }
  2937.  
  2938. return 1UL;       //return 0 if we want to indicate that the initialization code has failed
  2939. }
  2940.  
  2941. Note:  for compilers other than C-Set++, different run time library 
  2942. initialization/termination calls have to be made. 
  2943.  
  2944. Functions are exported from a DLL by either name or numerical offset.  The 
  2945. standard way of exporting a function is to specify its name in the "EXPORTS" 
  2946. section of the definition file for the DLL.  Most compilers also allow a short 
  2947. cut method of exporting functions.  This is to declare them with a special 
  2948. keyword that causes the compiler to generate code that the linker will 
  2949. automatically export for you.  In C-Set++ one uses the "_Export" keyword. 
  2950.  
  2951. This seems simple enough.  However, there are numerous pitfalls as we shall 
  2952. soon see. 
  2953.  
  2954. OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5 
  2955.  
  2956.  
  2957. ΓòÉΓòÉΓòÉ 8.3. DLLs and C++ ΓòÉΓòÉΓòÉ
  2958.  
  2959. DLLs and C++ 
  2960.  
  2961. C++ mangles function names.  This can increase the difficulty in exporting C++ 
  2962. functions.  C-Set++ provides a utility called CPPFILT to extract mangled names 
  2963. so that they may be placed in the .DEF file.  Alternatively, one can use the 
  2964. _Export keyword to have the compiler and linker work together to export the 
  2965. function.  Let's define the class Foo so that it's member functions will be 
  2966. exported.  The code to do this is presented below: 
  2967.  
  2968. struct FooBar{
  2969.    int   Y;
  2970. }
  2971.  
  2972. class _Export Foo{
  2973. public:
  2974.    Foo();
  2975.    ~Foo();
  2976.  
  2977.    int      GetVar(){return FooVar;}
  2978.    void     SetVar(int);
  2979.    FooBar*  CreateFooBar();
  2980.  
  2981. protected:
  2982.    int      FooVar;
  2983. };
  2984.  
  2985. Note:  Borland C++ allows one to use the _export keyword in a similar manner as 
  2986. one uses _Export in C-Set++. 
  2987.  
  2988. By placing the keyword _Export after the keyword class, the compiler 
  2989. automatically exports all non-inline functions.  In this example Foo::Foo(), 
  2990. Foo::~Foo(), Foo::SetVar(int), and Foo::CreateFooBar() will all be exported. 
  2991. Foo::GetVar() will not be exported because it is implicitly defined as inline. 
  2992.  
  2993. Let's say that we have coded Foo's member functions so they can be exported. 
  2994. We compiled the code and linked it statically to the C run time library to form 
  2995. a DLL.  We then link the resulting DLL to the following code snippet to produce 
  2996. an executable file. 
  2997.  
  2998. void main(){
  2999.    Foo      FooInst;
  3000.    FooBar   *Bar;
  3001.  
  3002.    Bar=FooInst->CreateFooBar();
  3003.  
  3004.    delete Bar;
  3005. }
  3006.  
  3007. Let's assume that Foo::CreateFooBar() is contained in the Foo DLL and is 
  3008. defined as follows: 
  3009.  
  3010. FooBar*  Foo::CreateFooBar(){
  3011.       return new FooBar;
  3012. }
  3013.  
  3014. We've now compiled and linked our code.  Everything should be fine until we 
  3015. actually try running the code.  In this scenario, we have 2 active C run time 
  3016. libraries.  The first is bound to the Foo DLL and the second is bound to the 
  3017. executable.  When the delete operator is evoked, the memory is freed from the 
  3018. local C RTL.  This is where the problem will occur.  The memory was allocated 
  3019. in the DLL's C RTL and an attempt to free it was made in the executable's CRTL. 
  3020. There are two ways of solving this problem.  First, one can use another DLL 
  3021. that holds the C RTL and dynamically link this DLL to FOO DLL and the 
  3022. executable.  Alternatively, one can create and export a new function in FOO DLL 
  3023. that is used to delete instances of FooBar. 
  3024.  
  3025. Creating a separate DLL for the C RTL is not without its pitfalls.  The biggest 
  3026. pitfall is that OS/2 doesn't unload DLLs in reverse order.  In fact, the order 
  3027. in which they are unloaded is somewhat unpredictable.  This is a serious 
  3028. problem.  What if the C RTL DLL is unloaded first?  If this happens, it's most 
  3029. likely that when subsequent DLLs are unloaded they will trap or hang the 
  3030. process if they have any static or global object instances in them.  One way 
  3031. around this is to use exit handlers at different priorities.  These exit 
  3032. handlers call the __ctordtorTerm() function and keep track of the DLL's 
  3033. initialization state.  Another method could be to use a counter variable in the 
  3034. C RTL DLL that keeps track of how many other DLLs are using it.  This method 
  3035. would require the C RTL DLL to export a function for incrementing and 
  3036. decrementing this counter.  These functions would have to be called each time a 
  3037. dependent DLL is loaded and unloaded.  When the counter reaches 0, the C RTL is 
  3038. shutdown by calling _CRT_term.  Both the counter method and the exit handler 
  3039. method require each DLL to use a custom _DLL_InitTerm function. 
  3040.  
  3041. OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5 
  3042.  
  3043.  
  3044. ΓòÉΓòÉΓòÉ 8.4. Using C++ DLLs Across Different Languages or Compilers ΓòÉΓòÉΓòÉ
  3045.  
  3046. Using C++ DLLs Across Different Languages or Compilers 
  3047.  
  3048. Because the name mangling scheme is not standardized, nor is the calling 
  3049. convention for that matter, it is impossible to use C++ functions "raw" across 
  3050. different compilers.  To do this, one has to define C to C++ wrapper functions. 
  3051. The following snippet shows how to wrap the Foo class in C- Set++. 
  3052.  
  3053. extern "C"{
  3054.    void* _System CreateFoo();
  3055.    void  _System DestroyFoo(void *_Foo);
  3056.  
  3057.    int   _System FooGetVar(void *_Foo);
  3058.    void  _System FooSetVar(void *_Foo, int V);
  3059.    void* _System FooCreateFooBar(void *_Foo);
  3060.  
  3061.    void  _System DestroyFooBar(void *_FooBar);
  3062. };
  3063.  
  3064. void* _System CreateFoo(){
  3065.    return new Foo;
  3066. }
  3067.  
  3068. void  _System DestroyFoo(void *_Foo){
  3069.    delete ((Foo*)_Foo);
  3070. }
  3071.  
  3072. int   _System FooGetVar(void *_Foo){
  3073.    return ((Foo*)_Foo)->GetVar();
  3074. }
  3075.  
  3076. void  _System FooSetVar(void *_Foo, int V){
  3077.    ((Foo*)_Foo)->SetVar(V);
  3078. }
  3079.  
  3080. void* _System FooCreateFooBar(void *_Foo){
  3081.    return ((Foo*)_Foo)->CreateFooBar();
  3082. }
  3083.  
  3084. void  _System DestroyFooBar(void *_FooBar){
  3085.    delete ((FooBar*)_FooBar);
  3086. }
  3087.  
  3088. The function names CreateFoo(), DestroyFoo(), etc. can be exported by placing 
  3089. them in the EXPORTS section of the DLLS module definition file.  The following 
  3090. snippet illustrates how these wrapper functions can be used. 
  3091.  
  3092. void main(){
  3093.    void  *FooInst=CreateFoo();
  3094.  
  3095.    FooSetVar(FooInst, 10);
  3096.  
  3097.    DestroyFoo(FooInst);
  3098. }
  3099.  
  3100. The above snippet can be the main routine for either a C or a C++ program. The 
  3101. problem of multiple C run time libraries is avoided in this case because all 
  3102. memory allocation and deallocation is handled in the DLL's wrapper functions. 
  3103.  
  3104. OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5 
  3105.  
  3106.  
  3107. ΓòÉΓòÉΓòÉ 8.5. Wrapping Things Up ΓòÉΓòÉΓòÉ
  3108.  
  3109. Wrapping Things Up 
  3110.  
  3111. That's it for another issue.  We have seen several ways of using C++ code 
  3112. contained in a DLL.  The problem of having multiple C runtime libraries within 
  3113. a single process along with the problem of DLL unloading has been examined. 
  3114. Several solutions to each of these problems have been presented here. 
  3115.  
  3116. OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5 
  3117.  
  3118.  
  3119. ΓòÉΓòÉΓòÉ 9. Introduction to PM Programming ΓòÉΓòÉΓòÉ
  3120.  
  3121.  
  3122. ΓòÉΓòÉΓòÉ 9.1. Introduction ΓòÉΓòÉΓòÉ
  3123.  
  3124. Introduction to PM Programming 
  3125.  
  3126. Written by Larry Salomon, Jr. 
  3127.  
  3128. Introduction 
  3129.  
  3130. The purpose of this column is to provide the readers out there who are not 
  3131. familiar with PM application development the information necessary to satisfy 
  3132. their curiosity, educate themselves, and give them an advantage over the 
  3133. documentation supplied by IBM.  Of course, much of this stuff could probably be 
  3134. found in one of the many books out there, but the problem with books in general 
  3135. is that they don't answer the questions you have after you read the book the 
  3136. first time through. 
  3137.  
  3138. I will gladly entertain feedback from the readers about what was "glossed over" 
  3139. or what was detailed well, what tangential topics need to be covered and what 
  3140. superfluous crap should have been removed.  This feedback is essential in 
  3141. guaranteeing that you get what you pay for.  <grin> 
  3142.  
  3143. It should be said that you must not depend solely on this column to teach you 
  3144. how to develop PM applications; instead, this should be viewed as a supplement 
  3145. to your other information storehouses (books, the network conferences, etc.). 
  3146. Because this column must take a general approach, there will be some topics 
  3147. that you would like to see discussed that really do not belong here.  Specific 
  3148. questions can be directed to me via email and I will do my best to answer them 
  3149. in a timely fashion. 
  3150.  
  3151. Last Month 
  3152.  
  3153. Last month we began looking at the menu control, which we will continue with 
  3154. this month. 
  3155.  
  3156. Introduction to PM Programming - EDM/2 - May 1995 - Volume 3, Issue 5 
  3157.  
  3158.  
  3159. ΓòÉΓòÉΓòÉ 9.2. Basic Knowledge Required ΓòÉΓòÉΓòÉ
  3160.  
  3161. Basic Knowledge Required 
  3162.  
  3163. Before we may continue, we should take a brief look at the typical use of a 
  3164. menu control, from the programmer's perspective.  This involves the definitions 
  3165. of the manifest constants, the menu template definition, the "loading" of the 
  3166. menu (you'll see why "loading" is in quotes in a minute), and the processing of 
  3167. the user's actions.  We're taking this different approach to looking at the 
  3168. window class because - as we stated last month - the menu provides the most 
  3169. widely used functionality of any of the window classes; as such, you'll need to 
  3170. know how to use it because you'll be writing this code more times than any 
  3171. other. 
  3172.  
  3173. Manifest Constants 
  3174.  
  3175. Manifest constants - a.k.a.  #define's - are a convenient language element 
  3176. which allow us to use a "name" in place of something else.  For menus, the 
  3177. "something else" is a number which represents an identifier unique to that menu 
  3178. template.  You'll find that in larger applications that the file containing 
  3179. these constants can grow quite large, so it would be helpful if, at a glance, 
  3180. you could determine the use of the constant from looking at its name.  To 
  3181. accomplish this, I defined a naming convention.  You can use this one or your 
  3182. own - it doesn't matter.  What does matter is that you spend less time trying 
  3183. to find out how a constant is used and more time on actually using the 
  3184. constant.  For menus, I use the following: 
  3185.  
  3186.  Constant form       What it represents 
  3187.  M_id                Menu or submenu identifier 
  3188.  MI_id               Menuitem identifier 
  3189.  
  3190.  The constants that are used for resource definitions I keep in a separate file 
  3191.  to allow me to make the file a dependancy of all files that use resources. 
  3192.  This is simply a suggestion. 
  3193.  
  3194.  Template Definition 
  3195.  
  3196.  Under Windows, there is App Studio which allows you to define and maintain all 
  3197.  of your resources.  How come there isn't something like this for OS/2? 
  3198.  Regardless, you have to design your menus "blind," meaning that you can't see 
  3199.  the result until you actually use the menu you've built. 
  3200.  
  3201.  As it is with writing applications, designing your menu layout should be the 
  3202.  most important action; a confusing or deep (i.e. many pullrights) menu 
  3203.  structure will often confuse the user and turn them away from using your 
  3204.  application.  Group the items in submenus in a logical fashion so that the 
  3205.  user can "take a guess" at where to look when trying to execute a particular 
  3206.  action. 
  3207.  
  3208.  IBM's "Common User Access" (CUA) guidelines define a number of pulldown menus 
  3209.  and a (non-inclusive) list of what they should contain.  I've included a brief 
  3210.  list of these (since I cannot find my CUA book <pout>) below: 
  3211.  
  3212.  Pulldown name       Menu items contained therein 
  3213.  File                New, Open, Close, Save, Save as, etc. 
  3214.  Edit                Undo, Copy, Cut, Paste, etc. 
  3215.  Help                Help index, General help, Using help, Keys help 
  3216.  
  3217.  Another important CUA note is the use of the ellipsis and bang punctuation 
  3218.  marks on text.  An ellipsis should be appended to menu item text when 
  3219.  selecting the menu item results in a dialog being displayed.  A bang should be 
  3220.  appended to text belonging to items on the action bar (note that this 
  3221.  therefore excludes pullrights and any popup menu items) when selecting them 
  3222.  does not display a pulldown menu (i.e. when it is a leaf-node).  These are 
  3223.  used as feedback indicators to the user to alert them about the behavior of 
  3224.  the application without having them find out "the hard way." 
  3225.  
  3226.  Loading a Menu 
  3227.  
  3228.  Loading a menu usually involves the setting of a flag only.  No explicit 
  3229.  loading is usually performed by the application code.  (Popup menus are the 
  3230.  exception to this rule, since the current CUA specification eliminates action 
  3231.  bars.)  In the call to WinCreateStdWindow(), simply include FCF_MENU on the 
  3232.  set of flags passed (by reference) as the third parameter. 
  3233.  
  3234.      #define RES_CLIENT      256
  3235.  
  3236.      HWND hwndFrame;
  3237.      HWND hwndClient;
  3238.      ULONG ulCreate=FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX |
  3239.                        FCF_MENU | FCF_SHELLPOSITION | FCF_TASKLIST;
  3240.  
  3241.      hwndFrame=WinCreateStdWindow(HWND_DESKTOP,
  3242.                                   WS_VISIBLE,
  3243.                                   &ulCreate,
  3244.                                   CLS_CLIENT,
  3245.                                   "Test application"
  3246.                                   0,
  3247.                                   NULLHANDLE,
  3248.                                   RES_CLIENT,
  3249.                                   &hwndClient);
  3250.  
  3251.  It has been stated before in this column (I hope) that, when using FCF_MENU, 
  3252.  FCF_ICON, or FCF_ACCELTABLE that the eighth parameter must specify the 
  3253.  resource identifier of the resources corresponding to these flags.  Since we 
  3254.  specified FCF_MENU, we should have a menu template defined that begins with: 
  3255.  
  3256.        MENU RES_CLIENT
  3257.          :
  3258.  
  3259.  If we do not have this defined, the WinCreateStdWindow() function will fail. 
  3260.  A useful note here is that, as each component of the window specified in 
  3261.  ulCreate is successfully created, the corresponding bit in ulCreate is set to 
  3262.  0. So, the components that were not created successfully can be determined by 
  3263.  examining ulCreate after the function fails. 
  3264.  
  3265.  Processing the User's Requests 
  3266.  
  3267.  Now we learn how to utilize the menu in our application code.  There are 
  3268.  usually two messages that we will be interested in when coding our 
  3269.  application:  WM_INITMENU and WM_COMMAND.  Note that, if any MENUITEMs have 
  3270.  the MIS_SYSCOMMAND or MIS_HELP style, we will need to add the WM_SYSCOMMAND 
  3271.  and WM_HELP messages to this list, but for the moment we'll assume that we 
  3272.  have none with these menu item styles. 
  3273.  
  3274.  WM_INITMENU is sent to the client window whenever a menu or submenu is about 
  3275.  to be used by the user, e.g.  when the user presses F10 to get to the action 
  3276.  bar, when the user clicks on a pulldown menu to display the pulldown, etc. 
  3277.  Intercepting this message allows us to dynamically enable or disable menu 
  3278.  items according to the state of our application.  For example, if the user 
  3279.  selects the "Print" menuitem, you might want to disable the "Exit" menuitem 
  3280.  until printing is completed.  We will see later how to change menuitem 
  3281.  attributes. 
  3282.  
  3283.  SHORT1FROMMP(mpParm1) specifies the identifier of the menu.  If the actionbar 
  3284.  is the cause of the message, this will be FID_MENU; otherwise, it will be the 
  3285.  identifier you specified on the SUBMENU statement in the menu template. 
  3286.  
  3287.  HWNDFROMMP(mpParm2) is the handle of the window corresponding to the 
  3288.  identifier.  You should know that pulldown and pullright menus are actually 
  3289.  separate windows which belong to something called an "object" window when not 
  3290.  in use.  When you click on a pulldown, the appropriate window is retrieved 
  3291.  from the object window and displayed on the desktop.  This window handle is 
  3292.  needed to send messages to the menu. 
  3293.  
  3294.  WM_COMMAND, WM_SYSCOMMAND, and WM_HELP are all sent whenever the user selects 
  3295.  a menuitem with the corresponding style. This is your indicator that the user 
  3296.  wants something done and that you are to process this request. 
  3297.  
  3298.  SHORT1FROMMP(mpParm1) specifies the identifier of the menuitem selected. 
  3299.  
  3300.  SHORT1FROMMP(mpParm2) specifies the source of the message and will always be 
  3301.  CMDSRC_MENU when this message is sent via a menu control. 
  3302.  
  3303.  SHORT2FROMMP(mpParm2) is TRUE if this message was sent as the result of a 
  3304.  mouse action or FALSE if sent as the result of a keyboard action. 
  3305.  
  3306.  Introduction to PM Programming - EDM/2 - May 1995 - Volume 3, Issue 5 
  3307.  
  3308.  
  3309. ΓòÉΓòÉΓòÉ 9.3. Next Month ΓòÉΓòÉΓòÉ
  3310.  
  3311. Next Month 
  3312.  
  3313. Next month we'll start to look at a sample application that uses the menu 
  3314. control, and we'll begin to look at the MM_ message family which allows you to 
  3315. interact with the menu control.  As always, feedback will be enjoyed immensely; 
  3316. send any comments, suggestions, etc. to os2man@panix.com. 
  3317.  
  3318. Introduction to PM Programming - EDM/2 - May 1995 - Volume 3, Issue 5 
  3319.  
  3320.  
  3321. ΓòÉΓòÉΓòÉ 10. Contributors to this Issue ΓòÉΓòÉΓòÉ
  3322.  
  3323. Are You a Potential Author? 
  3324.  
  3325. We are always looking for (new) authors.  If you have a topic about which you 
  3326. would like to write, send a brief description of the topic electronically to 
  3327. any of the editors, whose addresses are listed below, by the 15th of the month 
  3328. before the month in which your article will appear.  This alerts us that you 
  3329. will be sending an article so that we can plan the issue layout accordingly. 
  3330. After you have done this, get the latest copy of the Article Submission 
  3331. Guidelines from hobbes.nmsu.edu in the /os2/newsltr directory.  (The file is 
  3332. artsub.zip.) The completed text of your article should be sent to us no later 
  3333. than five days prior to the last day of the month; any articles received after 
  3334. that time may be pushed to the next issue. 
  3335.  
  3336. The editors can be reached at the following email addresses: 
  3337.  
  3338.      Larry Salomon - os2man@panix.com (Internet). 
  3339.      Carsten Whimster - bcrwhims@undergrad.math.uwaterloo.ca (Internet). 
  3340.  
  3341.  The following people contributed to this issue in one form or another (in 
  3342.  alphabetical order): 
  3343.  
  3344.      Larry Salomon, Jr. 
  3345.      Carsten Whimster 
  3346.      Johan Wikman 
  3347.      Gordon Zeglinski 
  3348.      Network distributors 
  3349.  
  3350.  Contributors - EDM/2 - May 1995 - Volume 3, Issue 5 
  3351.  
  3352.  
  3353. ΓòÉΓòÉΓòÉ 10.1. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
  3354.  
  3355. Larry Salomon Jr. 
  3356.  
  3357. Larry Salomon Jr. has been developing OS/2 applications since version 1.1 in 
  3358. 1989.  He has written numerous applications, including the Scramble applet that 
  3359. was included in OS/2 versions 2.0-2.11, and the I-Brow, Magnify, and Screen 
  3360. Capture trio that has been distributed on numerous CD-ROMs. 
  3361.  
  3362. Larry is also the coauthor of the successful book, The Art of OS/2 2.1 C 
  3363. Programming (Wiley-QED).  Finally, he is the CEO/President of IQPac Inc. which 
  3364. is responsible for the publication of EDM/2 and he is a frequent contributor to 
  3365. the publication. 
  3366.  
  3367. Larry can be reached electronically via the Internet at os2man@panix.com. 
  3368.  
  3369. Contributors - EDM/2 - May 1995 - Volume 3, Issue 5 
  3370.  
  3371.  
  3372. ΓòÉΓòÉΓòÉ 10.2. Carsten Whimster ΓòÉΓòÉΓòÉ
  3373.  
  3374. Carsten Whimster 
  3375.  
  3376. Carsten is an undergraduate Computer Science student at the University of 
  3377. Waterloo.  He is currently in fourth year, and enjoying it immensely.  He uses 
  3378. Watcom C/C++ 10.0a and Watcom VX-REXX 2.0b.  Carsten is the author of some 
  3379. commandline utilities, POV-Panel/2, and soon to come POVEd.  He is also a 
  3380. TEAM-OS/2 member, and has adopted a little computer store called The Data Store 
  3381. in Waterloo, Ontario. 
  3382.  
  3383. You may reach Carsten... 
  3384.  
  3385. ...via email: 
  3386.  
  3387. bcrwhims@undergrad.math.uwaterloo.ca - Internet 
  3388.  
  3389. ...World Wide Web homepage (incomplete; aren't they all): 
  3390.  
  3391. http://www.undergrad.math.uwaterloo.ca/~bcrwhims - WWW 
  3392.  
  3393. ...via snail mail: 
  3394.  
  3395. Carsten Whimster
  3396. 318A Spruce Street
  3397. Waterloo, Ontario
  3398. Canada
  3399. N2L 3M7
  3400.  
  3401. ...via phone 
  3402.  
  3403. (519) 886-2439 
  3404.  
  3405. Contributors - EDM/2 - May 1995 - Volume 3, Issue 5 
  3406.  
  3407.  
  3408. ΓòÉΓòÉΓòÉ 10.3. Johan Wikman ΓòÉΓòÉΓòÉ
  3409.  
  3410. Johan Wikman 
  3411.  
  3412. Johan Wikman received his Master's degree in Computer Science with a thesis 
  3413. "Adding remote execution capability to operating systems".  He has been 
  3414. programming for OS/2, using C++, ever since 1990. 
  3415.  
  3416. Currently he works for Nokia Telecommunications where he takes part in a 
  3417. project that developes network management software in a Unix environment.  In 
  3418. his spare time, he continues working on RMX-OS2, a system that provides remote 
  3419. execution for OS/2. 
  3420.  
  3421. Johan can be reached electronically via the Internet at 
  3422. johan.wikman@ntc.nokia.com, or via ordinary mail: 
  3423.  
  3424. Johan Wikman
  3425. Smedjeviksvagen 23 B 22
  3426. FI-00200 Helsinki
  3427. FINLAND
  3428.  
  3429. Contributors - EDM/2 - May 1995 - Volume 3, Issue 5 
  3430.  
  3431.  
  3432. ΓòÉΓòÉΓòÉ 10.4. Gordon Zeglinski ΓòÉΓòÉΓòÉ
  3433.  
  3434. Gordon Zeglinski 
  3435.  
  3436. Gordon Zeglinski is a freelance programmer/consultant who received his Master's 
  3437. degree in Mechanical Engineering with a thesis on C++ sparse matrix objects. 
  3438. He has been programming in C++ for 6 years and also has a strong background in 
  3439. FORTRAN.  He started developing OS/2 applications with version 2.0 . 
  3440.  
  3441. His current projects include a client/server communications program that 
  3442. utilitizes OS/2's features which has entered beta testing.  Additionally, he is 
  3443. involved in the development of a "real-time" automated vehicle based on OS/2 
  3444. and using C++ in which he does device driver development and designs the 
  3445. applications that comprise the control logic and user interface. 
  3446.  
  3447. He can be reached via the Internet at zeglins@cc.umanitoba.ca. 
  3448.  
  3449. Contributors - EDM/2 - May 1995 - Volume 3, Issue 5 
  3450.  
  3451.  
  3452. ΓòÉΓòÉΓòÉ 10.5. Network distributors ΓòÉΓòÉΓòÉ
  3453.  
  3454. Network Distributors 
  3455.  
  3456. These people are part of our distribution system to provide EDM/2 on networks 
  3457. other than the Internet.  Their help to provide access to this magazine for 
  3458. others is voluntary and we appreciate them a lot! 
  3459.  
  3460.      Paul Hethmon (phethmon@utk.edu) - Compuserve 
  3461.      Gess Shankar (gess@knex.mind.org) - Internet 
  3462.      Jason B. Tiller (PeerGynt@aol.com) - America On-line 
  3463.      David Singer (singer@almaden.ibm.com) - IBM Internal 
  3464.      Andre Asselin (ASSELIN AT RALVM12) - IBM Internal 
  3465.  
  3466.  If you would like to become a "network distributor", be sure to contact the 
  3467.  editors so that we can give you the credit you deserve! 
  3468.  
  3469.  Contributors - EDM/2 - May 1995 - Volume 3, Issue 5 
  3470.  
  3471.  
  3472. ΓòÉΓòÉΓòÉ 11. How Do I Get EDM/2? ΓòÉΓòÉΓòÉ
  3473.  
  3474. How Do I Get EDM/2? 
  3475.  
  3476. EDM/2 can be obtained in any of the following ways: 
  3477.  
  3478. On the Internet 
  3479.  
  3480.      All back issues are available via anonymous FTP from the following sites: 
  3481.         -  hobbes.nmsu.edu in the /os2/newsltr directory. 
  3482.         -  ftp.luth.se in the /pub/os2/programming/newsletter directory. 
  3483.         -  generalhq.pc.cc.cmu.edu in the /pub/newsletters/edm2 directory. 
  3484.      The EDM/2 mailing list.  Send an empty message to edm2-info@knex.mind.org 
  3485.       to receive a file containing (among other things) instructions for 
  3486.       subscribing to EDM/2.  This is a UUCP connection, so be patient please. 
  3487.      IBM's external gopher/WWW server in Almaden. The address is 
  3488.       index.almaden.ibm.com and it is in the "Non-IBM-Originated" submenu of 
  3489.       the "OS/2 Information" menu; the URL is 
  3490.       "gopher://index.almaden.ibm.com/1nonibm/os2nonib.70". 
  3491.  
  3492.  On Compuserve 
  3493.  
  3494.  All back issues are available in the OS/2 Developers Forum 2. 
  3495.  
  3496.  IBM Internal 
  3497.  
  3498.      IBM's internal gopher/WWW server in Almaden. The address is 
  3499.       n6tfx.almaden.ibm.com and it is in the "Non-IBM-Originated Files" menu; 
  3500.       the URL is "gopher://n6tfx.almaden.ibm.com/1!!nonibm/nonibm.70". 
  3501.      IBM's REQUEST command on all internal VM systems.  Enter the VM command 
  3502.       REQUEST LIST FROM ASSELIN AT RALVM12 and a list of the requestable 
  3503.       packages will be sent to you; in this list are the names of the packages 
  3504.       containing the EDM/2 issues. 
  3505.  
  3506.  How do I Get EDM/2? - EDM/2 - May 1995 - Volume 3, Issue 5