home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 32 Periodic / 32-Periodic.zip / edmi2-5.zip / EDMI2-5.INF (.txt) < prev    next >
OS/2 Help File  |  1994-05-09  |  204KB  |  2,219 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. May 1994 Title Page ΓòÉΓòÉΓòÉ
  3.  
  4.           Welcome to EDM/2 - The Electronic OS/2 Developer's Magazine!
  5.                    Portions copyright (c) by Larry Salomon Jr.
  6.                                 Volume 2, issue 5
  7.  
  8. Copyright Notice and Other Stuff 
  9.  
  10. The Editor-in-Chief of this electronic magazine is Larry Salomon, Jr. 
  11.  
  12. Portions of EDM/2 are copyrighted by the editors.  This publication may be 
  13. freely distributed in electronic form provided that all parts are present in 
  14. their original unmodified form.  A reasonable fee may be charged for the 
  15. physical act of distribution; no fee may be charged for the publication itself. 
  16.  
  17. All articles are copyrighted by their authors. No part of any article may be 
  18. reproduced without permission from the original author. 
  19.  
  20. Neither this publication nor the editors are affiliated with International 
  21. Business Machines Corporation. 
  22.  
  23. OS/2 is a registered trademark of International Business Machines Corporation. 
  24. Other trademarks are property of their respective owners.  Any mention of a 
  25. product in this publication does not constitute an endorsement or affiliation 
  26. unless specifically stated in the text. 
  27.  
  28. Administrivia 
  29.  
  30. Ah!  I've been running around like a madman the past two weeks.  So much has 
  31. happened that needs to be told that I doubt I will remember to tell it all. 
  32. First, the IBM PSP Technical Interchange in San Francisco (yes, I finally 
  33. spelled it correctly) was amazing.  I was fortunate enough to meet so many 
  34. people, and many of the people I met told me they knew of, if not read 
  35. themselves, EDM/2.  Of the many I met, I have to say that the best meets were 
  36. with Kathleen Panov (just because I coauthored a book with her doesn't mean 
  37. I've met her!), Tim Sipples, and Dave Whittle. 
  38.  
  39. The sessions themselves were chocked full of useful information.  Myself, I got 
  40. the most from Sheila Harnett's WPS Programming, and I hope to apply that to my 
  41. current work projects (and eventually write an article for EDM/2).  There was a 
  42. Meet the Editors session where the editors of OS/2 Developer, OS/2 Magazine, 
  43. and OS/2 Professional talked a lot and answered questions; of course, yours 
  44. truly jumped in the conversation whenever possible to plug the magazine. 
  45. Throughout the week, I managed to distribute close to 100 flyers to people who 
  46. asked for one about the magazine, so if any of you are out there, welcome 
  47. aboard! 
  48.  
  49. New Conquest Achieved 
  50.  
  51. Also, I had the pleasure of meeting Janet Gobielle who graciously volunteered 
  52. to distribute EDM/2 on FidoNet.  Onward to plunder and burn!  <grin> 
  53.  
  54. Things Desired 
  55.  
  56. Recently in the comp.os.os2.programmer.misc newsgroup, a few people griped 
  57. about the need for sprite support.  So, starting with this issue, there will be 
  58. a multi-part series on a completely modular, multithread-enabled library that 
  59. supports sprite of up to 128x128 pels in size.  The library is already written 
  60. and even incorporated into a new version of Common/2 - soon to be released on 
  61. hobbes - so don't worry about this becoming an undoable project.  <grin> 
  62.  
  63. Credit Deserved 
  64.  
  65. Since Carsten has been proofing the magazine since volume 2, issue 3 (although 
  66. I lost his changes for the last issue), I've decided it's time to start giving 
  67. him credit for his extra work beyond the call of duty; so, Carsten is now 
  68. officially the/an Associate Editor of the magazine. Congratulations on a job 
  69. well done! 
  70.  
  71. More From the Credit Department 
  72.  
  73. David Charlap, in his endless pursuit to open problem reports against OS/2 
  74. <grin> has notified me that APAR number PJ13781 has been created for the 
  75. problem of the Palette Manager samples (in volume 1, issue 1 of EDM/2) causing 
  76. PM to become unstable.  Thanks, David! 
  77.  
  78.  
  79. ΓòÉΓòÉΓòÉ 2. Features for May 1994 ΓòÉΓòÉΓòÉ
  80.  
  81. The following articles constitute this issue's features: 
  82.  
  83. o Sprites and Animation - Part 1 
  84. o Using SYSLEVEL Files in Your Applications 
  85.  
  86.  
  87. ΓòÉΓòÉΓòÉ 2.1. Sprites and Animation - Part 1 ΓòÉΓòÉΓòÉ
  88.  
  89.  
  90. ΓòÉΓòÉΓòÉ 2.1.1. Introduction ΓòÉΓòÉΓòÉ
  91.  
  92. Written by Larry Salomon, Jr. 
  93.  
  94. Introduction 
  95.  
  96. Some time ago, I posted an article to comp.os.os2.programmer.misc describing 
  97. how a friend and I wrote an animated demo application using home-grown sprite 
  98. routines.  As I stated then, the routines were very tightly integrated into the 
  99. application; thus, they were not suitable for general availability.  I received 
  100. a few requests to "clean them up" and since animation had been in the Want Ads 
  101. for some time, I decided to design and implement a sprite library. The result 
  102. is presented in i495.zip.  This is a demonstration program that uses the sprite 
  103. library to simulate the Long Island Expressway on my trip to and from work.  :) 
  104.  
  105. This multipart series will go through the design and implementation of the 
  106. sprite library; additionally, its uses for animation will be briefly touched 
  107. upon.  The reader is expected to be competent in PM application development as 
  108. well as have at least introductory knowledge to the Gpi subsystem.  Any 
  109. background knowledge on animation techniques will be very helpful also. 
  110.  
  111. A caveat:  I intentionally left out the source code for the sprite library from 
  112. part 1 so that no one who doesn't already know this stuff will make any 
  113. incorrect assumptions about how the code works; the source will be included in 
  114. later parts of this series.  In the meantime, you can enjoy using the SPRITE.H 
  115. and SPRITE.LIB files.  :) The library was compiled using IBM C-Set++, so it is 
  116. a 32-bit library.  It was not compiled for multithreaded applications, nor was 
  117. z-ordering implemented.  By next month, I will have released a new version of 
  118. Common/2 (available at your nearest hobbes shadow) containing the sprite 
  119. subsystem and corresponding programming reference; unlike the remainder of the 
  120. library, however, I will make the source for this component available so do not 
  121. think that the usefulness of the series will be diminished. 
  122.  
  123. Another caveat:  the library was developed on my SVGA system at work; when 
  124. showing it to some fellow colleagues at the IBM PSP Technical Interchange on an 
  125. XGA system, the transparancy was - shall we say - overdone.  A quick chat with 
  126. Kelvin Lawrence yielded nothing other than the SVGA drivers do not work 
  127. properly all of the time.  I guess I broke the library so that it would work on 
  128. my SVGA screen.  :) 
  129.  
  130.  
  131. ΓòÉΓòÉΓòÉ 2.1.2. Background ΓòÉΓòÉΓòÉ
  132.  
  133. Background 
  134.  
  135. What is a sprite?  The term dates at least as far back as the VIC-20 and refers 
  136. to a graphical object that is animated in some form or another; for performance 
  137. reasons, these sprites were typically bitmapped graphics.  Since animation 
  138. often depicts everyday objects, and these objects have arbitrary (i.e. 
  139. non-rectangular) shapes, bitmaps - in the Gpi sense - cannot be used alone to 
  140. represent a sprite because they overpaint what is underneath.  This wouldn't be 
  141. a problem normally except that bitmaps must be rectangular in shape. 
  142.  
  143. Presentation Manager defines a resource called a pointer (for this discussion, 
  144. we will lump icons in this category since the only difference between the two 
  145. is the first two bytes in the file defining the pointer or icon), which has an 
  146. color which is transparent, i.e. the areas painted by this "color" show what 
  147. was underneath instead.  Unfortunately for us, the size of the pointer is fixed 
  148. (its size can be determined using the WinQuerySysValue() function), making it 
  149. unsuitable for most animation (assuming we stick to documented functions for 
  150. drawing the pointer).  If we were able to create a transparent "color" for our 
  151. bitmaps, we could have irregular shapes surrounded by transparency to make the 
  152. shape "rectangular".  This is, then, our immediate goal; there are other 
  153. functions which will also be needed, but without the ability to draw a sprite 
  154. the remainder of the library is rather useless. 
  155.  
  156. Let us begin by looking at the design of the library as well as the decisions 
  157. that were made and how they affect the implementation.  My original intent for 
  158. the library was to have four functions: 
  159.  
  160. o Create a sprite from a bitmap 
  161. o Destroy a sprite 
  162. o Draw a sprite 
  163. o Move a sprite 
  164.  
  165. We must first explain the third for - speaking in hindsight - the 
  166. implementation of the drawing will affect the method of creation. 
  167.  
  168.  
  169. ΓòÉΓòÉΓòÉ 2.1.3. Blast From the Past ΓòÉΓòÉΓòÉ
  170.  
  171. Blast From the Past 
  172.  
  173. I must confess that I learned the technique for drawing a sprite from Charles 
  174. Petzold's article series in the Microsoft Systems Journal where he developed a 
  175. game of checkers for OS/2.  The checker pieces are irregular so he described 
  176. how to draw them and keep the underlying image intact where the piece was not 
  177. drawn.  How is it done?  Well, if you'll think back to the days of boolean 
  178. logic, you'll remember that the AND and OR functions have the following 
  179. properties: 
  180.  
  181. x AND 1 = x 
  182. x OR 0 = x 
  183.  
  184. If we require that all regions in the original bitmap that are to be 
  185. transparent must have the color black, we can use the OR function with the 
  186. target being x to implement the transparent portions.  If we only do this, 
  187. however, the non-transparent portions of the bitmap will get OR'd with whatever 
  188. was underneath. Somehow, we need to insure that all portions on the target 
  189. where the original bitmap is not transparent are turned to black, so the OR 
  190. function will not alter the bitmap in any way. 
  191.  
  192. Phantom of the Opera 
  193.  
  194. To accomplish this, we need a second bitmap.  Called a mask, it is a monochrome 
  195. bitmap which we combine with the target to change the portions of the target to 
  196. black as stated in the last paragraph.  This is accomplished by making the 
  197. portions of the mask corresponding to the transparent areas white, and the 
  198. non-transparent areas black, and then AND'ing this mask with the target. 
  199.  
  200. I realize this is quite confusing, so let's present an example of what is being 
  201. said.  To the left is the original bitmap; to the right is the mask. Both are 
  202. surrounded by a light gray rectangle only for illustrative purposes. 
  203.  
  204. We will paint the original bitmap on the following background, using black as 
  205. the transparency color, as described above. 
  206.  
  207. First, we need to mask out the areas of the target where the image will be 
  208. painted.  This is done using GpiBitBlt() with the ROP_SRCAND operation, and it 
  209. yields the following: 
  210.  
  211. Finally, we paint the original bitmap on top of this using the ROP_SRCPAINT 
  212. operation (the equivalent of the OR function), yielding the following: 
  213.  
  214.  
  215. ΓòÉΓòÉΓòÉ 2.1.4. The Four Revisited ΓòÉΓòÉΓòÉ
  216.  
  217. The Four Revisited 
  218.  
  219. To implement the create sprite from bitmap function, we need to also create a 
  220. mask which is associated with the bitmap.  The application programmer should 
  221. not have to manage this and insure the proper mask is used with the 
  222. corresponding bitmap, etc., so the sprite data structure should keep track of 
  223. both. 
  224.  
  225. When you look at the code, you'll think that it is rather trivial. However, 
  226. actually developing the code to its present state was a bit of work. Of course, 
  227. we have to have a memory device context and associated presentation space. 
  228. And, since we stated that the mask is a monochrome bitmap, we can call 
  229. GpiQueryBitmapInfoHeader() to get information about the original image, set 
  230. cPlanes and cBitCount to 1 and call GpiCreateBitmap() to create the bitmap. 
  231. This is then set into the presentation space. 
  232.  
  233. Now comes the tricky part.  How do you tell the GpiBitBlt() function to make 
  234. all black portions white and all non-black portions black? To quote an 
  235. extremely old piece of IBM documentation, the Programming Guide (page 24-7) 
  236. from the OS/2 1.2 Programmer's Toolkit: 
  237.  
  238. o If you are copying a color bit map to a monochrome bit map or device, those 
  239.   pels that have the same color as the current image-background color in the 
  240.   source presentation space adopt the image background color of the target 
  241.   presentation space.  So, for example, if your current image background color 
  242.   in the source presentation space is blue, all blue pels in the bit map take 
  243.   on the color of the current image background in the target presentation 
  244.   space. 
  245.  
  246.   All other pels in the color bit map adopt the current image-foreground color 
  247.   of the target presentation space. 
  248.  
  249. Unfortunately, I decided to use GpiWCBitBlt() instead of GpiBitBlt() for the 
  250. mask creation.  Since there is no source presentation space it is difficult to 
  251. determine what will happen given the above text.  I could not determine what 
  252. the rule is for GpiWCBitBlt() (since what I observed makes no sense), so either 
  253. the text is wrong, I am just being stupid, or we are seeing the broken SVGA 
  254. drivers in action. :)  By trial-and-error I figured out that, in order to 
  255. create the mask, we call GpiSetColor(CLR_WHITE) and GpiSetBackColor(CLR_BLACK) 
  256. and then call GpiWCBitBlt() to actually initialize the mask bitmap. 
  257.  
  258. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  259.  
  260. Sprite destruction should be fairly trivial, and we have already discussed how 
  261. the sprites are drawn, so let's look at how they are moved. 
  262.  
  263. The Quest to Avoid Flicker 
  264.  
  265. When a sprite is moved, there are two scenarios to consider: 
  266.  
  267.  1. The bounding rectangle of the sprite at the old and new positions do not 
  268.     overlap 
  269.  2. The bounding rectangle of the sprite at the old and new positions overlap 
  270.  
  271. The first case is trivial to implement - you paint the background over the old 
  272. position, and redraw in the new position.  The second case, however, is not so 
  273. simple; if we treated the second case as the first, there is a noticeable 
  274. flicker in the regions that overlap.  To avoid this, we need to insure that we 
  275. call GpiBitBlt() only once.  This is accomplished using a work-area which is 
  276. another bitmap set in a presentation space associated with a memory device 
  277. context.  The strategy is thus: 
  278.  
  279.  1. Determine the rectangle that bounds the bounding rectangles of the sprite 
  280.     at the old and new positions. 
  281.  2. Copy the background from the rectangle calculated in step 1 into the work 
  282.     area. 
  283.  3. Draw the sprite at the new position, relative to the old position. 
  284.  4. Copy the contents of the work area to the screen presentation space. 
  285.  
  286. Step 4 has the visible effect of both erasing the sprite at the old position 
  287. and redrawing it in the new position.  This is a hybrid form of 
  288. double-buffering, which is defined to be the procedure by which the next 
  289. "frame" in a sequence is prepared off-screen while the first screen is being 
  290. displayed.  The prepared screen is then displayed while the next frame is 
  291. prepared, and so on.  The effect produced is much smoother than if the frames 
  292. were prepared on-screen, as you can imagine. 
  293.  
  294. Note that the algorithm we used is only good when the overlapping is present. 
  295. Attempting to use this when there is no overlap could result is severely 
  296. degraded performance when you consider that the distance between the old and 
  297. new position could be quite a lot, making the area blit'd to the screen quite 
  298. large and CPU intensive in execution. 
  299.  
  300.  
  301. ΓòÉΓòÉΓòÉ 2.1.5. Summary ΓòÉΓòÉΓòÉ
  302.  
  303. Summary 
  304.  
  305. In the last section, you probably noticed a few loose ends, namely the concept 
  306. of a background and the management of the work area used when moving the sprite 
  307. from one position to another.  Next month, we'll tie up these loose ends with 
  308. the introduction of the playground; we will also start to look at the 
  309. implementation of i495.exe followed by the code for the library itself. 
  310.  
  311.  
  312. ΓòÉΓòÉΓòÉ 2.2. Using SYSLEVEL Files in Your Applications ΓòÉΓòÉΓòÉ
  313.  
  314.  
  315. ΓòÉΓòÉΓòÉ 2.2.1. Introduction ΓòÉΓòÉΓòÉ
  316.  
  317. Written by Martin Lafaix 
  318.  
  319. Introduction 
  320.  
  321. What's that? 
  322.  
  323. Determining a computer software configuration has always been a tricky process. 
  324. It would be great to have a standard way for registering applications, so that 
  325. we could easily query the system configuration.  But wait a minute!  OS/2 
  326. provides the SYSLEVEL command, which does just that (it even tells us the 
  327. various component versions)!  If only we could use it for our own purposes... 
  328.  
  329. Why? 
  330.  
  331. This registering ability proves its usefulness when writing (relatively) large 
  332. projects or components.  For example, if you write a public toolkit or tools 
  333. other programs may use, it would be a good idea to register them. (OS/2 already 
  334. uses it this way:  on my home system, the syslevel command tells me that MMPM/2 
  335. and the Developer's toolkit are present - the same thing occurs if you have 
  336. Communication Manager, etc.)  When distributing such a tool, tell your users 
  337. your component name and ID; it would then be easy for them to write an 
  338. installation procedure which checks your component presence. 
  339.  
  340. Another interest is that it helps component writers in creating CSD or 
  341. component updates.  As each SYSLEVEL file maintains a current CSD level as well 
  342. as a previous CSD level field, it's easy to check what to update, and what to 
  343. leave alone. 
  344.  
  345. It's also useful while maintaining a computer network.  It would provide the 
  346. maintainer an up-to-date information database. 
  347.  
  348. Contents 
  349.  
  350. This article contains two parts.  The first one describes the SYSLEVEL file 
  351. format.  The second part describes the two proposed APIs (one for C, and one 
  352. for Rexx). 
  353.  
  354.  
  355. ΓòÉΓòÉΓòÉ 2.2.2. A Voyage to Syslevel ΓòÉΓòÉΓòÉ
  356.  
  357. A Voyage to Syslevel 
  358.  
  359. When you start SYSLEVEL.EXE, it scans all your drives for SYSLEVEL files. 
  360. These files are named SYSLEVEL.xxx (where xxx is any three-letters extension), 
  361. and have a specific header. When one such file is found, it is displayed, as 
  362. shown in figure 1. So, to be able to use SYSLEVEL for our own purpose, we'll 
  363. have to decrypt SYSLEVELs' file headers, and find out how (and where) to store 
  364. our own data. 
  365.  
  366. C:\MMOS2\INSTALL\SYSLEVEL.MPM
  367.                              Multimedia Presentation Manager 2
  368. Extensions syst╨Üme 1.10     ID de composant 562137400
  369. Type MMPM\2
  370. Niveau de modifications en cours : UN00000
  371. Niveau de modifications ant╨Ærieur : UN00000
  372.  
  373. Figure 1.  Syslevel output sample (French version, sorry :-) ) 
  374.  
  375. On the File Header 
  376.  
  377. A SYSLEVEL file header looks like the following: 
  378.  
  379. typedef struct _SYSLEVELHEADER {
  380.    unsigned char h_magic[2];
  381.    unsigned char h_name[9];
  382.    unsigned char h_reserved1[4];
  383.    unsigned char h_updated;
  384.    unsigned char h_reserved2[17];
  385.    ULONG         h_data;
  386. } SYSLEVELHEADER;
  387.  
  388. Figure 2.  The SYSLEVELHEADER structure. 
  389.  
  390. h_magic             is the magic cookie.  Its value is 0xFFFF. 
  391.  
  392. h_name              is the string "SYSLEVEL", in uppercase and null-terminated. 
  393.  
  394. h_reserved1         meaning unknown.  Set to zero. 
  395.  
  396. h_updated           was 1 for OS2, GRE and MPM, and 0 for TLK.  My guess: set 
  397.                     it to zero. 
  398.  
  399. h_reserved2         meaning unknown.  Set to zero. 
  400.  
  401. h_data              points to the beginning of the file's data structure 
  402.                     (offset from the beginning of the file), which is described 
  403.                     below. 
  404.  
  405. While I realize there's still many holes in there, it appears to fulfill our 
  406. needs; namely, we are now able to create files recognized by SYSLEVEL.EXE. 
  407. Isn't that great? 
  408.  
  409. But it's time to learn more... 
  410.  
  411. The SYSLEVEL Data Structure 
  412.  
  413. In the previous section, we have seen that the file's data structure starts at 
  414. offset h_data.  This structure (aka. the SYSLEVEL data structure) looks like 
  415. the following: 
  416.  
  417. typedef struct _SYSLEVELDATA {
  418.    unsigned char d_reserved1[2];
  419.    unsigned char d_kind;
  420.    unsigned char d_version[2];
  421.    unsigned char d_reserved2[2];
  422.    unsigned char d_clevel[7];
  423.    unsigned char d_reserved3;
  424.    unsigned char d_plevel[7];
  425.    unsigned char d_reserved4;
  426.    unsigned char d_title[80];
  427.    unsigned char d_cid[9];
  428.    unsigned char d_revision;
  429.    unsigned char d_type[1];
  430. } SYSLEVELDATA;
  431.  
  432. Figure 3.  The SYSLEVELDATA structure. 
  433.  
  434. d_reserved1         set to zero... 
  435.  
  436. d_kind              specifies the component "kind".  It can be any of the 
  437.                     following: 
  438.  
  439.    SLK_BASE (0)             "Base version" 
  440.    SLK_EXTENSION (2)        "System extension" 
  441.    SLK_STANDARD (15)        Neither "Base version" nor "System extension"... 
  442.                             :-) 
  443.  
  444.    Any other value is equivalent to SLK_STANDARD (except 1, which is equivalent 
  445.    to SLK_EXTENSION). 
  446.  
  447. d_version           specifies the component version.  Its format is a bit 
  448.                     strange:  the four high-order bits of d_version[0] contains 
  449.                     the major version number, the four low-order bits contains 
  450.                     the first minor version digit, and d_version[1] contains 
  451.                     the second minor version digit. 
  452.  
  453.                     For example, if d_version[0] is 0x21 and d_version[1] is 
  454.                     0x02, you will get "2.12". 
  455.  
  456.                     [You can have a revision level, as in "2.12.a".  See 
  457.                     d_revision below.] 
  458.  
  459. d_reserved2         oh no, not again.  Set to zero. 
  460.  
  461. d_clevel            specifies the current CSD level.  It's a seven-byte string, 
  462.                     usually in the form "AAC####", where AA is a two-byte 
  463.                     string, C a country-dependent code, and #### a number.  For 
  464.                     example, on my home computer, I get "XRF2010" for the base 
  465.                     operating system (It's the French version), and "XR02100" 
  466.                     for the developer's toolkit (US version, this time). 
  467.  
  468.                     It's just a suggested usage and is not enforced in any way. 
  469.                     As long as you use seven printable characters, it should 
  470.                     work. 
  471.  
  472. d_reserved3         guess what?  You lose!  Set to 0x5F this time. 
  473.  
  474. d_plevel            specifies the previous CSD level.  If there was no previous 
  475.                     level; set it equal to the current level, d_clevel. 
  476.  
  477. d_reserved4         is just like d_reserved3; set to 0x5F 
  478.  
  479. d_title             specifies the component name.  It's a null-terminated 
  480.                     string. 
  481.  
  482. d_cid               specifies the component ID.  It's not null-terminated. 
  483.  
  484. d_revision          specifies the component revision.  It does not appear in 
  485.                     the version field if sets to zero.  If it's not null, it 
  486.                     will be concatenated with major and minor version number, 
  487.                     as in "1.2.3" (where 1 is the major version, 2 the minor 
  488.                     and 3 the revision).  If you prefer a letter in place of a 
  489.                     digit, just increment the revision number by 0x10 for an 
  490.                     upper-case letter, or by 0x30 for a lower-case.  That is, 
  491.                     if d_revision is 0x11, you will get an "A", and so on. 
  492.  
  493. d_type              specifies the component type.  It's an optional, 
  494.                     null-terminated string. This field allows you to store 
  495.                     additional informations for your component. For example, 
  496.                     this field is used to differentiate the blue and salmon 
  497.                     distribution of OS/2 (a type of '0-2' indicates the 
  498.                     'salmon' one). 
  499.  
  500. Well, enough said on this exploration.  It's time to go back to much safer 
  501. places... 
  502.  
  503.  
  504. ΓòÉΓòÉΓòÉ 2.2.3. Home, Sweet Home ΓòÉΓòÉΓòÉ
  505.  
  506. Home, Sweet Home 
  507.  
  508. This walk was fun, but all good things must come to an end.  So we are back. 
  509. And it's time to write some functions to comfort our precious new knowledge, 
  510. isn't it? 
  511.  
  512. Two APIs are available, a C one and a REXX one. 
  513.  
  514. The SYSLEVEL C API 
  515.  
  516. This section describes the API which provides access to the syslevel files. The 
  517. corresponding code is in CLEVEL.ZIP.  It's just an include file, level.h and a 
  518. small C file, level.c which can be included, say, in your favorite library.  It 
  519. has been tested with GCC/2, but it should work with any other C compiler... 
  520.  
  521. APIRET LvlOpenLevelFile(PSZ pszName, PHFILE phFile, ULONG ulOpenMode, PSZ 
  522. pszCID) 
  523. APIRET LvlCloseLevelFile(HFILE hFile) 
  524. APIRET LvlQueryLevelFile (PSZ pszName, PSZ pszCID, PVOID pBuffer, ULONG 
  525. ulBufSize) 
  526. APIRET LvlQueryLevelData(HFILE hFile, ULONG ulWhat, PVOID pBuffer, ULONG 
  527. ulBufSize, PULONG pulSize) 
  528. APIRET LvlWriteLevelData(HFILE hFile, ULONG ulWhat, PVOID pBuffer, ULONG 
  529. ulBufSize, PULONG pulSize) 
  530.  
  531. Design considerations 
  532.  
  533. This API has been modeled upon the profile (Prf) functions. 
  534.  
  535. Examples 
  536.  
  537. The following two figures show how to check for the existence of a component, 
  538. and if a component needs updating, respectively. 
  539.  
  540. :
  541. #include <level.h>
  542. :
  543. int main()
  544. {
  545.   HFILE hFile;
  546.   :
  547.   if(hFile = LvlOpenLevelFile("DBM",
  548.                               OLF_SCANDISKS | OLF_CHECKID,
  549.                               "123456789"))
  550.     /* present */
  551.     :
  552.   else
  553.     /* not present */
  554.     :
  555.   :
  556.   LvlCloseLevelFile(hFile);
  557.   :
  558. }
  559.  
  560. Figure 4.  Syslevel API usage sample - Checking for the existence of a 
  561. component 
  562.  
  563. :
  564. #include <level.h>
  565. :
  566. BOOL _needUpdate(HFILE hFile)
  567. {
  568.   CHAR achCSD[7];
  569.   ULONG ulCount;
  570.  
  571.   if(LvlQueryLevelData(hFile, QLD_CURRENTCSD, achCSD, 7, &ulCount))
  572.     /* shall we update it? */
  573.     return strncmp(achCSD, "DBF0099",7) <= 0; /* for example */
  574.   else
  575.     /* an error occurred */
  576.     :
  577. }
  578. :
  579.  
  580. Figure 5.  Syslevel API usage sample - Shall we update component? 
  581.  
  582. The SYSLEVEL REXX API 
  583.  
  584. Well, it's not really an API, it's in fact a single function.  The 
  585. corresponding code is in RLEVEL.ZIP.  It's just a REXX file, named REXXLVL.CMD. 
  586. Put it somewhere along your PATH.  The zip file also contains MAKESYSL.CMD, 
  587. which can be used to create SYSLEVEL files. 
  588.  
  589. This function has been modeled upon the STREAM function. 
  590.  
  591. RexxLvl() 
  592.  
  593. Example 
  594.  
  595. The following example is a REXX script.  It allows you to easily create 
  596. syslevel files. 
  597.  
  598. /* makesysl.cmd                                          940327 */
  599.  
  600. say 'Component name:';                  parse pull name
  601. say 'Component ID:';                    parse pull ID
  602. say 'Component type (optional):';       parse pull type
  603. say 'Component version (as x.y[.z]):';  parse pull version
  604. say 'Current CSD Level:';               parse pull CSD
  605. say 'Component extension:';             parse pull ext
  606.  
  607. file = RexxLvl("n", ext, ID)
  608. call RexxLvl "s", file, "n", name
  609. call RexxLvl "s", file, "c", csd
  610. call RexxLvl "s", file, "v", version
  611. call RexxLvl "s", file, "t", type
  612. rc = RexxLvl("c", file)
  613.  
  614. if rc = 0 then say 'SYSLEVEL.'ext' created.'
  615.  
  616. Figure 6.  Creating a syslevel file in REXX. 
  617.  
  618.  
  619. ΓòÉΓòÉΓòÉ 2.2.4. Summary ΓòÉΓòÉΓòÉ
  620.  
  621. Summary 
  622.  
  623. Now you have enough information to use the SYSLEVEL files well.  However, the 
  624. advertised advantages would become a reality only if we use SYSLEVEL files 
  625. extensively.  So, if you like these perspectives, use them, ask them, require 
  626. them, again and again, until you get satisfaction.  :-) 
  627.  
  628. As a sidenote, the information exposed in the first part of this article is the 
  629. result of my own exploration.  If you find any inaccuracy or if you have more 
  630. information, please, let me know. 
  631.  
  632.  
  633. ΓòÉΓòÉΓòÉ <hidden> kind ΓòÉΓòÉΓòÉ
  634.  
  635. SLK_BASE                 denotes a "base" component. 
  636. SLK_EXTENSION            denotes a system extension. 
  637. SLK_STANDARD             denotes a "standard" component.  It's the suggested 
  638.                          component kind value. 
  639.  
  640.  
  641. ΓòÉΓòÉΓòÉ <hidden> ulOpenMode - input ΓòÉΓòÉΓòÉ
  642.  
  643. ULONG field that describes the mode of the open function. 
  644.  
  645. OLF_OPEN                 open the specified file.  The default behavior is to 
  646.                          scan the current disk, starting from the current 
  647.                          directory.  It returns the first SYSLEVEL file whose 
  648.                          extension matches pszName  You can override this by 
  649.                          combining OLF_OPEN with OLF_SCANDISK or OLF_CHECKID. 
  650. OLF_SCANDISKS            scans all disks (starting from C:).  Use this flag to 
  651.                          modify the default OLF_OPEN behavior. 
  652. OLF_CHECKID              finds file(s) whose ID matches the specified one.  Use 
  653.                          this flag to override the default OLF_OPEN behavior. 
  654. OLF_CREATE               creates the specified file in the current directory. 
  655.                          A valid pszName and ID should be provided. 
  656.  
  657.  
  658. ΓòÉΓòÉΓòÉ <hidden> ulWhat - input ΓòÉΓòÉΓòÉ
  659.  
  660. The following flags can be used when querying (or writing) a SYSLEVEL file. 
  661.  
  662. QLD_MAJORVERSION         Query (or update) the major version field.  It's a 
  663.                          one-character field. It should be in the range 
  664.                          '0'-'9'.  The value is placed in (or taken from) the 
  665.                          first character of pBuffer.  (Buffer size should be at 
  666.                          least 1.) 
  667.  
  668. QLD_MINORVERSION         Query (or update) the minor version field.  It's a 
  669.                          two-character field. It should be in range '00'-'99'. 
  670.                          The value is placed in (or taken from) the first two 
  671.                          chars of pBuffer.  (Buffer size should be at least 2.) 
  672.  
  673. QLD_REVISION             Query (or update) the revision field.  It's should fit 
  674.                          in a character.  If it's '0', there's no revision 
  675.                          available.  It can be a letter as well as a digit. 
  676.                          The value is placed in (or taken from) the first 
  677.                          character of pBuffer.  (Buffer size should be at least 
  678.                          1.) 
  679.  
  680. QLD_KIND                 Query (or update) the kind field.  The value is placed 
  681.                          in (or taken from) the first character of *pBuffer. 
  682.                          (Buffer size should be at least 1.) 
  683.  
  684. QLD_CURRENTCSD           Query (or update) the current CSD level (when you 
  685.                          update this field, its old value is copied to the old 
  686.                          CSD level field).  It's a seven-character field, and 
  687.                          it does not have to be null-terminated.  The value is 
  688.                          placed in (or taken from) the first seven characters 
  689.                          of pBuffer.  (Buffer size should be at least 7.) 
  690.  
  691. QLD_PREVIOUSCSD          Query the previous CSD level.  You can't update this 
  692.                          field.  The value is placed in the first seven chars 
  693.                          of pBuffer.  (Buffer size should be at least 7.) 
  694.  
  695.                          Note:  CSD levels are not null-terminated.  Be careful 
  696.                          when using such a returned value. 
  697.  
  698. QLD_TITLE                Query (or update) the component title field.  It's an 
  699.                          eighty-character string (required ending null 
  700.                          included).  The value is placed in (or taken from) the 
  701.                          first eighty characters of pBuffer.  On input, the 
  702.                          buffer size should be at least 80.  On output, the 
  703.                          buffer size can exceed 80, but the written string is 
  704.                          truncated (and null-terminated) to eighty characters. 
  705.  
  706. QLD_ID                   Query (or update) the component ID field.  It's a 
  707.                          nine-character field. It does not have to be 
  708.                          null-terminated.  The value is placed in (or taken 
  709.                          from) the first nine characters of pBuffer.  (Buffer 
  710.                          size should be at least 9.) 
  711.  
  712.                          Note:  IDs are not null-terminated.  Be careful when 
  713.                          using such a returned value. 
  714.  
  715. QLD_TYPE                 Query (or update) the component type field. 
  716.  
  717.  
  718. ΓòÉΓòÉΓòÉ <hidden> LvlOpenLevelFile ΓòÉΓòÉΓòÉ
  719.  
  720. APIRET LvlOpenLevelFile(PSZ pszName, PHFILE phFile, ULONG ulOpenMode, PSZ 
  721. pszCID) 
  722.  
  723. Use this to find, open or create a SYSLEVEL file. 
  724.  
  725. It returns the following values: 
  726.  
  727. 0         NO_ERROR 
  728. 2         ERROR_FILE_NOT_FOUND 
  729. 3         ERROR_PATH_NOT_FOUND 
  730. 4         ERROR_TOO_MANY_OPEN_FILES 
  731. 5         ERROR_ACCESS_DENIED 
  732. 12        ERROR_INVALID_ACCESS 
  733. 26        ERROR_NOT_DOS_DISK 
  734. 32        ERROR_SHARING_VIOLATION 
  735. 36        ERROR_SHARING_BUFFER_EXCEEDED 
  736. 82        ERROR_CANNOT_MAKE 
  737. 87        ERROR_INVALID_PARAMETER 
  738. 99        ERROR_DEVICE_IN_USE 
  739. 108       ERROR_DRIVE_LOCKED 
  740. 110       ERROR_OPEN_FAILED 
  741. 112       ERROR_DISK_FULL 
  742. 206       ERROR_FILENAME_EXCEED_RANGE 
  743. 231       ERROR_PIPE_BUSY 
  744.  
  745.  
  746. ΓòÉΓòÉΓòÉ <hidden> pszName - input ΓòÉΓòÉΓòÉ
  747.  
  748. The syslevel file extension.  It's a three-letter, null-terminated string. That 
  749. is, LvlOpenLevelFile deals with syslevel files named syslevel.xxx, where xxx 
  750. is pszName's value. 
  751.  
  752.  
  753. ΓòÉΓòÉΓòÉ <hidden> LvlCloseLevelFile ΓòÉΓòÉΓòÉ
  754.  
  755. APIRET LvlCloseLevelFile(HFILE hFile) 
  756.  
  757. Use this to close a SYSLEVEL file.  It's just a DosClose alias, for API 
  758. consistence. 
  759.  
  760. It returns the following values: 
  761.  
  762. 0         NO_ERROR 
  763. 2         ERROR_FILE_NOT_FOUND 
  764. 5         ERROR_ACCESS_DENIED 
  765. 6         ERROR_INVALID_HANDLE 
  766.  
  767.  
  768. ΓòÉΓòÉΓòÉ <hidden> LvlQueryLevelData ΓòÉΓòÉΓòÉ
  769.  
  770. APIRET LvlQueryLevelData(HFILE hFile, ULONG ulWhat, PVOID pBuffer, ULONG 
  771. ulBufSize, PULONG pulSize) 
  772.  
  773. Use this to query an already opened SYSLEVEL file. 
  774.  
  775. It returns the following values: 
  776.  
  777. 0         NO_ERROR 
  778. 6         ERROR_INVALID_HANDLE 
  779. 87        ERROR_INVALID_PARAMETER 
  780. 122       ERROR_INSUFFICIENT_BUFFER 
  781.  
  782. When it returns ERROR_INSUFFICIENT_BUFFER, *pulSize contains the minimum 
  783. requested size. 
  784.  
  785.  
  786. ΓòÉΓòÉΓòÉ <hidden> pBuffer - input/output ΓòÉΓòÉΓòÉ
  787.  
  788.  Address of the buffer that contains the data to write/read. 
  789.  
  790.  
  791. ΓòÉΓòÉΓòÉ <hidden> pulSize - output ΓòÉΓòÉΓòÉ
  792.  
  793. Address of the variable to receive the number of bytes actually read or 
  794. written. 
  795.  
  796.  
  797. ΓòÉΓòÉΓòÉ <hidden> LvlWriteLevelData ΓòÉΓòÉΓòÉ
  798.  
  799. APIRET LvlWriteLevelData(HFILE hFile, ULONG ulWhat, PVOID pBuffer, ULONG 
  800. ulBufSize, PULONG pulSize) 
  801.  
  802. Use this to update an already opened SYSLEVEL file. 
  803.  
  804. It returns the following values: 
  805.  
  806. 0         NO_ERROR 
  807. 6         ERROR_INVALID_HANDLE 
  808. 19        ERROR_WRITE_PROTECT 
  809. 29        ERROR_WRITE_FAULT 
  810. 87        ERROR_INVALID_PARAMETER 
  811. 122       ERROR_INSUFFICIENT_BUFFER 
  812.  
  813. When it returns ERROR_INSUFFICIENT_BUFFER, *pulSize contains the minimum 
  814. requested size. 
  815.  
  816.  
  817. ΓòÉΓòÉΓòÉ <hidden> ulBufSize - input ΓòÉΓòÉΓòÉ
  818.  
  819. The length, in bytes, of pBuffer.  This is the number of bytes to be read or 
  820. write. 
  821.  
  822.  
  823. ΓòÉΓòÉΓòÉ <hidden> phFile - output ΓòÉΓòÉΓòÉ
  824.  
  825. Address of the handle for the file. 
  826.  
  827.  
  828. ΓòÉΓòÉΓòÉ <hidden> pszCID - input ΓòÉΓòÉΓòÉ
  829.  
  830. It's the component ID string.  It's required when you specify the OLF_CHECKID 
  831. flag when opening a syslevel flag.  It's a nine-digit string, not 
  832. null-terminated, which uniquely identifies the component in conjunction with 
  833. pszName.  That is, you can have multiple SYSLEVEL files with the same name, but 
  834. you can't have multiple syslevel files with the same name and ID. 
  835.  
  836. If you are not using the OLF_CHECKID flag, set pszCID to NULL. 
  837.  
  838.  
  839. ΓòÉΓòÉΓòÉ <hidden> RexxLvl() ΓòÉΓòÉΓòÉ
  840.  
  841. ΓöÇΓöÇΓöÇRexxLvl(ΓöÇΓö¼ΓöÇC,ΓöÇΓöÇfileΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇ)ΓöÇΓöÇΓöÇ
  842.               Γö£ΓöÇEΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  843.               Γöé          Γö£ΓöÇ,ΓöÇΓöÇextensionΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  844.               Γöé          Γöé              ΓööΓöÇ,ΓöÇidΓöÇΓöñ
  845.               Γöé          ΓööΓöÇ,,ΓöÇΓöÇidΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  846.               Γö£ΓöÇN,ΓöÇΓöÇextension,ΓöÇΓöÇidΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  847.               Γö£ΓöÇO,ΓöÇΓöÇextension,ΓöÇΓöÇidΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  848.               Γö£ΓöÇQ,ΓöÇΓöÇfile,ΓöÇΓöÇfieldΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  849.               ΓööΓöÇS,ΓöÇΓöÇfile,ΓöÇΓöÇfield,ΓöÇΓöÇvalueΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  850.  
  851. RexxLvl returns a string describing the state of, or the result of an operation 
  852. upon, a SYSLEVEL file.  This function is used to request information on the 
  853. state of a SYSLEVEL file, or to carry out some specific operation on the 
  854. SYSLEVEL file. 
  855.  
  856. The first argument can be one of the following strings (of which only the first 
  857. letter is needed) which describes the action to be carried out: 
  858.  
  859. "c[lose]"      closes the specified syslevel file.  File is a filename returned 
  860.                by a previous RexxLvl OPEN or NEW call. 
  861.  
  862. "e[num]"       enumerates the matching SYSLEVEL files.  Extension is (an 
  863.                optional) SYSLEVEL file extension.  Id is (an optional) 
  864.                component ID.  It returns the number of matching files, or 
  865.                'ERROR'.  The corresponding filenames are pushed on the current 
  866.                queue.  Use PULL or PARSE PULL to get them back. 
  867.  
  868. "n[ew]"        creates a new SYSLEVEL file, in the current directory. Extension 
  869.                is the SYSLEVEL file extension, and id is the component ID.  It 
  870.                returns a file name to be used by subsequent RexxLvl calls. 
  871.  
  872. "o[pen]"       opens the specified SYSLEVEL file.  Extension is the SYSLEVEL 
  873.                file extension, and id is the component ID.  It returns a file 
  874.                name to be used by subsequent RexxLvl calls, 'NOTFOUND' if the 
  875.                required file was not found or 'ERROR' if an error occurred 
  876.                while searching. 
  877.  
  878.                Note:  It returns the first matching SYSLEVEL file. 
  879.  
  880. "q[uery]"      queries a SYSLEVEL file field.  File is a filename returned by a 
  881.                previous RexxLvl OPEN or NEW call. Field is the field to be 
  882.                queried.  It can be any of the following (of which only the 
  883.                first letter is needed): 
  884.  
  885.    "n[ame]"       component name.  Its length cannot exceed 79 characters. 
  886.    "i[d]"         component ID. It's a nine-digit string. 
  887.    "k[ind]"       component kind.  It can be 0 (if the component is a base 
  888.                   one), 1 or 2 (if the component is a system extension) or 15 
  889.                   otherwise. 
  890.    "v[ersion]"    component version.  It should follows the 'x.yy[.z]' format. 
  891.    "t[ype]"       component type.  It's a string. 
  892.    "c[csd]"       current CSD level.  It's a seven-byte string. 
  893.    "p[csd]"       previous CSD level.  It's a seven-byte string. 
  894.  
  895.                It returns the field value or 'ERROR'. 
  896.  
  897. "s[et]"        sets the specified SYSLEVEL file field.  File is a filename 
  898.                returned by a previous RexxLvl OPEN or NEW call.  Field is the 
  899.                field to be set.  It can be any of the values taken by the field 
  900.                parameter of the RexxLvl "query" call, except "p[csd]"  (you 
  901.                can't set the "p[csd]" field's value -- it is automatically sets 
  902.                when you update the c[csd] field).  Value is the field's new 
  903.                value.  It returns an empty string, or 'ERROR'. 
  904.  
  905.  
  906. ΓòÉΓòÉΓòÉ <hidden> LvlQueryLevelFile ΓòÉΓòÉΓòÉ
  907.  
  908. APIRET LvlQueryLevelFile(PSZ pszName, PSZ pszCID, PVOID pBuffer, ULONG 
  909. ulBufSize) 
  910.  
  911. Use this to query/find existing SYSLEVEL files.  This function enumerates all 
  912. the SYSLEVEL files present in the system and returns the names as a list in the 
  913. pBuffer parameter.  Each SYSLEVEL file name is terminated with a NULL character 
  914. and the last name is terminated with two successive NULL characters. 
  915. Specifying pszName or pszCID (or both) restricts the enumeration to the 
  916. corresponding SYSLEVEL files. 
  917.  
  918. It returns the following values: 
  919.  
  920. 0         NO_ERROR 
  921. 87        ERROR_INVALID_PARAMETER 
  922. 122       ERROR_INSUFFICIENT_BUFFER 
  923.  
  924. When it returns ERROR_INSUFFICIENT_BUFFER, the first ulBufSize bytes of pBuffer 
  925. are correctly filled. 
  926.  
  927.  
  928. ΓòÉΓòÉΓòÉ 3. Columns ΓòÉΓòÉΓòÉ
  929.  
  930. The following columns can be found in this issue: 
  931.  
  932. o /dev/EDM/BookReview 
  933. o C++ Corner 
  934. o Introduction to PM Programming 
  935. o Scratch Patch 
  936.  
  937.  
  938. ΓòÉΓòÉΓòÉ 3.1. /dev/EDM/BookReview ΓòÉΓòÉΓòÉ
  939.  
  940.  
  941. ΓòÉΓòÉΓòÉ 3.1.1. Introduction ΓòÉΓòÉΓòÉ
  942.  
  943. /dev/EDM2/BookReview 
  944.  
  945. /dev/EDM2/BookReview is a monthly column which focuses on development oriented 
  946. books and materials.  This will mostly consist of programming books, such as 
  947. this month's Writing OS/2 2.1 Device Drivers in C, but could also be books like 
  948. The Design of OS/2.  The column is from a beginning PM programmer's eyes 
  949. (because that's what I am), and hopefully that is most useful to the community 
  950. in general.  As I get on with the column, however, I expect to get better, and 
  951. so within a year or so, I will presumably :) qualify as an intermediate 
  952. programmer, or perhaps even somewhat of an expert.  Hopefully you, the readers, 
  953. will move with me in that respect.  When reading this column, try to pick up 
  954. whichever book strikes your fancy, and join the growing group of people 
  955. following our introductory PM programming columns.  I will try to review books 
  956. aimed at beginners to start with, and then move on from there. 
  957.  
  958. The column will largely be demand-oriented (after I get my own books out of the 
  959. way early on), so if you have a book you would like reviewed, send me e-mail 
  960. and tell me about it, or even better, send me the book.  (no-one has sent me 
  961. any requests yet, and my personal library is nearly covered!  If no-one writes, 
  962. I will choose some myself).  Finally, please send me your comments and thoughts 
  963. so that I can make this column as effective as possible. After all, this is our 
  964. magazine, and it will be most effective with lots of reader feedback. 
  965.  
  966. I decided to review this book for two reasons.  First of all, OS/2 needs more 
  967. device drivers, as we all know, and I figured that reviewing this might prompt 
  968. some would-be device-driver writers to buy it and get going.  Secondly, I have 
  969. heard many good things about this book, and so was naturally curious about it. 
  970.  
  971.  
  972. ΓòÉΓòÉΓòÉ 3.1.2. Errata ΓòÉΓòÉΓòÉ
  973.  
  974. Errata 
  975.  
  976. I have just picked up Watcom C/C++ 9.5, so things have changed a bit since last 
  977. month. The makefile that comes with Real World Programming for OS/2 2.1 works 
  978. fine, with a couple of modifications: 
  979.  
  980.  1. Add a section for C++, if you plan on using the makefile for C++ 
  981.     programming. You can just copy the C section, and modify it as follows: 
  982.  
  983.          .cpp.obj:
  984.             @echo ╨╛╨╛╨╛ Compiling $*.cpp using WATCOM C/C++ options ╨┐╨┐╨┐
  985.             wpp386 -d1 -zq -W2 -D__WATCOM__ $(WCL386OPTS) $*.cpp
  986.  
  987.     and add .cpp to the .EXTENSIONS directive after .c. 
  988.  2. In each .DEP file, add .SYMBOLIC to the end of the ALL: line.  This 
  989.     eliminates some error messages that otherwise occur. 
  990.  
  991.  
  992. ΓòÉΓòÉΓòÉ 3.1.3. Writing OS/2 2.1 Device Drivers in C, 2nd Edition ΓòÉΓòÉΓòÉ
  993.  
  994. Writing OS/2 2.1 Device Drivers in C, 2nd Edition 
  995.  
  996. This book is a must for device driver programmers!  It has extensive reference 
  997. material all the way through, and brief examples of how to use many of the 
  998. functions.  Skeleton code is presented throughout, to guide the novice and 
  999. intermediate OS/2 device driver programmer.  Strategies are explained and much 
  1000. of the inside workings of OS/2 and hardware are explained. 
  1001.  
  1002. Here are the chapter headings: 
  1003.  
  1004.  1. The Evolution of PC Device Drivers 
  1005.  2. Understanding Device Drivers 
  1006.  3. The PC Hardware Architecture 
  1007.  4. An Overview of the OS/2 Operating System 
  1008.  5. The Anatomy of an OS/2 Device Driver 
  1009.  6. Device Driver Strategy Commands 
  1010.  7. A Simple OS/2 Physical Device Driver 
  1011.  8. The Micro Channel Bus 
  1012.  9. OS/2 2.1 Virtual Device Drivers 
  1013. 10. Memory Mapped Adapters and IOPL 
  1014. 11. Direct Memory Access (DMA) 
  1015. 12. Extended Device Driver Interface 
  1016. 13. Debugging OS/2 2.1 Device Drivers 
  1017. 14. An Introduction to Presentation Drivers 
  1018. 15. Working with Pointers 
  1019. 16. PCMCIA Device Drivers 
  1020. 17. Tips and Techniques 
  1021. 18. Device Helper Reference 
  1022. 19. Reference Publications 
  1023. 20. Listings 
  1024. 21. OEMHLP and TESTCFG 
  1025.  
  1026. The first four chapters serve to introduce the area of device driver 
  1027. programming by way of explaining where we came from, and where OS/2 is headed. 
  1028. First, we are treated to a brief history of the micro-computer, starting with 
  1029. the Altair 8800, and covering the very early ways of programming directly for 
  1030. the hardware.  This stuff is even worse than DOS, believe it or not.  The very 
  1031. early programs each had their own built-in operating system!!  The origins of 
  1032. micro-computer operating systems are outlined along with explanations of BIOS 
  1033. and some architecture basics, like the bus. 
  1034.  
  1035. In chapter three, the PC hardware architecture is explained, starting with the 
  1036. 8088, and going through the 80286, the AT bus, the PS/2, the Micro Channel bus, 
  1037. EISA, real mode, protect mode, addressing and the ring architecture of the 
  1038. 80386 and 80486.  In chapter four we are then walked through the early versions 
  1039. of OS/2, disadvantages and all, to the OS we all know and love, OS/2 2.x. 
  1040.  
  1041. The book really starts in chapter five.  The early chapters were very brief, 
  1042. and could be read comfortably in one sitting.  This chapter gets more 
  1043. complicated, and has some spine chilling warnings like "It may be difficult or 
  1044. impossible to find a device driver problem using normal debugging techniques." 
  1045. Luckily, we have the OS/2 kernel debugger, KDB.  Installation of the kernel 
  1046. debugger is explained, and then the basic OS/2 device driver design is 
  1047. explained step by step.  The various components of the device driver are 
  1048. outlined, and code for a start-up routine given.  Unfortunately, the start-up 
  1049. routine is in assembly code, and Watcom C/C++, my compiler, does not come with 
  1050. an assembler, so I could not follow this on my computer. 
  1051.  
  1052. Device drivers have a strategy section, which is basically a switch for the 
  1053. message type the OS calls the driver with.  Depending on what the OS needs, a 
  1054. separate section of the device driver is entered, and the need fulfilled. 
  1055. Device drivers can either fulfil the request immediately, or it can acknowledge 
  1056. the receipt of the request, and fulfil it as time permits.  There are quite a 
  1057. few different strategy commands that the OS can use, depending on what type of 
  1058. driver you are writing. 
  1059.  
  1060. Chapter seven explains a sample device driver for an 8-bit parallel port. You 
  1061. can enhance this code to suit your needs, if you have to program such a port. 
  1062. This is the only fairly complete device driver code that the book contains, but 
  1063. of course most people attempting to program a device driver have the 
  1064. specifications for the particular device they are interested in, and so the 
  1065. skeleton code suffices. 
  1066.  
  1067. The remainder of the chapters discuss various other types of device drivers, 
  1068. such as memory mapped drivers, presentation device drivers, and so on.  These 
  1069. chapters are fairly introductory in nature, and no-one is going to get a free 
  1070. ride here.  This book has to be supplemented with device specific reference 
  1071. material!  On the other hand, I shudder to think how anyone would program a 
  1072. device driver for OS/2 without this book, or something similar. There are many 
  1073. efficiency considerations to take into account, and trying to program for OS/2 
  1074. with only DOS device driver knowledge would be like trying to climb Mont Blanc 
  1075. after walking up the local Devil's Hill.  You are bound to do things wrong 
  1076. without some guidelines. 
  1077.  
  1078. Programming device drivers for OS/2 is not for the faint of heart, but neither 
  1079. is it impossible.  It requires the right tools, the right attitude, the right 
  1080. information, the patience, and this book (or another similar book, but I have 
  1081. never heard of any other book like this).  Like any difficult programming 
  1082. problem, successfully writing a device driver for OS/2 is tricky, but 
  1083. potentially very rewarding.  Just take a look at the popularity of the SIO 
  1084. drivers, which are considered to be better than OS/2's own by most people. Good 
  1085. luck! 
  1086.  
  1087.  
  1088. ΓòÉΓòÉΓòÉ 3.1.4. Summary and Ratings ΓòÉΓòÉΓòÉ
  1089.  
  1090. Summary and Ratings 
  1091.  
  1092. This is a very authoritative book, almost more of a reference book than a 
  1093. tutorial.  It has a lot of tables of flag bits, device helper functions, PCMCIA 
  1094. card services, KDB keywords, ad infinitum.  Although it is a large book (at 547 
  1095. pages), it still has a very terse feel to it, and is definitely aimed at 
  1096. advanced programmers.  Anyone considering writing device drivers should 
  1097. definitely be comfortable with C, and familiar with computer architecture and 
  1098. the specific hardware they want to program for.  This is a "bible" type of 
  1099. book, and as such is probably required reading for OS/2 device driver 
  1100. programmers in much the same way that the ARM is required for C++ programmers. 
  1101. The only downside is what is not there.  IFS drivers are not covered, and 
  1102. neither are SCSI or ADD drivers.  This is mentioned in the introduction, 
  1103. however, and is promised for the next printing.  I did feel a little surprised 
  1104. by the fact that the DevHlp library used in the book has to be purchased 
  1105. separately, but I suppose it would be a little much to ask for it to be 
  1106. included with such a reasonably priced book. 
  1107.  
  1108. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  1109. ΓöéBOOK                                ΓöéAUDIENCE    ΓöéMARKΓöéCOMMENTS                                          Γöé
  1110. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1111. ΓöéReal World Programming for OS/2 2.1,ΓöéIntermediateΓöéB+  ΓöéLots of good code examples, but sometimes it is   Γöé
  1112. ΓöéBlain, Delimon, and English, SAMS   Γöéto Advanced Γöé    Γöétoo complex for novices. Accurate.  Well          Γöé
  1113. ΓöéPublishing. ISBN 0-672-30300-0.     ΓöéPM C        Γöé    Γöéorganized.  The index needs a little beefing up.  Γöé
  1114. ΓöéUS$40, CAN$50.                      Γöéprogrammers Γöé    ΓöéGood, but not entirely complete how-to reference. Γöé
  1115. Γöé                                    Γöé            Γöé    ΓöéGood purchase.                                    Γöé
  1116. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1117. ΓöéLearning to Program OS/2 2.0        ΓöéBeginning PMΓöéB-  ΓöéThis book can be both frustrating and very        Γöé
  1118. ΓöéPresentation Manager by Example,    ΓöéC           Γöé    Γöérewarding.  It is not very large, and a bit       Γöé
  1119. ΓöéKnight, Van Nostrand Reinhold. ISBN ΓöéProgrammers Γöé    Γöépricey, but has some excellent chapters on        Γöé
  1120. Γöé0-442-01292-6. US$40, CAN$50.       Γöé            Γöé    Γöébeginning topics, such as messages, resources,    Γöé
  1121. Γöé                                    Γöé            Γöé    ΓöéIPF, and dialog boxes.  Strictly for beginners.   Γöé
  1122. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1123. ΓöéWriting OS/2 2.1 Device Drivers in  ΓöéAdvanced C  ΓöéA-  ΓöéThe only thing a device driver programmer would   Γöé
  1124. ΓöéC, 2nd Edition, Mastrianni, Van     ΓöéProgrammers,Γöé    Γöénot find in here is how to write SCSI, ADD, and   Γöé
  1125. ΓöéNostrand Reinhold. ISBN             Γöéfamiliar    Γöé    ΓöéIFS drivers.  Most everything else is in here,    Γöé
  1126. Γöé0-442-01729-4. US$35, CAN$45.       Γöéwith        Γöé    Γöéalong with skeleton examples.  An optional DevHlp Γöé
  1127. Γöé                                    Γöéhardware    Γöé    Γöélibrary of C-callable functions can be purchased  Γöé
  1128. Γöé                                    Γöéprogramming Γöé    Γöéby those who don't have time to write their own.  Γöé
  1129. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1130.  
  1131. This table contains all books I have reviewed, so that you can find what you 
  1132. are looking for at a glance.  I will be very careful to rate books fairly 
  1133. relative to each other.  If I feel a need to adjust ratings, I will adjust all 
  1134. of them at the same time, and write a note explaining why I felt this 
  1135. necessary.  Please note that books aimed at different audiences should only be 
  1136. compared with great care, if at all.  I intend to concentrate on the strong 
  1137. points of the books I review, but I will point out any weaknesses in a 
  1138. constructive manner.  Read the reviews carefully for what you are looking for. 
  1139.  
  1140. BOOK:  The name of the book, author(s), publishing company, ISBN, and 
  1141. approximate price. 
  1142.  
  1143. AUDIENCE:  This is a description of the audience I think the book targets best. 
  1144. This is not intended as gospel, just a guideline for people not familiar with 
  1145. the book. 
  1146.  
  1147. MARK:  My opinion of the success of the book's presentation, and how well it 
  1148. targets its audience.  Technical content, accuracy, organization, readability, 
  1149. and quality of index all weigh heavily here, but the single most important item 
  1150. is how well the book covers what it says it covers.  I don't expect to see any 
  1151. book score less than C, but the scale is there if necessary. 
  1152.  
  1153. ΓöîΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  1154. ΓöéA+ ΓöéGround-breaking, all-around outstanding book                          Γöé
  1155. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1156. ΓöéA  ΓöéExcellent book. This is what I want to see happen a lot               Γöé
  1157. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1158. ΓöéA- ΓöéExcellent book with minor flaws                                       Γöé
  1159. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1160. ΓöéB+ ΓöéVery good book with minor flaws or omissions                          Γöé
  1161. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1162. ΓöéB  ΓöéGood book with some flaws and omissions                               Γöé
  1163. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1164. ΓöéB- ΓöéGood book, but in need of improvement                                 Γöé
  1165. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1166. ΓöéC  ΓöéMediocre book with some potential, but in need of repairing           Γöé
  1167. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1168. ΓöéD  ΓöéDon't buy this book unless you need it, and nothing else exists       Γöé
  1169. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  1170. ΓöéF  ΓöéDon't buy this book. Period                                           Γöé
  1171. ΓööΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1172.  
  1173. COMMENTS: This is a summary of the review proper, although in a very brief 
  1174. format. 
  1175.  
  1176.  
  1177. ΓòÉΓòÉΓòÉ 3.1.5. Coming Up ΓòÉΓòÉΓòÉ
  1178.  
  1179. Coming Up 
  1180.  
  1181. Next month I will be looking at The Art of OS/2 C Programming, Panov, Salomon 
  1182. and Panov, if it gets here in time (sounds familiar :). Otherwise I will review 
  1183. OS/2 Presentation Manager GPI, Winn, or a REXX book. The books I intend to 
  1184. review are (not necessarily in this order): 
  1185.  
  1186. o The Art of OS/2 C Programming, Panov, Salomon and Panov 
  1187. o OS/2 Presentation Manager GPI, Winn 
  1188. o OS/2 Presentation Manager Programming, Petzold - 1994 - not yet published :( 
  1189. o The Design of OS/2, 2nd Edititon, Kogan and Deitel - 1994 - not published 
  1190.   yet? I will review the old version if someone sends me one, but if I have to 
  1191.   buy it I will wait for the new edition. 
  1192.  
  1193. This list is not set in stone, but they are books I am interested in.  I am 
  1194. considering reviewing the IBM OS/2 Redbooks, since they are readily and cheaply 
  1195. available, and look like good introductory reference.  I am also considering 
  1196. reviewing OS/2 Unleashed, but it is not strictly speaking a development book, 
  1197. so I'm going to wait until the list of real development books has diminished a 
  1198. bit.  By the way, does anyone know why the special edition of OS/2 Unleashed 
  1199. has completely different authors?  And what is different about the Special 
  1200. Edition? 
  1201.  
  1202. I would like to review a REXX book as I have VX-REXX 2.0, but I don't really 
  1203. know what books are supposed to be good, so if anyone has ideas here, please 
  1204. write.  Finally, if anyone has a book they want to see reviewed, I will be 
  1205. happy to oblige as long as I can afford it.  Of course, the request could be 
  1206. satisfied a lot quicker if accompanied by a book.  :) 
  1207.  
  1208.  
  1209. ΓòÉΓòÉΓòÉ 3.2. C++ Corner ΓòÉΓòÉΓòÉ
  1210.  
  1211.  
  1212. ΓòÉΓòÉΓòÉ 3.2.1. Introduction ΓòÉΓòÉΓòÉ
  1213.  
  1214. Written by Gordon Zeglinski 
  1215.  
  1216. Introduction 
  1217.  
  1218. As my project enters its final stages, the work load associated with it has 
  1219. gone through the roof.  Therefore, the column will be a tad shorter than usual. 
  1220.  
  1221. Drag and drop is one of OS/2's nicest features, but probably one of the most 
  1222. feared by new programmers.  It's particularly painful, because you can't set 
  1223. breakpoints inside the processing of the DM_DRAG, DM_DRAGOVER, etc. messages. 
  1224. But since this is a C++ column, and drag and drop is a bit complex for a single 
  1225. "tad smaller than usual" article, we'll look at the drop half of drag and drop 
  1226. using the IBM PM class libraries. These class libraries do a lot more than just 
  1227. encapsulate the PM infrastructure; they abstract PM to such an extent, that 
  1228. they could be developed into a cross platform toolkit. 
  1229.  
  1230.  
  1231. ΓòÉΓòÉΓòÉ 3.2.2. Processing Drop ΓòÉΓòÉΓòÉ
  1232.  
  1233. Processing Drop 
  1234.  
  1235. Drop Basics 
  1236.  
  1237. Before moving on to looking at the code which processes the drop actions, we 
  1238. will briefly look at the stages involved in processing a drop: 
  1239.  
  1240.  1. The application is notified of a drag occurring.  The application checks 
  1241.     what is being dragged over it.  It then sets the return value to indicate 
  1242.     to the OS, whether the dragged object(s) can be dropped. 
  1243.  
  1244.  2. When the user drops the dragged objects, the application is notified of the 
  1245.     drop.  It then performs the actions associated with the drag. 
  1246.  
  1247. Both the initiator and recipient of the drag and drop operation must agree upon 
  1248. the information being exchanged; this is done by using a rendering mechanism 
  1249. and format specifier, both of which are text strings.  The OS/2 PM programming 
  1250. reference defines a set of standard rendering and format strings. In addition 
  1251. to these, the programmer can define application-specific rendering and format 
  1252. strings. 
  1253.  
  1254. Drop in the ICLUI 
  1255.  
  1256. The ICLUI uses several objects to encapsulate drag and drop.  We will look at 
  1257. those classes which we will use in the sample program. 
  1258.  
  1259. Instances of the IDMItem or it's ancestors represent the objects being dragged. 
  1260. By subclassing IDMItem, we can create specialized drag items if we choose to 
  1261. implement our own rendering mechanisms. For this example, we create a new class 
  1262. called AFileItem but give it no "special" properties. 
  1263.  
  1264. class AFileItem : public IDMItem {
  1265. public:
  1266.   AFileItem ( const IDMItem::Handle &item );
  1267.  
  1268. virtual Boolean
  1269.   targetDrop ( IDMTargetDropEvent & );
  1270. };
  1271.  
  1272. The method targetDrop is called when the dragged objects are dropped.  We 
  1273. override this function to handle our application specific processing of the 
  1274. drop event. 
  1275.  
  1276. The template class IDMItemProviderFor is derived from the class 
  1277. IDMItemProvider.  We subclass IDMItemProviderFor to control various aspects of 
  1278. the drag and drop process. IDMItemProvider implies that this object creates 
  1279. IDMItem objects.  However, it can do a lot more than just that.  Below, we 
  1280. subclass the template class IDMItemProviderFor to provide support for drag over 
  1281. type events. 
  1282.  
  1283. class AFileProvider : public IDMItemProviderFor< AFileItem > {
  1284.  
  1285. public:
  1286. virtual Boolean
  1287.   provideEnterSupport ( IDMTargetEnterEvent &event );
  1288. };
  1289.  
  1290. We override the method provideEnterSupport so that when objects are dragged 
  1291. over our main window, we can test them to see if they can be dropped.  Both the 
  1292. ICLUI classes we have looked at provide many more member functions that we can 
  1293. override to provide other drag and drop features, but we will not look at these 
  1294. here. 
  1295.  
  1296.  
  1297. ΓòÉΓòÉΓòÉ 3.2.3. Building a Simple Test Application ΓòÉΓòÉΓòÉ
  1298.  
  1299. Building a Simple Test Application 
  1300.  
  1301. Our simple test application will consist of a frame window and a multi-line 
  1302. edit control.  The frame window class will be subclassed by MyFrame.  The MLE 
  1303. control will be a member of MyFrame. When a file is dropped on the MLE, the 
  1304. contents of the MLE are discarded and the file is loaded into the control.  The 
  1305. following section of code checks the objects being dragged over the MLE. 
  1306.  
  1307. Boolean AFileProvider::provideEnterSupport( IDMTargetEnterEvent &event ){
  1308.  
  1309.   // Get handle to the drag target operation
  1310.   IDMTargetOperation::Handle targetOp = IDMTargetOperation::targetOperation();
  1311.  
  1312.  
  1313.   // only want to accept 1 file
  1314.   if(targetOp->numberOfItems()!=1){
  1315.      event.setDropIndicator(IDM::neverOk);
  1316.      return(true);
  1317.    }
  1318.  
  1319.   // Get the types for the drag item.
  1320.   IString strTypes = targetOp->item(1)->types();
  1321.  
  1322.   // See if it's marked as a "plain text" file
  1323.   if ((strTypes.indexOf(IDM::plainText))){
  1324.     event.setDropIndicator(IDM::ok);
  1325.     return(true);
  1326.   }
  1327.  
  1328.   // Type is not recognized - set the drop indicator to prevent a drop!
  1329.   event.setDropIndicator(IDM::neverOk);
  1330.   return(true);
  1331. }
  1332.  
  1333. If there is more than one object being dropped over, or the object isn't 
  1334. identified as "plain text", the application sets the drop indicator to neverOk. 
  1335. This will then prevent the drop from occurring, and change the pointer to 
  1336. indicate that a drop is not permitted.  The following code snippet, loads the 
  1337. MLE with the dropped file. 
  1338.  
  1339. Boolean AFileItem::targetDrop( IDMTargetDropEvent & Event){
  1340.    IMultiLineEdit *DropWin=(IMultiLineEdit *)this->targetOperation()->targetWindow();
  1341.  
  1342.  
  1343.    IString
  1344.     fname = this->containerName() + this->sourceName();
  1345.  
  1346.    //erase the edit window
  1347.    DropWin->removeAll();
  1348.  
  1349.    //load the file into the edit window
  1350.    DropWin->importFromFile(fname);
  1351.  
  1352.  
  1353.    return true;
  1354. }
  1355.  
  1356. The constructor for the class MyFrame follows.  The constructor enables drag 
  1357. and drop for the MLE and attaches an instance of our FileProvider to the MLE. 
  1358.  
  1359. MyFrame::MyFrame(const char *Title):
  1360.    IFrameWindow(Title,IResourceId(1),  //-------------------
  1361.       IFrameWindow::titleBar|          //
  1362.       IFrameWindow::sizingBorder|      //
  1363.       IFrameWindow::minimizeButton|    // Create the Frame
  1364.       IFrameWindow::systemMenu|        //  Window
  1365.       IFrameWindow::shellPosition|     //
  1366.       IFrameWindow::minimizeButton|    //
  1367.       IFrameWindow::windowList|        //
  1368.       IFrameWindow::maximizeButton),   //--------------------
  1369.    EditWin(10,this,this){              // Create the Edit Window
  1370.                                        // ID=10, use this frame
  1371.                                        // window as the parent and
  1372.                                        //owner
  1373.                                        //---------------------
  1374.  
  1375.    setIcon(IResourceId(1));
  1376.    setClient(&EditWin);
  1377.  
  1378.    //enable default drag and drop handler
  1379.    IDMHandler::enableDragDropFor(&EditWin);
  1380.    //attach the provider
  1381.    EditWin.setItemProvider(&FileProvider);
  1382.  
  1383.    show();
  1384. }
  1385.  
  1386. The file CPPDD.CPP contains the complete source code for the simple app. To 
  1387. compile the code simply execute the Rexx program GO.CMD. 
  1388.  
  1389.  
  1390. ΓòÉΓòÉΓòÉ 3.2.4. Summary ΓòÉΓòÉΓòÉ
  1391.  
  1392. Summary 
  1393.  
  1394. Drag and drop is one of OS/2's most intuitive user interface features and the 
  1395. ICLUI completely encapsulates the direct manipulation API.  However, as with 
  1396. other parts of the ICLUI its encapsulation strategy is not clearly documented. 
  1397. In this article, we have explored how to enable our ICLUI applications to 
  1398. accept dropped files. 
  1399.  
  1400. Yet, we still have only barely touched this topic's surface. 
  1401.  
  1402.  
  1403. ΓòÉΓòÉΓòÉ 3.3. Introduction to PM Programming ΓòÉΓòÉΓòÉ
  1404.  
  1405.  
  1406. ΓòÉΓòÉΓòÉ 3.3.1. Introduction ΓòÉΓòÉΓòÉ
  1407.  
  1408. Written by Larry Salomon, Jr. 
  1409.  
  1410. Introduction 
  1411.  
  1412. The purpose of this column is to provide the readers out there who are not 
  1413. familiar with PM application development the information necessary to satisfy 
  1414. their curiousity, educate themselves, and give them an advantage over the 
  1415. documentation supplied by IBM.  Of course, much of this stuff could probably be 
  1416. found in one of the many books out there, but the problem with books in general 
  1417. is that they don't answer the questions you have after you read the book the 
  1418. first time through. 
  1419.  
  1420. I will gladly entertain feedback from the readers about what was "glossed over" 
  1421. or what was detailed well, what tangential topics need to be covered and what 
  1422. superfluous crap should have been removed.  This feedback is essential in 
  1423. guaranteeing that you get what you pay for.  :) 
  1424.  
  1425. It should be said that you must not depend solely on this column to teach you 
  1426. how to develop PM applications; instead, this should be viewed as a supplement 
  1427. to your other information storehouses (books, the network conferences, etc.). 
  1428. Because this column must take a general approach, there will be some topics 
  1429. that you would like to see discussed that really do not belong here.  Specific 
  1430. questions can be directed to the Scratch Patch, where an attempt to answer them 
  1431. will be made. 
  1432.  
  1433.  
  1434. ΓòÉΓòÉΓòÉ 3.3.2. Last Month ΓòÉΓòÉΓòÉ
  1435.  
  1436. Last Month 
  1437.  
  1438. Last month, we introduced the WM_COMMAND and WM_CONTROL messages, which are - 
  1439. as you will see - very important in the development of many PM applications. 
  1440. We also looked at the HELLO dialog procedure in a little detail, and were 
  1441. introduced to three new APIs. 
  1442.  
  1443. This month, we will introduce some more APIs, will continue dissecting the 
  1444. dialog procedure, and will begin looking at our first window class in detail. 
  1445.  
  1446.  
  1447. ΓòÉΓòÉΓòÉ 3.3.3. New APIs ΓòÉΓòÉΓòÉ
  1448.  
  1449. New APIs 
  1450.  
  1451. PM has a few specific APIs which are more "helper APIs" than anything else, 
  1452. because they replace two APIs, the first of which is always WinWindowFromID(). 
  1453.  
  1454. HWND WinWindowFromID(HWND hwndParent,ULONG ulId);
  1455.  
  1456. WinWindowFromID searches the children of hwndParent to find a window whose 
  1457. identifier (remember these from the first column in this series?) matches ulId. 
  1458. It returns the window handle if found, or NULLHANDLE otherwise. 
  1459.  
  1460. These new functions are listed below: 
  1461.  
  1462. BOOL WinSetDlgItemText(HWND hwndDlg,ULONG ulId,PSZ pszText);
  1463.  
  1464. ULONG WinQueryDlgItemText(HWND hwndDlg,
  1465.                           ULONG ulId,
  1466.                           LONG ulSzBuffer,
  1467.                           PCHAR pchBuffer);
  1468.  
  1469. LONG WinQueryDlgItemTextLength(HWND hwndDlg,ULONG ulId);
  1470.  
  1471. These three functions provide the equivalent of the WinSetWindowText(), 
  1472. WinQueryWindowText(), and WinQueryWindowTextLength() functions that we looked 
  1473. at last month. The only difference is that the above three functions call 
  1474. WinWindowFromID() first to determine the handle of the window you are 
  1475. interested in. 
  1476.  
  1477. Letter carriers and Bulletin Boards 
  1478.  
  1479. While thinking about the topics that I should cover this month, I realized 
  1480. that, although the terms sending and posting messages have been used liberally 
  1481. over the lifespan of this column, the functions to perform these two actions 
  1482. have never been discussed, nor has the difference between the two been 
  1483. discussed. 
  1484.  
  1485. MRESULT WinPostMsg(HWND hwndWnd,
  1486.                    ULONG ulMsg,
  1487.                    MPARAM mpParm1,
  1488.                    MPARAM mpParm2);
  1489.  
  1490. MRESULT WinSendMsg(HWND hwndWnd,
  1491.                    ULONG ulMsg,
  1492.                    MPARAM mpParm1,
  1493.                    MPARAM mpParm2);
  1494.  
  1495. Both WinSendMsg and WinPostMsg take the same parameter set: 
  1496.  
  1497. hwndWnd             the window to receive the message to be posted or sent 
  1498. ulMsg               the message identifier 
  1499. mpParm1, mpParm2    message-specific parameters.  See the Programming Reference 
  1500.                     for detailed information about the parameters required for 
  1501.                     each message. 
  1502.  
  1503. The difference between posting and sending is that the former simply puts the 
  1504. message in the message queue of the recipient, while the latter is (logically 
  1505. speaking) a direct call to the window procedure of the recipient's window 
  1506. procedure.  The significance of the last statement is that your window 
  1507. procedure will be blocked until the WinSendMsg() call returns, and that will 
  1508. not happen until the recipient finishes processing the message. 
  1509.  
  1510. Why is one used over the other?  For one thing, since WinSendMsg() is a 
  1511. synchronous call, pointers that are specified are guaranteed to point to valid 
  1512. areas of memory (this is important if they point to local variables on the 
  1513. stack).  Note the word valid instead of accessible; if you send a message to 
  1514. another process with a pointer, accessability to the pointer must be 
  1515. established either via shared memory or giveable/gettable memory.  WinSendMsg() 
  1516. does have one disadvantage, however; it requires that the sender have a message 
  1517. queue. WinPostMsg(), on the other hand, can be sent from anywhere, regardless 
  1518. of whether or not WinCreateMsgQueue() was called previously (this is handy for 
  1519. secondary threads). 
  1520.  
  1521. Given this information, let us look at one more "dialogish" API - 
  1522. WinSendDlgItemMsg(). 
  1523.  
  1524. MRESULT WinSendDlgItemMsg(HWND hwndDlg,
  1525.                           ULONG ulId,
  1526.                           ULONG ulMsg,
  1527.                           MPARAM mpParm1,
  1528.                           MPARAM mpParm2);
  1529.  
  1530. This function, as you can imagine, behaves the same as WinSendMsg(), except 
  1531. that - as with the first three APIs discussed in this section - it calls 
  1532. WinWindowFromID() to get the handle of the window to whom the message should be 
  1533. sent.  It should be noted that there is no function WinPostDlgItemMsg().  I 
  1534. have never been able to get a straight answer for why this is so, 
  1535. unfortunately. 
  1536.  
  1537. One last API to look at - WinDefDlgProc(). 
  1538.  
  1539. MRESULT WinDefDlgProc(HWND hwndWnd,
  1540.                       ULONG ulMsg,
  1541.                       MPARAM mpParm1,
  1542.                       MPARAM mpParm2);
  1543.  
  1544. In volume 2, issue 1, we briefly noted how WinDefWindowProc() was used to 
  1545. handle all messages that we did not want to process in our window class 
  1546. procedure.  WinDefDlgProc() has the same purpose except that it is used within 
  1547. dialog procedures.  Please be aware that, using one when you should be using 
  1548. the other will result in very strange behavior, so be careful! 
  1549.  
  1550.  
  1551. ΓòÉΓòÉΓòÉ 3.3.4. nameDlgProc() Revisited ΓòÉΓòÉΓòÉ
  1552.  
  1553. nameDlgProc() Revisited 
  1554.  
  1555. Let's look at nameDlgProc() one more time, this time in its entirety. 
  1556. Following that is the resource file definition for the dialog. 
  1557.  
  1558. MRESULT EXPENTRY nameDlgProc(HWND hwndWnd,
  1559.                              ULONG ulMsg,
  1560.                              MPARAM mpParm1,
  1561.                              MPARAM mpParm2)
  1562. {
  1563.    PNAMEDLGINFO pndiInfo;
  1564.  
  1565.    pndiInfo=(PNAMEDLGINFO)WinQueryWindowPtr(hwndWnd,0);              // @1
  1566.  
  1567.    switch (ulMsg) {
  1568.    case WM_INITDLG:                                                  // @2
  1569.       {
  1570.          HAB habAnchor;
  1571.          HWND hwndLb;
  1572.          CHAR achText[64];
  1573.  
  1574.          pndiInfo=(PNAMEDLGINFO)PVOIDFROMMP(mpParm2);                // @3
  1575.          WinSetWindowPtr(hwndWnd,0,(PVOID)pndiInfo);                 // @4
  1576.  
  1577.          WinSendDlgItemMsg(hwndWnd,                                  // @5
  1578.                            DNAME_EF_NAME,
  1579.                            EM_SETTEXTLIMIT,
  1580.                            MPFROMSHORT(sizeof(pndiInfo->achName)),
  1581.                            0);
  1582.  
  1583.          habAnchor=WinQueryAnchorBlock(hwndWnd);
  1584.          hwndLb=WinWindowFromID(hwndWnd,DNAME_LB_NAMELIST);
  1585.  
  1586.          WinLoadString(habAnchor,                                    // @6
  1587.                        NULLHANDLE,
  1588.                        STR_TOM,
  1589.                        sizeof(achText),
  1590.                        achText);
  1591.  
  1592.          WinInsertLboxItem(hwndLb,LIT_END,achText);                  // @7
  1593.  
  1594.          WinLoadString(habAnchor,
  1595.                        NULLHANDLE,
  1596.                        STR_DICK,
  1597.                        sizeof(achText),
  1598.                        achText);
  1599.  
  1600.          WinInsertLboxItem(hwndLb,LIT_END,achText);
  1601.  
  1602.          WinLoadString(habAnchor,
  1603.                        NULLHANDLE,
  1604.                        STR_HARRY,
  1605.                        sizeof(achText),
  1606.                        achText);
  1607.  
  1608.          WinInsertLboxItem(hwndLb,LIT_END,achText);
  1609.       }
  1610.       break;
  1611.    case WM_CONTROL:                                                  // @8
  1612.       switch (SHORT1FROMMP(mpParm1)) {
  1613.       case DNAME_LB_NAMELIST:
  1614.          switch (SHORT2FROMMP(mpParm1)) {
  1615.          case LN_SELECT:                                             // @9
  1616.             {
  1617.                HWND hwndLb;
  1618.                SHORT sIndex;
  1619.  
  1620.                hwndLb=WinWindowFromID(hwndWnd,DNAME_LB_NAMELIST);
  1621.  
  1622.                sIndex=WinQueryLboxSelectedItem(hwndLb);
  1623.                WinQueryLboxItemText(hwndLb,
  1624.                                     sIndex,
  1625.                                     pndiInfo->achName,
  1626.                                     sizeof(pndiInfo->achName));
  1627.  
  1628.                WinSetDlgItemText(hwndWnd,
  1629.                                  DNAME_EF_NAME,
  1630.                                  pndiInfo->achName);
  1631.             }
  1632.             break;
  1633.          case LN_ENTER:                                              // @10
  1634.             WinPostMsg(hwndWnd,WM_COMMAND,MPFROMSHORT(DID_OK),0);
  1635.             break;
  1636.          default:
  1637.             return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);     // @11
  1638.          } /* endswitch */
  1639.          break;
  1640.       default:
  1641.          return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1642.       } /* endswitch */
  1643.       break;
  1644.    case WM_COMMAND:
  1645.       switch (SHORT1FROMMP(mpParm1)) {
  1646.       case DID_OK:                                                   // @12
  1647.          WinDismissDlg(hwndWnd,TRUE);
  1648.          break;
  1649.       case DID_CANCEL:                                               // @13
  1650.          WinDismissDlg(hwndWnd,FALSE);
  1651.          break;
  1652.       default:
  1653.          return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1654.       } /* endswitch */
  1655.       break;
  1656.    default:
  1657.       return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1658.    } /* endswitch */
  1659.  
  1660.    return MRFROMSHORT(FALSE);
  1661. }
  1662.  
  1663. ------------------------------------------
  1664.  
  1665. DLGTEMPLATE DLG_NAME LOADONCALL MOVEABLE DISCARDABLE
  1666. {
  1667.    DIALOG  "Input Required", DLG_NAME, 112, 59, 150, 100,
  1668.       WS_VISIBLE,
  1669.       FCF_SYSMENU | FCF_TITLEBAR
  1670.    {
  1671.       LTEXT "Select a name, or enter it below, and select ""Ok""" ".", -1, 10, 80, 130, 16, DT_WORDBREAK
  1672.       LISTBOX DNAME_LB_NAMELIST, 10, 45, 130, 35, LS_HORZSCROLL
  1673.       ENTRYFIELD "", DNAME_EF_NAME, 12, 30, 127, 8, ES_MARGIN
  1674.       DEFPUSHBUTTON "Ok", DID_OK, 10, 10, 40, 13
  1675.       PUSHBUTTON "Cancel", DID_CANCEL, 55, 10, 40, 13
  1676.    }
  1677. }
  1678.  
  1679. From the dialog template, we see that the dialog consists of five controls:  a 
  1680. text control (LTEXT) whose identifier is -1 (see below), a listbox control 
  1681. (LISTBOX) whose identifier is DNAME_LB_NAMELIST, an entryfield control 
  1682. (ENTRYFIELD)  whose identifier is DNAME_EF_NAME, and two pushbuttons (the first 
  1683. is DEFPUSHBUTTON meaning it's the default pushbutton and the second which is 
  1684. simply PUSHBUTTON) whose identifiers are DID_OK and DID_CANCEL, respectively. 
  1685.  
  1686. It is important to remember that, while the symbolic constants 
  1687. DNAME_LB_NAMELIST and DNAME_EF_NAME are defined in HELLORC.H, DID_OK and 
  1688. DID_CANCEL are defined in <pmwin.h> which is #include-d by <os2.h>. 
  1689.  
  1690. Looking at the easiest message first, at numbers @12 and @13 we see the 
  1691. processing of the WM_COMMAND message, which (if you'll remember from last 
  1692. month) is sent by a pushbutton whenever it is pressed ("selected" is the term 
  1693. typically used).  You should remember that the identifier of the button is in 
  1694. SHORT1FROMMP(mpParm1), which we "switch" on to determine the appropriate action 
  1695. to take.  Here, we simply dismiss the dialog with either TRUE or FALSE returned 
  1696. depending on whether the user completed the dialog or changed their mind and 
  1697. decided to select Cancel. 
  1698.  
  1699. At number @8 we see the WM_CONTROL message.  Again, last month we looked at 
  1700. this message and you should remember that the identifier of the window sending 
  1701. the message is in SHORT1FROMMP(mpParm1), which we "switch" on to determine how 
  1702. to interpret the notification code.  Since we're interested in the listbox 
  1703. only, we process "case DNAME_LB_NAMELIST" and let WinDefDlgProc() handle 
  1704. everything else (at number @11).  At number @9 is the LN_SELECT notification, 
  1705. which is sent whenever a listbox item is selected.  Number @10 is the LN_ENTER 
  1706. notification, which is sent whenever ENTER is pressed while the listbox has the 
  1707. input focus or any listbox item is double-clicked.  Since we will not be 
  1708. looking at the listbox in any great detail until a future issue, I will not 
  1709. elaborate on these two notifications until that time. 
  1710.  
  1711. At number @2 is the dialog initialization code, which I will not discuss at 
  1712. this time due to its complexity relative to what has been covered by this 
  1713. column up to this point in time. 
  1714.  
  1715.  
  1716. ΓòÉΓòÉΓòÉ 3.3.5. The WC_ENTRYFIELD Window Class ΓòÉΓòÉΓòÉ
  1717.  
  1718. The WC_ENTRYFIELD Window Class 
  1719.  
  1720. Entryfields belong to the class WC_ENTRYFIELD and are probably the easiest of 
  1721. the window classes to use, since there isn't a lot of variation involved in the 
  1722. control's design.  An entryfield is used to get a single line of text from the 
  1723. user and has clipboard support built-in (the clipboard will be discussed in a 
  1724. later issue).  In an entryfield, text can be selected with the mouse or the 
  1725. keyboard.  A selection consists of an anchor point and a cursor point.  The 
  1726. anchor point is the point at which the selection began, and the cursor point is 
  1727. the point where the selection ends, and may move depending on whether the 
  1728. selection is still in progress. 
  1729.  
  1730. An entryfield can have the following styles: 
  1731.  
  1732. ES_ANY              relates to DBCS ("double byte character set") support and 
  1733.                     will not be discussed here. 
  1734. ES_AUTOSCROLL       specifies that, when the user moves the cursor outside of 
  1735.                     the visible area, the entryfield should automatically 
  1736.                     scroll so that the cursor is in a visible area. 
  1737. ES_AUTOSIZE         specifies that the entryfield should automatically size 
  1738.                     itself to insure that its contents are completely visible. 
  1739. ES_AUTOTAB          specifies that, when the user enters the number of 
  1740.                     characters equal to the current text limit (see 
  1741.                     EM_SETTEXTLIMIT), the entryfield should automatically give 
  1742.                     the input focus to the next control on the dialog. 
  1743. ES_CENTER           specifies that the text should be displayed centered. 
  1744. ES_COMMAND          relates to online help and will not be discussed here. 
  1745. ES_DBCS             relates to DBCS ("double byte character set") support and 
  1746.                     will not be discussed here. 
  1747. ES_LEFT             specifies that the text should be displayed flush-left. 
  1748. ES_MARGIN 
  1749. ES_MIXED            relates to DBCS ("double byte character set") support and 
  1750.                     will not be discussed here. 
  1751. ES_READONLY         specifies that the user should not be able to change the 
  1752.                     contents. 
  1753. ES_RIGHT            specifies that the text should be displayed flush-right. 
  1754. ES_SBCS             relates to DBCS ("double byte character set") support and 
  1755.                     will not be discussed here. 
  1756. ES_UNREADABLE       specifies that each character in the entryfield should be 
  1757.                     displayed as an asterisk ('*'). 
  1758.  
  1759. The entryfield has a number of messages that it understands, and they are 
  1760. listed below.  We will discuss some of them here, and will continue in the next 
  1761. issue. 
  1762.  
  1763. o EM_CLEAR 
  1764. o EM_COPY 
  1765. o EM_CUT 
  1766. o EM_PASTE 
  1767. o EM_QUERYCHANGED 
  1768. o EM_QUERYFIRSTCHAR 
  1769. o EM_QUERYREADONLY 
  1770. o EM_QUERYSEL 
  1771. o EM_SETFIRSTCHAR 
  1772. o EM_SETINSERTMODE 
  1773. o EM_SETREADONLY 
  1774. o EM_SETSEL 
  1775. o EM_SETTEXTLIMIT 
  1776.  
  1777. You've probably noticed that there are no messages for setting and retrieving 
  1778. the contents of an entryfield.  This is done using the WinSetWindowText() and 
  1779. WinQueryWindowText() (and through the "dialogish" APIs discussed earlier this 
  1780. issue). 
  1781.  
  1782. Let's look at our first four messages - EM_QUERYCHANGED, EM_QUERYFIRSTCHAR, 
  1783. EM_QUERYREADONLY, and EM_QUERYSEL. 
  1784.  
  1785. EM_QUERYCHANGED 
  1786.  
  1787. This message is sent to determine if the text has changed since this message 
  1788. was last sent (or since the control was created). 
  1789.  
  1790. Parameters 
  1791.  
  1792.    param1 
  1793.  
  1794.       ulReserved (ULONG) 
  1795.  
  1796.          Reserved, 0. 
  1797.  
  1798.    param2 
  1799.  
  1800.       ulReserved (ULONG) 
  1801.  
  1802.          Reserved, 0. 
  1803.  
  1804. Returns 
  1805.  
  1806.    reply 
  1807.  
  1808.       bChanged (BOOL) 
  1809.  
  1810.          changed indicator 
  1811.  
  1812.          TRUE      the contents have changed since the last time this message 
  1813.                    was sent. 
  1814.          FALSE     the contents have not changed since the last time this 
  1815.                    message was sent. 
  1816.  
  1817. EM_QUERYFIRSTCHAR 
  1818.  
  1819. This message is sent to determine the zero-based index of the first character 
  1820. visible in the entryfield. 
  1821.  
  1822. Parameters 
  1823.  
  1824.    param1 
  1825.  
  1826.       ulReserved (ULONG) 
  1827.  
  1828.          Reserved, 0. 
  1829.  
  1830.    param2 
  1831.  
  1832.       ulReserved (ULONG) 
  1833.  
  1834.          Reserved, 0. 
  1835.  
  1836. Returns 
  1837.  
  1838.    reply 
  1839.  
  1840.       sIndex (SHORT) 
  1841.  
  1842.          the zero-based index of the first visible character. 
  1843.  
  1844. EM_QUERYREADONLY 
  1845.  
  1846. This message is sent to determine if the entryfield is read-only or not. 
  1847.  
  1848. Parameters 
  1849.  
  1850.    param1 
  1851.  
  1852.       ulReserved (ULONG) 
  1853.  
  1854.          Reserved, 0. 
  1855.  
  1856.    param2 
  1857.  
  1858.       ulReserved (ULONG) 
  1859.  
  1860.          Reserved, 0. 
  1861.  
  1862. Returns 
  1863.  
  1864.    reply 
  1865.  
  1866.       bReadOnly (BOOL) 
  1867.  
  1868.          the read-only state of the entryfield. 
  1869.  
  1870.          TRUE      the entryfield is read-only. 
  1871.          FALSE     the entryfield is not read-only. 
  1872.  
  1873. EM_QUERYSEL 
  1874.  
  1875. This message is sent to determine the current selection, if any exists. 
  1876.  
  1877. Parameters 
  1878.  
  1879.    param1 
  1880.  
  1881.       ulReserved (ULONG) 
  1882.  
  1883.          Reserved, 0. 
  1884.  
  1885.    param2 
  1886.  
  1887.       ulReserved (ULONG) 
  1888.  
  1889.          Reserved, 0. 
  1890.  
  1891. Returns 
  1892.  
  1893.    reply 
  1894.  
  1895.       sFirst (SHORT) 
  1896.  
  1897.          the zero-based index of the anchor point. 
  1898.  
  1899.       sLast (SHORT) 
  1900.  
  1901.          the zero-based index of the cursor point. 
  1902.  
  1903.  
  1904. ΓòÉΓòÉΓòÉ 3.3.6. Summary ΓòÉΓòÉΓòÉ
  1905.  
  1906. Summary 
  1907.  
  1908. This month we learned a lot of new things: 
  1909.  
  1910. o We looked at a slew of new APIs, many of which are attuned to dialogs 
  1911. o We looked at nameDlgProc() is more detail 
  1912. o We began looking at the WC_ENTRYFIELD class in detail 
  1913.  
  1914. Next month, we will continue with the WC_ENTRYFIELD discussion, but will hold 
  1915. off from discussing nameDlgProc() until we look at the WC_LISTBOX window class. 
  1916.  
  1917.  
  1918. ΓòÉΓòÉΓòÉ 3.4. Scratch Patch ΓòÉΓòÉΓòÉ
  1919.  
  1920. Written by Larry Salomon, Jr. 
  1921.  
  1922. Welcome to this month's "Scratch Patch"!  Each month, I collect various items 
  1923. that fit into this column sent to me via email. The ones that I feel contribute 
  1924. the most to developers, whether in terms of information or as a nifty trick to 
  1925. tuck into your cap, get published in this column. 
  1926.  
  1927. To submit an item, send it via email to my address - os2man@panix.com - and be 
  1928. sure to grant permission to publish it (those that forget will not be 
  1929. considered for publication). 
  1930.  
  1931.  
  1932. ΓòÉΓòÉΓòÉ 3.4.1. Gotcha Notes! ΓòÉΓòÉΓòÉ
  1933.  
  1934. Gotcha Notes! 
  1935.  
  1936. Last week I was developing a multithreaded application that needed two-way 
  1937. communication between the main and secondary threads.  The easiest solution, as 
  1938. you may well know, was to use an object window in the second thread with its 
  1939. own message loop.  The purpose of the second thread was to perform some lengthy 
  1940. processing, but needed to be interruptable, i.e. if the user pressed the Abort 
  1941. button, the dialog would send the object window the appropriate message.  After 
  1942. the thread terminated its processing, it would send a response back. 
  1943.  
  1944. A problem was created, though, that resulted in deadlock.  Although it didn't 
  1945. take long to deduce because the code was still quite skeletal (making the 
  1946. process of elimination quite easy), I still do not know why the deadlock 
  1947. occurred.  In any case, it is necessary to relate the situation to the readers 
  1948. so that they may avoid it in their own applications. 
  1949.  
  1950. The code looked something like the following: 
  1951.  
  1952. objectWndProc(...)
  1953. {
  1954.    POBJECTINSTDATA poidData;
  1955.  
  1956.      :
  1957.    case MYM_ABORT:
  1958.       :   /* Abort processing */
  1959.       WinSendMsg(poidData->hwndDlg,MYM_PROCESSINGABORTED,0,0);
  1960.       break;
  1961.      :
  1962. }
  1963.  
  1964. processDlgProc(...)
  1965. {
  1966.    POBJECTINSTDATA poidData;
  1967.  
  1968.      :
  1969.    case WM_COMMAND:
  1970.       switch (SHORT1FROMMP(mpParm1)) {
  1971.       case DLG_PB_ABORT:
  1972.          WinPostMsg(poidData->hwndObj,MYM_ABORT,0,0);
  1973.       default:
  1974.          return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
  1975.       } /* endswitch */
  1976.    case MYM_PROCESSINGABORTED:
  1977.       WinDismissDlg(hwndWnd,DID_CANCEL);
  1978.       break;
  1979.      :
  1980. }
  1981.  
  1982. INT main(VOID)
  1983. {
  1984.    SHORT sRc;
  1985.  
  1986.      :
  1987.    sRc=WinDlgBox(HWND_DESKTOP,
  1988.                  HWND_DESKTOP,
  1989.                  processDlgProc,
  1990.                  NULLHANDLE,
  1991.                  DLG_PROCESS,
  1992.                  NULL);
  1993.    if (sRc!=DID_CANCEL) {
  1994.         :
  1995.    } /* endif */
  1996.      :
  1997. }
  1998.  
  1999. A lot was removed for clarity, but the pertinent parts are shown above. What 
  2000. would happen was that, while testing the communication mechanisms, whenever I 
  2001. would press the Abort button, the dialog would go away, but the application 
  2002. would not terminate; looking at the above, you can probably figure out what the 
  2003. problem was.  The problem, in case you can't figure it out, is the 
  2004. WinSendMsg(...,MYM_PROCESSINGABORTED,...) call to the dialog.  For some reason, 
  2005. if a message is sent intraprocess from the object window to the dialog and the 
  2006. dialog dismisses itself, the process will deadlock.  Changing the WinSendMsg() 
  2007. to WinPostMsg() eliminated the problem. 
  2008.  
  2009. I suspect the answer to why lies in the existence of a message loop in the 
  2010. object window thread, but I cannot be sure.  If anyone can give a definitive 
  2011. answer, I would be happy to publish it. 
  2012.  
  2013.  
  2014. ΓòÉΓòÉΓòÉ 3.4.2. Snippet(s) of the Month ΓòÉΓòÉΓòÉ
  2015.  
  2016. Snippet(s) of the Month 
  2017.  
  2018. David Charlap (david@porsche.visix.com) sent us the following: 
  2019.  
  2020. You can include this snippet.  SWEEP.CMD is a REXX program that allows you to 
  2021. apply any command-line to a recursive set of directories. 
  2022.  
  2023. Syntax is: 
  2024.  
  2025.     SWEEP <command-line>
  2026.  
  2027. The program will visit every subdirectory of the current directory (and all 
  2028. descendants thereof) and execute your command line in each one.  For example, 
  2029. to delete every backup file on your drive, just "cd" to the root directory of 
  2030. the drive and type 
  2031.  
  2032.     SWEEP DEL *.BAK
  2033.  
  2034. If the command you want to execute is a CMD file, be sure to use the "CALL" 
  2035. command, or Rexx will complain: 
  2036.  
  2037.     SWEEP CALL MyCmdFile.CMD myArgs...
  2038.  
  2039.  
  2040. ΓòÉΓòÉΓòÉ 3.4.3. Want Ads ΓòÉΓòÉΓòÉ
  2041.  
  2042. Want Ads 
  2043.  
  2044. Below are the hot topics as of this issue's writing.  Feel free to write on any 
  2045. of these. 
  2046.  
  2047. Workplace Shell Programming (hot) - this is still quite the "black magic" 
  2048. topic, about which we have seen only one article.  There are many out there who 
  2049. do WPS programming for a living, but they have not been sufficiently 
  2050. enlightened about our need. :) 
  2051.  
  2052. Client/Server (hot) - using either named pipes (with or without a network) or 
  2053. sockets, client/server programming is all the rage these days.  On a related 
  2054. note, some people have also expressed an interest in learning about interfacing 
  2055. with the various protocol drivers (e.g.  NDIS, IPX/SPX, etc.).  Any articles in 
  2056. this area are most welcome. 
  2057.  
  2058. Multimedia (warm) - we recently had two articles on this topic.  However, they 
  2059. both dealt with sound, which we all know is not the only alternative media 
  2060. type.  Articles on anything else - MIDI, video, etc. - are needed. 
  2061.  
  2062.  
  2063. ΓòÉΓòÉΓòÉ 4. How do I get EDM/2? ΓòÉΓòÉΓòÉ
  2064.  
  2065. EDM/2 can be obtained in any of the following ways: 
  2066.  
  2067. On the Internet 
  2068.  
  2069. o All back issues are available via anonymous FTP from ftp.cdrom.com in the 
  2070.   /pub/os2/2_x/program/newsltr directory. 
  2071. o The EDM/2 mailing list.  Send an empty message to edm2-info@knex.mind.org to 
  2072.   receive a file containing (among other things) instructions for subscribing 
  2073.   to EDM/2.  This is a UUCP connection, so be patient please. 
  2074. o IBM's external gopher/WWW server in Almaden. The address is 
  2075.   index.almaden.ibm.com and it is in the "Non-IBM-Originated" submenu of the 
  2076.   "OS/2 Information" menu; the URL is 
  2077.   "gopher://index.almaden.ibm.com/1nonibm/os2nonib.70". 
  2078.  
  2079. On Compuserve 
  2080.  
  2081. All back issues are available in the OS/2 Developers Forum 2. 
  2082.  
  2083. IBM Internal 
  2084.  
  2085. o IBM's internal gopher/WWW server in Almaden. The address is 
  2086.   n6tfx.almaden.ibm.com and it is in the "Non-IBM-Originated Files" menu; the 
  2087.   URL is "gopher://n6tfx.almaden.ibm.com/1!!nonibm/nonibm.70". 
  2088. o IBM's REQUEST command on all internal VM systems.  Enter the VM command 
  2089.   REQUEST LIST FROM ASSELIN AT RALVM12 and a list of the requestable packages 
  2090.   will be sent to you; in this list are the names of the packages containing 
  2091.   the EDM/2 issues. 
  2092.  
  2093.  
  2094. ΓòÉΓòÉΓòÉ 5. Contributors to this Issue ΓòÉΓòÉΓòÉ
  2095.  
  2096. Are You a Potential Author? 
  2097.  
  2098. We are always looking for (new) authors.  If you have a topic about which you 
  2099. would like to write, send a brief description of the topic electronically to 
  2100. any of the editors, whose addresses are listed below, by the 15th of the month 
  2101. before the month in which your article will appear.  This alerts us that you 
  2102. will be sending an article so that we can plan the issue layout accordingly. 
  2103. After you have done this, get the latest copy of the Article Submission 
  2104. Guidelines  from ftp.cdrom.com  in the /pub/os2/2_x/program/newsltr directory. 
  2105. (the file is artsub.zip)  The completed text of your article should be sent to 
  2106. us no later than five days prior to the last day of the month; any articles 
  2107. received after that time may be pushed to the next issue. 
  2108.  
  2109. The editors can be reached at the following email addresses: 
  2110.  
  2111. o Larry Salomon - os2man@panix.com (Internet). 
  2112. o Carsten Whimster - bcrwhims@undergrad.math.uwaterloo.ca (Internet). 
  2113.  
  2114. The following people contributed to this issue in one form or another (in 
  2115. alphabetical order): 
  2116.  
  2117. o Martin Lafaix 
  2118. o Larry Salomon, Jr. 
  2119. o Carsten Whimster 
  2120. o Gordon Zeglinski 
  2121. o Network distributors 
  2122.  
  2123.  
  2124. ΓòÉΓòÉΓòÉ 5.1. Martin Lafaix ΓòÉΓòÉΓòÉ
  2125.  
  2126. Martin Lafaix 
  2127.  
  2128. Martin Lafaix is a computer science student at the Universit╨Æ  de Nice-Sophia 
  2129. Antipolis.  He currently works on his PhD thesis (key areas: functional 
  2130. language, type as value, programming at large, ...). 
  2131.  
  2132. He can be reached at the following address: lafaix@sophia.inria.fr 
  2133.  
  2134.  
  2135. ΓòÉΓòÉΓòÉ 5.2. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
  2136.  
  2137. Larry Salomon, Jr. 
  2138.  
  2139. Larry Salomon, Jr. wrote his first Presentation Manager application for OS/2 
  2140. version 1.1 in 1989.  Since that time, he has written numerous VIO and PM 
  2141. applications, including the Scramble applet included with OS/2 and the 
  2142. I-Brow/Magnify/Screen Capture trio being distributed by IBM with the 
  2143. Professional Developers Kit CD-ROM.  Currently, he works for Cheyenne Software 
  2144. in Roslyn, New York and resides in Bellerose, New York with his wife Lisa. 
  2145.  
  2146. Larry can be reached electronically via the Internet at os2man@panix.com. 
  2147.  
  2148.  
  2149. ΓòÉΓòÉΓòÉ 5.3. Carsten Whimster ΓòÉΓòÉΓòÉ
  2150.  
  2151. Carsten Whimster 
  2152.  
  2153. I am an undergraduate Computer Science student at the University of Waterloo, 
  2154. and an OS/2 enthusiast as of OS/2 2.0.  I am currently in my third year, taking 
  2155. mainly operating system, language, and compiler courses as much as possible. 
  2156. This is not too difficult obviously, since this covers most of what they try to 
  2157. teach us in any case :).  This summer I will be working at the University as a 
  2158. tutor in CS241, an introductory course to compilers. 
  2159.  
  2160. I am a beginning OS/2 PM programmer with a few projects on the go, and many 
  2161. more in my head.  I am now using Watcom C/C++ 9.5, and Watcom VX-REXX 2.0, with 
  2162. Watcom C/C++ 10.0 becoming my mainstay, as soon as it comes out.  I try to buy 
  2163. as many books as I can afford on OS/2 programming, but I don't have much money. 
  2164. If anyone sends me books, I will review them as time permits, provided they are 
  2165. topical.  Finally, I am a TEAM-OS/2 member, and stay busy trying to keep up 
  2166. with several OS/2 groups on the Internet.  My Mosaic homepage should get a lot 
  2167. more interesting over the summer as I get more time to spend on these things. 
  2168.  
  2169. You may reach me... 
  2170.  
  2171. ...via email: 
  2172.  
  2173. bcrwhims@undergrad.math.uwaterloo.ca - Internet 
  2174.  
  2175. gopher://descartes.math.uwaterloo.ca:70/h0/mathSOC/.csc/.www/.bcrwhimster/homepage.html 
  2176. - Mosaic homepage 
  2177.  
  2178. ...via snail mail: 
  2179.  
  2180. Carsten Whimster
  2181. 319 Erb Street West, 3rd floor
  2182. Waterloo, Ontario
  2183. Canada
  2184. N2L 1W4
  2185.  
  2186.  
  2187. ΓòÉΓòÉΓòÉ 5.4. Gordon Zeglinski ΓòÉΓòÉΓòÉ
  2188.  
  2189. Gordon Zeglinski 
  2190.  
  2191. Gordon Zeglinski is a freelance programmer/consultant who received his Master's 
  2192. degree in Mechanical Engineering with a thesis on C++ sparse matrix objects. 
  2193. He has been programming in C++ for 6 years and also has a strong background in 
  2194. FORTRAN.  He started developing OS/2 applications with version 2.0 . 
  2195.  
  2196. His current projects include a client/server communications program that 
  2197. utilitizes OS/2's features which has entered beta testing.  Additionally, he is 
  2198. involved in the development of a "real-time" automated vehicle based on OS/2 
  2199. and using C++ in which he does device driver development and designs the 
  2200. applications that comprise the control logic and user interface. 
  2201.  
  2202. He can be reached via the Internet at zeglins@cc.umanitoba.ca. 
  2203.  
  2204.  
  2205. ΓòÉΓòÉΓòÉ 5.5. Network distributors ΓòÉΓòÉΓòÉ
  2206.  
  2207. Network Distributors 
  2208.  
  2209. These people are part of our distribution system to provide EDM/2 on networks 
  2210. other than the Internet.  Their help to provide access to this magazine for 
  2211. others is voluntary and we appreciate them a lot! 
  2212.  
  2213. o Paul Hethman (hethmon@apac.ag.utk.edu) - Compuserve 
  2214. o Gess Shankar (gess@knex.mind.org) - Internet 
  2215. o David Singer (singer@almaden.ibm.com) - IBM Internal 
  2216. o Andre Asselin (ASSELIN AT RALVM12) - IBM Internal 
  2217.  
  2218. If you would like to become a "network distributor", be sure to contact the 
  2219. editors so that we can give you the credit you deserve!